JavaScript函数调用的经典例题

JavaScript函数调用的经典例题

不少初学JavaScript的人对函数的调用理解有些模糊的,话很少说,直接上题:函数

function Foo() {
        getName = function () { 
        console.log(1); 
        };
        return this;
    }
    Foo.getName = function () {
        console.log(2);
    };
    Foo.prototype.getName = function () {
        console.log(3);
    };
    var getName = function () { 
        console.log(4);
    };
    function getName() { 
        console.log(5);
    }

请写出如下每行代码的输出结果this

Foo.getName();  
     getName(); 
     Foo().getName(); 
     getName(); 
     new Foo.getName();  
     new Foo().getName();

此题涉及的知识点比较普遍,包括变量的做用域、变量提高、this指针指向、运算符优先级、原型、继承、等等。prototype

解题以前,咱们先分析一下代码:指针

//① 函数声明,声明了一个Foo函数,里面有个全局变量getName指向一个匿名函数
    function Foo() {
        getName = function () { 
        console.log(1); 
        };
        return this;
    }

    //② Foo函数的建立了一个静态属性getName指向一个匿名函数
    Foo.getName = function () {
        console.log(2);
    };
    
    //③ Foo函数的原型上建立了一个getName方法
    Foo.prototype.getName = function () {
        console.log(3);
    };
    
    //④ 函数表达式,定义一个变量getName指向一个匿名函数 
    var getName = function () { 
        console.log(4);
    };
    
    //⑤ 函数声明,声明了一个叫getName的有名函数
    function getName() { 
        console.log(5);
    }

第一问

Foo.getName(); //2
访问Foo函数上存储的静态属性getName,因此结果为2。code

第二问

getName(); //4
直接调用getName函数,至关于调用window.getName,那么与函数①、②、③无关。在分析题目前咱们首先知道什么变量提高以及JS引擎工做的执行顺序。对象

变量提高
全部的变量声明都会被提高到它所在做用域的最开始的部分
例如:继承

console.log(a); //undifined
    var a = 10;

js引擎执行代码的顺序为:ip

var a; 
    console.log(a);
    a = 10;

例如:作用域

var a = 10;
    function test(){
        conlose.log(a); //undifined
        var a = 20;
    }
    test();

js引擎执行代码的顺序为:get

var a;
    a = 10;
    function test(){
        var a;
        conlose.log(a); //undifined
        a = 20;
    }

JS引擎工做的执行顺序:

  • 解析器会预先读取函数声明和变量声明,并使其在执行任何代码前能够访问;
  • 再由上而下逐行执行,函数表达式必须等到解析器执行到它所在的代码行才会真正被解释执行

咱们再看原题,函数④的变量会被提高,再结合上述JS引擎工做的执行顺序,所以代码的执行顺序是:

function Foo(){
        getName = function(){
        console.log(1); 
        };
        return this;
    }
    var getName;
    function getName(){
        console.log(5);
    }
    Foo.getName = function(){ 
        console.log(2);
    };
    Foo.prototype.getName = functio() { 
        console.log(3);
    };
    getName = function(){ 
        console.log(4); //最终的赋值覆盖function getName声明
    };

因此结果为4。

第三问

Foo().getName(); //1
Foo().getName(); 先执行了Foo函数,而后调用Foo函数的返回值对象的getName属性函数。

  1. 先看前面的Foo()
    显然调用了函数①,Foo函数第一句getName = function(){alert(1);};是一句赋值语句,由于它没有var声明,因此先向当前Foo函数做用域内寻找getName变量,没有。再向当前函数做用域上层,即外层做用域内寻找是否含有getName变量,找到函数④var getName=function(){alert(1)};,将此变量getName赋值为function(){alert(1)}。

    咱们将相关的代码单独拿出:

    function Foo() {
            getName = function () { //全局变量 
            console.log(1); 
            };
        }
        var getName = function () { 
            console.log(4);
        };
        Foo();
        console.log(getName);  //function(){console.log(1); }

    实质上就是将外层做用域内的getName函数修改了。

  2. 再看Foo().getName()
    Foo函数的返回值结果是this那么Foo().getName()=>this.getName()
    this的指向在函数定义的时候是肯定不了的,只有函数被调用执行时才能肯定this到底指向谁,谁调用指向谁。而此处是直接调用,this指向window对象。
    this.getName()=> window.getName(),而window中的getName已经被修改成console.log(1),因此最终会输出1。

此处考察了两个知识点,一个是变量做用域,一个是this指向。

关于变量做用域,若是将代码变为:

function Foo() {
        var getName = function () { // 局部变量,只能在函数内部访问
        console.log(1); 
        };
     }
     var getName = function () { 
         console.log(4);
     };
     Foo();
     console.log(getName);//function(){console.log(4);}

那么此题结果则为4了。

第四问

getName(); //1
再次调用getName函数时,此时函数④已经被第三问执行Foo()时修改,因此结果为1。

第五问

new Foo.getName(); //2
--> new(Foo.getName)()

此处考察的是js的运算符优先级。
.的优先级大于new,所以应该先执行Foo.getName(),那么执行函数②,结果是2,而后new了Foo的实例对象即new(Foo.getName)()
最终结果为2。

第六问

new Foo().getName();//3
--> (new Foo()).getName()

  1. 先执行new Foo(),那么执行函数①,返回this,this在构造函数中表明当前实例化对象,因此Foo函数产生一个新的实例对象。
  2. 以后调用实例对象的getName方法即(new Foo()).getName()=>实例对象.getName()

接着咱们就要说到构造函数和原型实例和实例对象。
实例对象可以调用的方法和属性只能是定义在自身函数内方法和继承了构造函数原型中的方法和属性。
实例对象.getName()自己并无定义属性和方法,则继承其构造函数Foo原型中的方法,执行函数③,结果为3。

相关文章
相关标签/搜索