js 裏函數調用有4種模式:方法調用、正常函數調用、構造器函數調用、apply/call 調用。

js 裏函數調用有4種模式:方法調用、正常函數調用、構造器函數調用、apply/call 調用。
同時,不管哪一種函數調用除了你聲明時定義的形參外,還會自動添加2個形參,分別是 this 和 arguments。
這裏你既然問 this,那麼就只談 this。this 的值,在上面4中調用模式下,分別會綁定不一樣的值。分別來講一說:
方法調用:
這個很好理解,函數是一個對象的屬性,好比javascript

var a = {
    v : 0,
    f : function(xx) {        this.v = xx;
    }
}
a.f(5);

這個時候,上面函數裏的 this 就綁定的是這個對象 a。因此 this.v 能夠取到對象 a 的屬性 v。java

正常函數調用:
依然看代碼數組

function f(xx) {    this.x = xx;
}
f(5);

這個時候,函數 f 裏的 this 綁定的是全局對象,若是是在瀏覽器運行的解釋器中,通常來講是樓上說的 window 對象。因此這裏 this.x 訪問的實際上是 window.x ,固然,若是 window 沒有 x 屬性,那麼你這麼一寫,按照 js 的坑爹語法,就是給 window 對象添加了一個 x 屬性,同時賦值。瀏覽器

構造器函數調用:
構造函數一直是我認爲是 js 裏最坑爹的部分,由於它和 js 最初設計的基於原型的面向對象實現方式格格不入,就好像是特地爲了迎合你們已經被其餘基於類的面相對象實現給慣壞了的習慣。
若是你在一個函數前面帶上 new 關鍵字來調用,那麼 js 會建立一個 prototype 屬性是此函數的一個新對象,同時在調用這個函數的時候,把 this 綁定到這個新對象上。固然 new 關鍵字也會改變 return 語句的行爲,不過這裏就不談了。看代碼app

function a(xx) {    this.m = xx;
}var b = new a(5);

上面這個函數和正常調用的函數寫法上沒什麼區別,只不過在調用的時候函數名前面加了關鍵字 new 罷了,這麼一來,this 綁定的就再也不是前面講到的全局對象了,而是這裏說的建立的新對象,因此說這種方式其實很危險,由於光看函數,你不會知道這個函數究竟是準備拿來當構造函數 用的,仍是通常函數用的,因此咱們能夠看到,在 jslint 裏,它會要求你寫的全部構造函數,也就是一旦它發現你用了 new 關鍵字,那麼後面那個函數的首字母必須大寫,這樣經過函數首字母大寫的方式來區分,我我的只有一個見解:坑爹:)函數

apply/call 調用:
咱們知道,在 js 裏,函數其實也是一個對象,那麼函數天然也能夠擁有它本身的方法,有點繞,就好像函數能夠本身有屬性也是一個函數。其中每一個函數都擁有 apply() 這個方法,讓咱們構造一個參數數組傳遞給函數,同時能夠本身來設置 this 的值,這就是它最強大的地方,上面的3種函數調用方法,你能夠看到,this 都是自動綁定的,沒辦法由你來設,當你想設的時候,就能夠用 apply() 了。apply 接收2個參數,第一個是將傳遞給這個函數的 this 的值,第二個是參數數組。看代碼:this

function a(xx) {    this.b = xx;
}var o = {};
a.apply(o, [5]);
alert(a.b);    // undefinedalert(o.b);    // 5

是否是很神奇,函數 a 竟然能夠給 o 加屬性值。固然,若是你 apply 的第一個參數傳遞 null,那麼在函數 a 裏面 this 指針依然會綁定全局對象。你可能要問了,apply 函數是哪來的,由於在 js 裏全部的函數都有一個共同的 prototype,也就是傳說中的 Function.prototype, 這個原型裏有兩個神奇的方法,一個就是這裏的 apply ,另外一個就是讓題主疑惑的 call。prototype

說了這麼一大堆,終於來到 call 了。
call() 方法和 apply() 方法很相似,它們的存在都是爲了改變 this 的綁定,那 call() 和 apply() 有什麼區別呢?就我我的看來,沒啥鳥區別。。。開玩笑!剛剛說了,上面 apply() 接收兩個參數,第一個是你想要 this 綁定的對象,第二個是一個參數數組,注意是一個數組,你想傳遞給這個函數的全部內容都放在數組裏,而後 apply() 函數會在傳遞形參時自動幫你展開,同時加入我上面提到的另外一個神奇形參 arguments。而 call() 呢,它的第一個參數也是你想要 this 綁定的對象,可是後面能夠接受不定參數,而再也不是一個數組,也就是你能夠像平時給函數傳參那樣把這些參數一個一個傳遞,固然,神奇形參 arguments 仍是不會少的。因此若是必定要說有什麼區別的話,看起來是這樣的設計

function a(xx, yy) {
    alert(xx, yy);
    alert(this);
    alert(arguments);
}
a.apply(null, [5, 55]);
a.call(null, 5, 55);

僅此而已。指針

再來看題主的疑問,這樣寫包裹代碼有什麼好處呢?這裏就必須說一說另外一個關鍵的地方了,題主貼出來的代碼,能夠看到這個函數使用嚴格模式 "use strict",什麼是嚴格模式呢?本身搜去吧。在正常模式下,js 函數裏那些你沒有聲明就使用的變量,實際上是訪問的全局對象的屬性,好比說上面正常函數調用的時候,函數裏的 this ,就訪問的是全局對象。可是在嚴格模式下,不容許這種語法,全部變量都必需要顯示聲明,因此若是你不用 call() 傳遞 this 給這個函數,那麼就會報錯了。由於你在函數裏面有一個 return 語句,訪問了 this 變量。因此問題不是題主說的這樣寫有什麼好處,而是用了嚴格模式,就必須這麼寫。

而後還想說一下,apply() 和 call() ,用它們有什麼好處呢?好處就是可讓你改變 this,這不是廢話嗎。改變 this 來幹嗎呢?可讓這個函數,使用 this 的方法,換句話說,就是你的函數能夠針對不一樣的 this,來調用它們不一樣的方法,有點像反射機制。哈哈,我扯遠了。

相關文章
相關標籤/搜索