摘要:此模式調(diào)用函數(shù)的時候,被綁定到全局對象。構(gòu)造器調(diào)用模式如果在一個函數(shù)前面帶上來調(diào)用,那么背地里將會創(chuàng)建一個連接到該函數(shù)的成員的新對象,同時會被綁定到新對象上。
前言
今天閑著無聊隨便逛了逛MDN,忽而看到一個方法Function.prototype.bind(),突然發(fā)現(xiàn)除了使用這個方法之外都沒有仔細(xì)琢磨過這個方法。于是乎,找到了kill time的事情-寫博客。
基礎(chǔ)知識簡介隨便看看資料發(fā)現(xiàn)這玩意其實不簡單,理解起來需要不少基礎(chǔ)知識,在這里羅列一些,也算是一個總結(jié)和復(fù)習(xí)。
函數(shù)下面這段話來自《JavaScript語言精粹》,名副其實地描述了函數(shù)的精髓。
方法調(diào)用模式調(diào)用一個函數(shù)會暫停當(dāng)前函數(shù)的執(zhí)行,傳遞控制權(quán)和參數(shù)給新函數(shù)。除了聲明時定義的形式參數(shù),每個函數(shù)還接收兩個附加的參數(shù):this和arguments。參數(shù)this在面向?qū)ο缶幊讨蟹浅V匾闹等Q于調(diào)用的模式。在JavaScript里面一共有四種調(diào)用模式:方法調(diào)用模式、函數(shù)調(diào)用模式、構(gòu)造器調(diào)用模式和apply調(diào)用模式。這些模式在如何初始化關(guān)鍵參數(shù)this上面存在差異。
當(dāng)一個函數(shù)被保存為對象的一個屬性時,我們稱它為一個方法。當(dāng)一個方法被調(diào)用的時候,this被綁定到該對象。
var info = { name: "yuanzm", sayName: function() { console.log(this.name); } } info.sayName(); //yuanzm函數(shù)調(diào)用模式
當(dāng)一個函數(shù)并非為一個對象的屬性的時候,他就是被當(dāng)做一個函數(shù)來調(diào)用的。此模式調(diào)用函數(shù)的時候,this被綁定到全局對象。這是語言設(shè)計上的一個錯誤。倘若語言設(shè)計正確,this應(yīng)該是綁定到外部函數(shù)的this變量。
var name = "yuanzm" var sayName = function() { console.log(this.name); } sayName();// yuanzm構(gòu)造器調(diào)用模式
如果在一個函數(shù)前面帶上new來調(diào)用,那么背地里將會創(chuàng)建一個連接到該函數(shù)的prototype成員的新對象,同時this會被綁定到新對象上。(JavaScript原型相關(guān)知識這里不做贅述)
function Info(name) { this.name = name; } Info.prototype.sayName = function() { console.log(this.name); } var info = new Info("yuanzm"); info.sayName();//yuanzmApply調(diào)用模式
根據(jù)MDN的定義
The apply() method calls a function with a given this value and arguments provided as an array (or an array-like object).
var numbers = [5, 6, 2, 3, 7]; var max = Math.max.apply(null, numbers);類數(shù)組
一個類數(shù)組被定義為:
具有:指向?qū)ο笤氐臄?shù)字索引下標(biāo)以及 length 屬性告訴我們對象的元素個數(shù)
不具有:諸如 push 、 forEach 以及 indexOf 等數(shù)組對象具有的方法
符合上述定義的類數(shù)組是長下面這樣子的:
var my_object = { "0": "zero", "1": "one", "2": "two", "3": "three", "4": "four", length: 5 };
前面提到的arguments也是類數(shù)組。很多時候,處理類數(shù)組最省事的方法就是將它轉(zhuǎn)化成數(shù)組。那么就涉及到一個非常有意思的話題:將類數(shù)組轉(zhuǎn)換成數(shù)組。
將類數(shù)組轉(zhuǎn)換成數(shù)組非常簡單,調(diào)用Array自帶的方法即可:
Array.prototype.slice.call(arguments);
其中call換成apply也是一樣的。
簡單解釋一下,slice方法常規(guī)的調(diào)用方式為array.slice(start, end),會對array中的一段做淺復(fù)制,首先復(fù)制array[start], 一直復(fù)制到array[end]。前面提到過apply(或call)會切換一個函數(shù)調(diào)用的上下文,也就是Array.prototype.slice.call(arguments);手動綁定了需要操作的array為arguments,由于arguments和數(shù)組一樣具有下標(biāo),所以這個方法也是可行的,因而產(chǎn)生了一個新的數(shù)組,這個數(shù)組具有普通數(shù)組的所有方法,同時具有arguments每一個下標(biāo)對應(yīng)的值。
前面說了這么多,主角終于登場了!不過為了凸顯它的作用,還是需要拋出一段達(dá)不到我們需求的代碼。
var name = "yuan" var info = { name: "yuanzm", sayName: function() { console.log(this.name); } } var sayName = info.sayName; // 我們本身是希望得到y(tǒng)uanzm的,但是確得到了yuan這個結(jié)果。為什么會得到這個結(jié)果,前面的長篇大論起作用了。 // 如果是采用info.sayName()這種調(diào)用方式,符合函數(shù)的方法調(diào)用模式,函數(shù)內(nèi)部的this是info對象; // 如果令一個變量sayName為info.sayName,這個時候再調(diào)用函數(shù),就是普通的函數(shù)調(diào)用模式了,結(jié)果自然為yuan。 sayName(); // yuan
那么我們使用bind就是希望最后得到的結(jié)果為yuanzm。
現(xiàn)在我們可以好好介紹bind了。根據(jù)MDN的定義:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
翻譯過來就是,bind()方法會創(chuàng)建一個新函數(shù),稱為綁定函數(shù).當(dāng)調(diào)用這個綁定函數(shù)時,綁定函數(shù)會以創(chuàng)建它時傳入 bind()方法的第一個參數(shù)作為 this,傳入 bind() 方法的第二個以及以后的參數(shù)加上綁定函數(shù)運行時本身的參數(shù)按照順序作為原函數(shù)的參數(shù)來調(diào)用原函數(shù)。
他的語法是:
fun.bind(thisArg[, arg1[, arg2[, ...]]]);解決問題
有了bind,上述問題我們就能夠得到想要的結(jié)果了:
var name = "yuan" var info = { name: "yuanzm", sayName: function() { console.log(this.name); } } var sayName = info.sayName.bind(info); sayName(); // yuanzm
bind的用法在MDN上面描述得很詳細(xì),本文的目的也不是為了照搬MDN,所以這里有關(guān)bind使用的部分就到這兒,接下來我們?nèi)タ纯碕avascript庫中bind的實現(xiàn)
Prototype中的bind很久之前Prototype的bind寫法是下面這樣的(注釋為本人所加):
Function.prototype.bind = function(){ // bind作為Function的prototype屬性,每一個函數(shù)都具有bind方法,其中的this指向調(diào)用該方法的函數(shù)(也即一個函數(shù)對象實例) var fn = this; // 前面說過,這個方法是為了將類數(shù)組轉(zhuǎn)換成數(shù)組 var args = Array.prototype.slice.call(arguments); // 數(shù)組的shift方法會移除數(shù)組的第一個元素,在bind方法的參數(shù)里面,第一個參數(shù)就是需要綁定this的對象 var object = args.shift(); return function(){ return fn.apply(object, // 現(xiàn)在的args是移除了最初參數(shù)中第一個參數(shù)后的數(shù)組,也就是新函數(shù)的預(yù)設(shè)的初始參數(shù)。 // array.concat(items...)方法產(chǎn)生一個新數(shù)組,它包含一份array的淺復(fù)制,并把一個或者多個參數(shù)item附加在其后。 // 如果參數(shù)item是一個數(shù)組,那么它的元素會被分別添加。 // 于是這一行代碼產(chǎn)生了一個參數(shù)數(shù)組,這個數(shù)組由預(yù)設(shè)的初始參數(shù)(如果存在)和新傳遞的參數(shù)組成。 args.concat(Array.prototype.slice.call(arguments))); }; };
在最新的版本1.7.2(2015.06.23查閱官網(wǎng))中https://github.com/sstephenson/prototype/blob/master/src/prototype/lan...,bind是下面這樣子的:
function bind(context) { if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; if (!Object.isFunction(this)) throw new TypeError("The object is not callable."); var nop = function() {}; var __method = this, args = slice.call(arguments, 1); var bound = function() { var a = merge(args, arguments); // Ignore the supplied context when the bound function is called with // the "new" keyword. var c = this instanceof bound ? this : context; return __method.apply(c, a); }; nop.prototype = this.prototype; bound.prototype = new nop(); return bound; }
可見,除了加了一些異常情況判斷,核心代碼和之前并無大差別。
結(jié)語總得來說apply、call和bind都是為了手動綁定this對象,目的上沒有什么區(qū)別。但是bind和另外兩者的明顯的區(qū)別是,bind會產(chǎn)生一個新的函數(shù),這個函數(shù)還可以有預(yù)設(shè)的參數(shù),這在很多時候會比apply和call更加好用。合理利用apply、call和bind會使得javaScript代碼更加優(yōu)雅。
參考資料[1] Function.prototype.apply()
[2] JavaScript 的怪癖 8:“類數(shù)組對象”
[3] how does Array.prototype.slice.call() work?
[4] JavaScript’s Apply, Call, and Bind Methods are Essential for JavaScript Professionals
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/85752.html
摘要:控制反轉(zhuǎn)容器控制反轉(zhuǎn)使依賴注入變得更加便捷。有瑕疵控制反轉(zhuǎn)容器是實現(xiàn)的控制翻轉(zhuǎn)容器的一種替代方案。容器的獨立使用即使沒有使用框架,我們?nèi)匀豢梢栽陧椖恐惺褂冒惭b組件來使用的控制反轉(zhuǎn)容器。在沒有給定任何信息的情況下,容器是無法實例化相關(guān)依賴的。 聲明:本文并非博主原創(chuàng),而是來自對《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當(dāng)然也不是原汁原味...
摘要:接上回第二部分,編寫爬蟲。進(jìn)入微信嵌套選擇圖片和上傳圖片接口,實現(xiàn)一鍵上傳圖片,遇到問題看吧,我現(xiàn)在已經(jīng)可以通過爬蟲獲取的提問標(biāo)題了。微信故意省略想做小偷站的,看到這里基本上就能搞出來了。下一篇,采集入庫 上回,我裝了環(huán)境 也就是一對亂七八糟的東西 裝了pip,用pip裝了virtualenv,建立了一個virtualenv,在這個virtualenv里面,裝了Django,創(chuàng)建了一個...
閱讀 1398·2021-10-19 11:42
閱讀 735·2021-09-22 16:04
閱讀 1886·2021-09-10 11:23
閱讀 1865·2021-07-29 14:48
閱讀 1265·2021-07-26 23:38
閱讀 2827·2019-08-30 15:54
閱讀 1041·2019-08-30 11:25
閱讀 1710·2019-08-29 17:23