js里函數(shù)調(diào)用的四種模式

js 里函數(shù)調(diào)用有4種模式:方法調(diào)用、正常函數(shù)調(diào)用、構(gòu)造器函數(shù)調(diào)用、apply/call調(diào)用。同時(shí),無論哪種函數(shù)調(diào)用除了你聲明時(shí)定義的形參外,還會自動添加2個形參,分別是thisarguments。

1.方法調(diào)用

這個很好理解,函數(shù)是一個對象的屬性,比如

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

這個時(shí)候,上面函數(shù)里的 this 就綁定的是這個對象 a。所以this.v 可以取到對象a 的屬性 v

2.正常函數(shù)調(diào)用:

依然看代碼

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

這個時(shí)候,函數(shù) f里的this 綁定的是全局對象,如果是在瀏覽器運(yùn)行的解釋器中,一般來說是樓上說的 window對象。所以這里 this.x訪問的其實(shí)是 window.x,當(dāng)然,如果 window沒有 x 屬性,那么你這么一寫,按照 js 的坑爹語法,就是給 window 對象添加了一個 x 屬性,同時(shí)賦值。

3.構(gòu)造器函數(shù)調(diào)用:

構(gòu)造函數(shù)一直是我認(rèn)為是 js 里最坑爹的部分,因?yàn)樗?js 最初設(shè)計(jì)的基于原型的面向?qū)ο髮?shí)現(xiàn)方式格格不入,就好像是特意為了迎合大家已經(jīng)被其他基于類的面相對象實(shí)現(xiàn)給慣壞了的習(xí)慣。
如果你在一個函數(shù)前面帶上 new關(guān)鍵字來調(diào)用,那么 js 會創(chuàng)建一個prototype屬性是此函數(shù)的一個新對象,同時(shí)在調(diào)用這個函數(shù)的時(shí)候,把this綁定到這個新對象上。當(dāng)然new 關(guān)鍵字也會改變return語句的行為。看代碼

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

上面這個函數(shù)和正常調(diào)用的函數(shù)寫法上沒什么區(qū)別,只不過在調(diào)用的時(shí)候函數(shù)名前面加了關(guān)鍵字new 罷了,這么一來,this 綁定的就不再是前面講到的全局對象了,而是這里說的創(chuàng)建的新對象,所以說這種方式其實(shí)很危險(xiǎn),因?yàn)楣饪春瘮?shù),你不會知道這個函數(shù)到底是準(zhǔn)備拿來當(dāng)構(gòu)造函數(shù)用的,還是一般函數(shù)用的,所以我們可以看到,在jslint里,它會要求你寫的所有構(gòu)造函數(shù),也就是一旦它發(fā)現(xiàn)你用了 new關(guān)鍵字,那么后面那個函數(shù)的首字母必須大寫,這樣通過函數(shù)首字母大寫的方式來區(qū)分,我個人只有一個看法:坑爹:)

4.apply/call 調(diào)用:

我們知道,在 js 里,函數(shù)其實(shí)也是一個對象,那么函數(shù)自然也可以擁有它自己的方法,有點(diǎn)繞,就好像函數(shù)可以自己有屬性也是一個函數(shù)。其中每個函數(shù)都擁有apply()這個方法,讓我們構(gòu)造一個參數(shù)數(shù)組傳遞給函數(shù),同時(shí)可以自己來設(shè)置this 的值,這就是它最強(qiáng)大的地方,上面的3種函數(shù)調(diào)用方法,你可以看到,this 都是自動綁定的,沒辦法由你來設(shè),當(dāng)你想設(shè)的時(shí)候,就可以用 apply()了。apply接收2個參數(shù),第一個是將傳遞給這個函數(shù)的 this的值,第二個是參數(shù)數(shù)組??创a:

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

是不是很神奇,函數(shù) a居然可以給o 加屬性值。當(dāng)然,如果你 apply的第一個參數(shù)傳遞 null,那么在函數(shù)a 里面 this 指針依然會綁定全局對象。你可能要問了,apply 函數(shù)是哪來的,因?yàn)樵?js 里所有的函數(shù)都有一個共同的prototype,也就是傳說中的 Function.prototype, 這個原型里有兩個神奇的方法,一個就是這里的apply ,另一個就是讓題主疑惑的 call
call()方法和 apply() 方法很類似,它們的存在都是為了改變this 的綁定,那call()apply() 有什么區(qū)別呢?就我個人看來,沒啥鳥區(qū)別。。。開玩笑!剛剛說了,上面 apply()接收兩個參數(shù),第一個是你想要 this 綁定的對象,第二個是一個參數(shù)數(shù)組,注意是一個數(shù)組,你想傳遞給這個函數(shù)的所有內(nèi)容都放在數(shù)組里,然后 apply() 函數(shù)會在傳遞形參時(shí)自動幫你展開,同時(shí)加入我上面提到的另一個神奇形參arguments。而 call() 呢,它的第一個參數(shù)也是你想要this 綁定的對象,但是后面可以接受不定參數(shù),而不再是一個數(shù)組,也就是你可以像平時(shí)給函數(shù)傳參那樣把這些參數(shù)一個一個傳遞,當(dāng)然,神奇形參 arguments還是不會少的。所以如果一定要說有什么區(qū)別的話,看起來是這樣的

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

僅此而已。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容