今天來(lái)實(shí)現(xiàn)JavaScript的bind函數(shù)。
首先看MDN的bind函數(shù)描述:
從上面可以看出來(lái),var A = B.bind(this)函數(shù)其實(shí)干了這幾件事情:
返回一個(gè)函數(shù),且這個(gè)函數(shù)后面運(yùn)行時(shí)的this就是bind(this)傳入的this
接收參數(shù),這些參數(shù)(如果有的話)作為bind()的第二個(gè)參數(shù)跟在this(或其他對(duì)象)后面,之后它們會(huì)被插入到目標(biāo)函數(shù)的參數(shù)列表的開(kāi)始位置,傳遞給綁定函數(shù)的參數(shù)會(huì)跟在它們的后面
使用new操作bind函數(shù)返回的函數(shù)時(shí),之前傳入的this會(huì)被忽略,也就是說(shuō)new的優(yōu)先級(jí)高于bind
第一步首先實(shí)現(xiàn)第一步:
Function.prototype.Zbind = function (othis) { var originFunc = this; return function () { originFunc.apply(othis); } } var obj = { } function createAgumon() { this.name = "agumon"; } var createAgumonBind = createAgumon.Zbind(obj); createAgumonBind(); obj;// {name: "agumon"}第二步
第二步考慮傳參的問(wèn)題,首先看看原生的bind函數(shù)是如何傳參的:
var obj = { } function createAgumon(gender, age) { this.name = "agumon"; this.gender = gender; this.age = age; } var createAgumonBind = createAgumon.bind(obj, "female"); createAgumonBind(22);
可以看出來(lái)在bind函數(shù)中能先傳部分參數(shù),運(yùn)行bind返回的函數(shù)時(shí)可以再傳入部分參數(shù)。
自己實(shí)現(xiàn):
Function.prototype.Zbind = function (othis) { var originFunc = this; var partArgs = [].slice.call(arguments, 1); var func = function() {}; var boundFunc = function () { var finalArgs = partArgs.concat([].slice.call(arguments)); return originFunc.apply(othis, finalArgs); } return boundFunc; } var obj = { } function createAgumon(gender, age) { this.name = "agumon"; this.gender = gender; this.age = age; } var createAgumonBind = createAgumon.Zbind(obj, "female"); createAgumonBind(22); obj;// {name: "agumon", gender: "female", age: 22}第三步
使用new來(lái)調(diào)用bind返回的函數(shù)時(shí),會(huì)忽略bind傳入的this
new操作和普通的函數(shù)調(diào)用有哪些區(qū)別?
粗略的來(lái)講,例如new F()這樣的調(diào)用,有以下幾個(gè)步驟:
新建一個(gè)對(duì)象,var o = new Object()
設(shè)置原型鏈,o.__proto__ = F.prototype
把F函數(shù)體內(nèi)的this綁定為o,并且執(zhí)行F函數(shù)的代碼
判斷F的返回類型:
如果是值類型,則返回o
如果是引用類型,則返回該引用類型對(duì)象
開(kāi)始實(shí)現(xiàn):
Function.prototype.Zbind = function (othis) { var originFunc = this; var partArgs = [].slice.call(arguments, 1); var func = function() {}; var boundFunc = function () { var finalArgs = partArgs.concat([].slice.call(arguments)); return originFunc.apply(this instanceof boundFunc ? this : othis, finalArgs); } return boundFunc; } var obj = {} function createAgumon(gender, age) { this.name = "agumon"; this.gender = gender; this.age = age; } var createAgumonBind = createAgumon.Zbind(obj, "female"); var newObj = new createAgumonBind(22); obj // {} newObj // {name: "agumon", gender: "female", age: 22}
關(guān)鍵的地方在于這里:this instanceof boundFunc ? this : othis,如果是new操作的話,此時(shí)this的__proto__已經(jīng)指向了boundFunc,所以使用instanceof可以檢測(cè)出是否在使用new操作
小細(xì)節(jié)原型丟失
剛剛實(shí)現(xiàn)的Zbind方法有個(gè)小問(wèn)題:
Function.prototype.Zbind = function (othis) { var originFunc = this; var partArgs = [].slice.call(arguments, 1); var func = function() {}; var boundFunc = function () { var finalArgs = partArgs.concat([].slice.call(arguments)); return originFunc.apply(this instanceof boundFunc ? this : othis, finalArgs); } return boundFunc; } var obj = { } function createAgumon(gender, age) { this.name = "agumon"; this.gender = gender; this.age = age; } createAgumon.prototype.college = "THU" var createAgumonBind = createAgumon.Zbind(obj, "female"); var newObj = new createAgumonBind(22); console.log(newObj.college)// undefined
可以看出來(lái)原型鏈丟失了,newObj.college得是"THU"才行
修改:
Function.prototype.Zbind = function (othis) { var originFunc = this; var partArgs = [].slice.call(arguments, 1); var func = function() {}; var boundFunc = function () { var finalArgs = partArgs.concat([].slice.call(arguments)); return originFunc.apply(this instanceof boundFunc ? this : othis, finalArgs); } func.prototype = originFunc.prototype; boundFunc.prototype = new func(); return boundFunc; } var obj = { } function createAgumon(gender, age) { this.name = "agumon"; this.gender = gender; this.age = age; } createAgumon.prototype.college = "THU" var createAgumonBind = createAgumon.Zbind(obj, "female"); var newObj = new createAgumonBind(22); console.log(newObj.college)// "THU"
為什么要使用func.prototype = originFunc.prototype;boundFunc.prototype = new func();,而不是直接用boundFunc.prototype = originFunc.prototype;是因?yàn)檫@樣寫的話,修改boundFunc.prototype會(huì)影響到原函數(shù)的prototype。
that"all
參考資料:
mdn-bind
javascript中,new操作符的工作原理是什么?
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/108034.html
摘要:新開(kāi)一個(gè)坑,起名為,自己造一些小輪子。之前貌似在知乎上看到一個(gè)問(wèn)題是說(shuō)如何使用實(shí)現(xiàn)它原生的和方法,今天我來(lái)實(shí)現(xiàn)一番。但是,這樣等于說(shuō)只給傳了一個(gè)數(shù)組參數(shù),并不能達(dá)到目的。同理來(lái)實(shí)現(xiàn)參考資料深入之和的模擬實(shí)現(xiàn) showImg(https://segmentfault.com/img/bVbbHCv?w=1123&h=629); 新開(kāi)一個(gè)坑,起名為【build your xxx】,自己造一...
摘要:初次寫文章,請(qǐng)多多包涵我最近正在根據(jù)這本書從頭開(kāi)始實(shí)現(xiàn)了一遍的框架。筆記目錄鏈接個(gè)人認(rèn)為本書對(duì)于想了解框架源碼的讀者來(lái)說(shuō)相當(dāng)有用,完全值得去購(gòu)買這本書書本主頁(yè)。因?yàn)槭浅鯇W(xué)者,筆記里可能有一些錯(cuò)誤,我也會(huì)繼續(xù)修改。 (初次寫文章,請(qǐng)多多包涵) 我最近正在根據(jù)《Build your own angularJS》這本書從頭開(kāi)始實(shí)現(xiàn)了一遍AngularJS的框架。我把相關(guān)的源碼和我的個(gè)人學(xué)習(xí)筆...
摘要:第二個(gè)類級(jí)別注解是。將引導(dǎo)應(yīng)用程序,啟動(dòng),從而啟動(dòng)自動(dòng)配置服務(wù)器。比如想使用不同版本的,具體如下在標(biāo)簽中還可以指定編譯的版本和項(xiàng)目的編碼格式指定項(xiàng)目編碼為使用插件可以為項(xiàng)目提供的操作方式,的個(gè),默認(rèn)。 引言 Spring 框架對(duì)于很多 Java 開(kāi)發(fā)人員來(lái)說(shuō)都不陌生。Spring 框架包含幾十個(gè)不同的子項(xiàng)目,涵蓋應(yīng)用開(kāi)發(fā)的不同方面。如此多的子項(xiàng)目和組件,一方面方便了開(kāi)發(fā)人員的使用,另外...
閱讀 2122·2021-11-22 15:24
閱讀 2410·2021-09-09 11:53
閱讀 3037·2021-09-04 16:40
閱讀 1636·2019-08-30 15:52
閱讀 3354·2019-08-29 13:47
閱讀 2735·2019-08-26 17:40
閱讀 1540·2019-08-26 13:24
閱讀 2245·2019-08-26 12:01