源码来袭:bind手写实现
- JavaScript中的this指向規(guī)則
- 源碼來襲:call、apply手寫實(shí)現(xiàn)與應(yīng)用
理解建議:如果對(duì)this指向規(guī)則不了解的話,建議先了解this指向規(guī)則,最好還能對(duì)call和apply的使用和內(nèi)部原理也有所了解,不然直接研究bind還是會(huì)有些難度的。
?一、bind()的使用
//html <button id="btn"></button> //js var list = {init:function(){this.ms = "duyi";this.dom = document.getElementById("btn");this.bindEvent();},bindEvent:function(){this.dom.onclick = this.showMessage.bind(this);},showMessage:function(){alert(this.ms);} } list.init();在單對(duì)象編程中,有一種非常典型的bind()的應(yīng)用,就以上面的示例來說,當(dāng)出現(xiàn)給DOM綁定事件回調(diào)函數(shù)時(shí),又還需要繼續(xù)保持函數(shù)的this指向原來的對(duì)象,就可以按照示例的這種方式來實(shí)現(xiàn):this.dom.onclick = this.showMessage.bind(this);
我們知道call和apply可以改變函數(shù)執(zhí)行的this指向,但是call和apply都是立即執(zhí)行該函數(shù),而bind是將this指向綁定到指定的對(duì)象上,并且返回函數(shù)并維持this指向這個(gè)對(duì)象。接下來再來看看bind的參數(shù)設(shè)置示例:
function show(x,y,z,w){console.log(this,x,y,z,w); } var DuyiO = {x : 20 } var newShow = show.bind(DuyiO,"1","2",3); newShow(4);//Object {x: 20} "1" "2" 3 4bind的參數(shù)和call非常類似,唯一的區(qū)別就在于除了調(diào)用bind時(shí)傳入?yún)?shù)外,還可以在正式執(zhí)行時(shí)傳入?yún)?shù),兩次傳入?yún)?shù)以拼接的方式作為函數(shù)執(zhí)行的實(shí)參。但是需要注意的是,第一個(gè)參數(shù)作為函數(shù)的this指向?qū)ο蟊仨氁谡{(diào)用bind方法時(shí)傳入,如果調(diào)用bind方法不傳入任何參數(shù),函數(shù)的this指向就會(huì)綁定到window上。比如下面這種情況:
var newShow = show.bind(); newShow(DuyiO,"1","2",3,4);//Window {…} Object {x: 20} "1" "2" 3最后還有一個(gè)基本上不會(huì)被應(yīng)用到的功能,就是返回的函數(shù)被new關(guān)鍵字用來創(chuàng)建一個(gè)新的對(duì)象,而構(gòu)造函數(shù)還是原函數(shù)本身(第二個(gè)示例中的show)。這個(gè)功能在模仿bind源碼不能100%實(shí)現(xiàn),但是也可以間接的實(shí)現(xiàn)其需要的功能。
?二、bind手寫實(shí)現(xiàn)
1.首先實(shí)現(xiàn)函數(shù)調(diào)用bind修改this指向即參數(shù)設(shè)置:
1 Function.prototype.MyBind = function(target){ 2 var self = this; 3 var args = [].slice.call(arguments,1); 4 var f = function(){ 5 return self.apply( target || window,args ); 6 } 7 return f; 8 }2.接著再來實(shí)現(xiàn)函數(shù)正式調(diào)用執(zhí)行時(shí)傳入設(shè)置:
1 Function.prototype.MyBind = function(target){ 2 var self = this; 3 var args = [].slice.call(arguments,1); 4 var f = function(){ 5 var _arg = [].slice.call(arguments,0); 6 return self.apply( target || window,args.concat(_arg) ); 7 } 8 return f; 9 }3.最后實(shí)現(xiàn)當(dāng)返回函數(shù)被new操作符引用作為構(gòu)造函數(shù)依然指向原函數(shù)(模擬實(shí)現(xiàn)功能):
1 Function.prototype.MyBind = function(target){ 2 var self = this; 3 var args = [].slice.call(arguments,1); 4 var temp = function(){}; 5 var f = function(){ 6 var _arg = [].slice.call(arguments,0); 7 return self.apply(this instanceof temp ? this : ( target || window ),args.concat(_arg) ); 8 } 9 temp.prototype = self.prototype; 10 f.prototype = new temp(); 11 return f; 12 }這個(gè)模擬實(shí)現(xiàn)主要有兩個(gè)關(guān)鍵點(diǎn)需要重點(diǎn)理解:
a.代碼第七行中的this instanceof temp ? this : ( target || window ):當(dāng)返回函數(shù)f被new作為構(gòu)造函數(shù)引用時(shí),這時(shí)候this指向了函數(shù)執(zhí)行時(shí)內(nèi)部隱式添加在變量對(duì)象上的this(這里不清楚的話可以參考JavaScript中的this指向規(guī)則),當(dāng)然普通調(diào)用執(zhí)行就是指向self。
b.代碼第九行和第十行為什么需要改變f的原型,這就是我前面講的模擬實(shí)現(xiàn)方法構(gòu)造,我們知道bind在JS內(nèi)部實(shí)現(xiàn)的是其返回函數(shù)還是那個(gè)原來的函數(shù),這里我們多加了一層f來實(shí)現(xiàn)的,所以在函數(shù)被當(dāng)做構(gòu)造函數(shù)的時(shí)候,將f的原型指向self也可以實(shí)現(xiàn)其功能,但是構(gòu)造的實(shí)例對(duì)象是基于f實(shí)現(xiàn)的,最終構(gòu)造原型鏈還是指向self原型,該有的方法屬性依然都會(huì)有。只是在原型鏈上多了f這個(gè)包裝層。
轉(zhuǎn)載于:https://www.cnblogs.com/ZheOneAndOnly/p/10423825.html
超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
以上是生活随笔為你收集整理的源码来袭:bind手写实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 重新上课,学习HTML的第一天
- 下一篇: uwsgi xml 配置