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。

相關文章
相關標籤/搜索