新聞中心
在給我們項(xiàng)目組的其他程序介紹 js 的時(shí)候,我準(zhǔn)備了很多的內(nèi)容,但看起來(lái)效果不大,果然光講還是不行的,必須動(dòng)手。前幾天有人問(wèn)我關(guān)于代碼里 call() 函數(shù)的用法,我讓他去看書(shū),這里推薦用js 寫(xiě)服務(wù)器的程序猿看《javascript編程精粹》 這本書(shū),crockford大神果然不是蓋的。之后我在segmentfault 上又看到了類似的問(wèn)題,那邊解答之后干脆這里記一筆。

成都創(chuàng)新互聯(lián)公司長(zhǎng)期為上1000+客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為鹽池企業(yè)提供專業(yè)的網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì),鹽池網(wǎng)站改版等技術(shù)服務(wù)。擁有十載豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。
首先,關(guān)于 js 定義類或?qū)ο蟮姆椒?,?qǐng)參看 w3school 的這里的這里,寫(xiě)的非常詳細(xì)和清晰,我不再贅言了。
為了介紹 bind、call、apply 這三個(gè)函數(shù)的用法,不得不介紹 js 里函數(shù)的一些設(shè)定。關(guān)于這部分推薦通讀 《javascript編程精粹》 的第四章,這里我所說(shuō)的在書(shū)里都能找到。
關(guān)于這三個(gè)函數(shù)的詳細(xì)介紹,可以參看 MDN 的文檔:bind、call、apply。
下面開(kāi)始搬磚,修改自我之前在 segmentfault 上的答案:
js 里函數(shù)調(diào)用有 4 種模式:方法調(diào)用、正常函數(shù)調(diào)用、構(gòu)造器函數(shù)調(diào)用、apply/call 調(diào)用。
同時(shí),無(wú)論哪種函數(shù)調(diào)用除了你聲明時(shí)定義的形參外,還會(huì)自動(dòng)添加 2 個(gè)形參,分別是 this 和arguments。
arguments 不涉及到上述 3 個(gè)函數(shù),所以這里只談 this。this 的值,在上面 4 中調(diào)用模式下,分別會(huì)綁定不同的值。分別來(lái)說(shuō)一說(shuō):
方法調(diào)用:
這個(gè)很好理解,函數(shù)是一個(gè)對(duì)象的屬性,比如
- var a = {
- v : 0,
- f : function(xx) {
- this.v = xx;
- }
- }
- a.f(5);
這個(gè)時(shí)候,上面函數(shù)里的 this 就綁定的是這個(gè)對(duì)象 a。所以 this.v 可以取到對(duì)象 a 的屬性 v。
正常函數(shù)調(diào)用:依然看代碼
- function f(xx) {
- this.x = xx;
- }
- f(5);
這個(gè)時(shí)候,函數(shù) f 里的 this 綁定的是全局對(duì)象,如果是在瀏覽器運(yùn)行的解釋器中,一般來(lái)說(shuō)是 window 對(duì)象。所以這里 this.x 訪問(wèn)的其實(shí)是 window.x ,當(dāng)然,如果 window 沒(méi)有 x 屬性,那么你這么一寫(xiě),按照 js 的坑爹語(yǔ)法,就是給 window 對(duì)象添加了一個(gè) x 屬性,同時(shí)賦值。
構(gòu)造器函數(shù)調(diào)用:
構(gòu)造函數(shù)一直是我認(rèn)為是 js 里最坑爹的部分,因?yàn)樗?js 最初設(shè)計(jì)的基于原型的面向?qū)ο髮?shí)現(xiàn)方式格格不入,就好像是特意為了迎合大家已經(jīng)被其他基于類的面相對(duì)象實(shí)現(xiàn)給慣壞了的習(xí)慣。
如果你在一個(gè)函數(shù)前面帶上 new 關(guān)鍵字來(lái)調(diào)用,那么 js 會(huì)創(chuàng)建一個(gè) prototype 屬性是此函數(shù)的一個(gè)新對(duì)象,同時(shí)在調(diào)用這個(gè)函數(shù)的時(shí)候,把 this 綁定到這個(gè)新對(duì)象上。當(dāng)然 new 關(guān)鍵字也會(huì)改變r(jià)eturn 語(yǔ)句的行為,不過(guò)這里就不談了??创a
- function a(xx)
- {
- this.m = xx;
- }
- var b = new a(5);
上面這個(gè)函數(shù)和正常調(diào)用的函數(shù)寫(xiě)法上沒(méi)什么區(qū)別,只不過(guò)在調(diào)用的時(shí)候函數(shù)名前面加了關(guān)鍵字 new罷了,這么一來(lái),this 綁定的就不再是前面講到的全局對(duì)象了,而是這里說(shuō)的創(chuàng)建的新對(duì)象,所以說(shuō)這種方式其實(shí)很危險(xiǎn),因?yàn)楣饪春瘮?shù),你不會(huì)知道這個(gè)函數(shù)到底是準(zhǔn)備拿來(lái)當(dāng)構(gòu)造函數(shù)用的,還是一般函數(shù)用的。所以我們可以看到,在 jslint 里,它會(huì)要求你寫(xiě)的所有構(gòu)造函數(shù),也就是一旦它發(fā)現(xiàn)你用了 new 關(guān)鍵字,那么后面那個(gè)函數(shù)的首字母必須大寫(xiě),這樣通過(guò)函數(shù)首字母大寫(xiě)的方式來(lái)區(qū)分,我個(gè)人只有一個(gè)看法:坑爹:)
apply/call 調(diào)用:
我們知道,在 js 里,函數(shù)其實(shí)也是一個(gè)對(duì)象,那么函數(shù)自然也可以擁有它自己的方法,有點(diǎn)繞,在js 里,每個(gè)函數(shù)都有一個(gè)公共的 prototype —— Function,而這個(gè)原型自帶有好幾個(gè)屬性和方法,其中就有這里困惑的 bind、call、apply 方法。先說(shuō) apply 方法,它讓我們構(gòu)造一個(gè)參數(shù)數(shù)組傳遞給函數(shù),同時(shí)可以自己來(lái)設(shè)置 this 的值,這就是它***大的地方,上面的 3 種函數(shù)調(diào)用方式,你可以看到,this 都是自動(dòng)綁定的,沒(méi)辦法由你來(lái)設(shè),當(dāng)你想設(shè)的時(shí)候,就可以用 apply()了。apply 函數(shù)接收 2 個(gè)參數(shù),***個(gè)是傳遞給這個(gè)函數(shù)用來(lái)綁定 this 的值,第二個(gè)是一個(gè)參數(shù)數(shù)組。
看代碼
- 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 的***個(gè)參數(shù)傳遞 null,那么在函數(shù) a 里面 this 指針依然會(huì)綁定全局對(duì)象。
call() 方法和 apply() 方法很類似,它們的存在都是為了改變 this 的綁定,那 call() 和apply() 有什么區(qū)別呢?就我個(gè)人看來(lái),沒(méi)啥鳥(niǎo)區(qū)別。。。開(kāi)玩笑!剛剛說(shuō)了,上面 apply() 接收兩個(gè)參數(shù),***個(gè)是綁定 this 的值,第二個(gè)是一個(gè)參數(shù)數(shù)組,注意它是一個(gè)數(shù)組,你想傳遞給這個(gè)函數(shù)的所有參數(shù)都放在數(shù)組里,然后 apply() 函數(shù)會(huì)在調(diào)用函數(shù)時(shí)自動(dòng)幫你把數(shù)組展開(kāi)。而 call()呢,它的***個(gè)參數(shù)也是綁定給 this 的值,但是后面接受的是不定參數(shù),而不再是一個(gè)數(shù)組,也就是說(shuō)你可以像平時(shí)給函數(shù)傳參那樣把這些參數(shù)一個(gè)一個(gè)傳遞。
所以如果一定要說(shuō)有什么區(qū)別的話,看起來(lái)是這樣的
- function a(xx, yy) {
- alert(xx, yy);
- alert(this);
- alert(arguments);
- }
- a.apply(null, [5, 55]);
- a.call(null, 5, 55);
僅此而已。
***再來(lái)說(shuō) bind() 函數(shù),上面講的無(wú)論是 call() 也好, apply() 也好,都是立馬就調(diào)用了對(duì)應(yīng)的函數(shù),而 bind() 不會(huì), bind() 會(huì)生成一個(gè)新的函數(shù),bind() 函數(shù)的參數(shù)跟 call() 一致,***個(gè)參數(shù)也是綁定 this 的值,后面接受傳遞給函數(shù)的不定參數(shù)。 bind() 生成的新函數(shù)返回后,你想什么時(shí)候調(diào)就什么時(shí)候調(diào),看下代碼就明白了
- var m = {
- "x" : 1
- };
- function foo(y) {
- alert(this.x + y);
- }
- foo.apply(m, [5]);
- foo.call(m, 5);
- var foo1 = foo.bind(m, 5);
- foo1();
末了來(lái)個(gè)吐槽,你在 js 里想定義一個(gè)函數(shù),于是你會(huì)這么寫(xiě):
- 1function jam() {};
其實(shí)這是 js 里的一種語(yǔ)法糖,它等價(jià)于:
- var jam = function() {};
然后你想執(zhí)行這個(gè)函數(shù),腦洞大開(kāi)的你會(huì)這么寫(xiě):
- function jam() {}();
但是這么寫(xiě)就報(bào)錯(cuò)了,其實(shí)這種寫(xiě)法也不算錯(cuò),因?yàn)樗_實(shí)是 js 支持的函數(shù)表達(dá)式,但是同時(shí) js 又規(guī)定以function 開(kāi)頭的語(yǔ)句被認(rèn)為是函數(shù)語(yǔ)句,而函數(shù)語(yǔ)句后面是肯定不會(huì)帶 () 的,所以才報(bào)錯(cuò),于是聰明的人想出來(lái),加上一對(duì)括號(hào)就可以了。于是就變成了這樣:
1(function jam() {}());
這樣就定義了一個(gè)函數(shù)同時(shí)也執(zhí)行它,詳情參加 ECMAScript 的 Expression Statement 章節(jié)。
本文出自 “菜鳥(niǎo)浮出水” 博客,原文鏈接:http://rangercyh.blog./1444712/1615809
文章標(biāo)題:【博文推薦】Javascript中bind、call、apply函數(shù)用法
文章出自:http://m.5511xx.com/article/djijego.html


咨詢
建站咨詢
