日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Js實現(xiàn)Bind的這五層,你在第幾層?

本文轉(zhuǎn)載自微信公眾號「秋風的筆記」,作者藍色的秋風 。轉(zhuǎn)載本文請聯(lián)系秋風的筆記公眾號。

創(chuàng)新互聯(lián)建站主營梅州網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,成都app開發(fā),梅州h5小程序制作搭建,梅州網(wǎng)站營銷推廣歡迎梅州等地區(qū)企業(yè)咨詢

最近在幫女朋友復習 JS 相關(guān)的基礎(chǔ)知識,遇到不會的問題,她就會來問我。

這不是很簡單?三下五除二,分分鐘解決。

 
 
 
 
  1. function bind(fn, obj, ...arr) {
  2.  return fn.apply(obj, arr)
  3. }

于是我就將這段代碼發(fā)了過去

這時候立馬被女朋友進行了一連串的靈魂拷問。

這個時候,我馬老師就坐不住了,我不服氣,我就去復習了一下 bind,發(fā)現(xiàn)太久不寫基礎(chǔ)代碼,還是會需要一點時間復習,這一次我得寫一個有深度的 bind,深得馬老師的真?zhèn)?,給他分成了五層速記法。

第一層 - 綁定在原型上的方法

這一層非常的簡單,得益于 JS 原型鏈的特性。由于 function xxx 的原型鏈 指向的是 Function.prototype , 因此我們在調(diào)用 xxx.bind 的時候,調(diào)用的是 Function.prototype 上的方法。

 
 
 
 
  1. Function.prototype._bind = function() {}

這樣,我們就可以在一個構(gòu)造函數(shù)上直接調(diào)用我們的bind方法啦~例如像這樣。

 
 
 
 
  1. funciton myfun(){}
  2. myfun._bind();

想要詳細理解這方面的可以看這張圖和這篇文章(https://github.com/mqyqingfeng/blog/issues/2)

第二層 - 改變 this 的指向

這可以說是 bind 最核心的特性了,就是改變 this 的指向,并且返回一個函數(shù)。而改變 this , 我們可以通過已知的 apply 和 call 來實現(xiàn),這里我們就暫且使用 apply 來進行模擬。首先通過 self 來保存當前 this,也就是傳入的函數(shù)。因為我們知道 this 具有 隱式綁定的規(guī)則(摘自 《你不知道的JavaScript(上)》2.2.2 ),

 
 
 
 
  1. function foo() {console.log(this.a)}
  2. var obj = {a: 2, foo};
  3. obj.foo(); // 2

通過以上特性,我們就可以來寫我們的 _bind 函數(shù)。

 
 
 
 
  1. Function.prototype._bind = function(thisObj) {
  2.  const self = this;
  3.  return function () {
  4.     self.apply(thisObj);
  5.   }
  6. }
  7. var obj = {a:1}
  8. function myname() {console.log(this.a)}
  9. myname._bind(obj)(); // 1

可能很多朋友都止步于此了,因為在一般的面試中,特別是一些校招面試中,可能你只需要知道前面兩個就差不多了。但是想要在面試中驚艷所有人,仍然是不夠的,接下來我們繼續(xù)我們的探索與研究。

第三層 - 支持柯里化

函數(shù)柯里化是一個老生常談的話題,在這里再復習一下。

 
 
 
 
  1. function fn(x) {
  2.  return function (y) {
  3.   return x + y;
  4.  }
  5. }
  6. var fn1 = fn(1);
  7. fn1(2) // 3

不難發(fā)現(xiàn),柯里化使用了閉包,當我們執(zhí)行 fn1 的時候,函數(shù)內(nèi)使用了外層函數(shù)的 x, 從而形成了閉包。

而我們的 bind 函數(shù)也是類似,我們通過獲取當前外部函數(shù)的 arguments ,并且去除了綁定的對象,保存成變量 args,最后 return 的方法,再一次獲取當前函數(shù)的 arguments, 最終用 finalArgs 進行了一次合并。

 
 
 
 
  1. Function.prototype._bind = function(thisObj) {
  2.  const self = this;
  3.   const args = [...arguments].slice(1)
  4.  return function () {
  5.     const finalArgs = [...args, ...arguments]
  6.     self.apply(thisObj, finalArgs);
  7.   }
  8. }

通過以上代碼,讓我們 bind 方法,越來越健壯了。

 
 
 
 
  1. var obj = { i: 1}
  2. function myFun(a, b, c) {
  3.   console.log(this.i + a + b + c);
  4. }
  5. var myFun1 = myFun._bind(obj, 1, 2);
  6. myFun1(3); // 7

一般到了這層,可以說非常棒了,但是再堅持一下下,就變成了完美的答卷。

第四層 - 考慮 new 的調(diào)用

要知道,我們的方法,通過 bind 綁定之后,依然是可以通過 new 來進行實例化的, new 的優(yōu)先級會高于 bind(摘自 《你不知道的JavaScript(上)》2.3 優(yōu)先級)。

這一點我們通過原生 bind 和我們第四層的 _bind 來進行驗證對比。

 
 
 
 
  1. // 原生
  2. var obj = { i: 1}
  3. function myFun(a, b, c) {
  4.   // 此處用new方法,this指向的是當前函數(shù) myFun 
  5.   console.log(this.i + a + b + c);
  6. }
  7. var myFun1 = myFun.bind(obj, 1, 2);
  8. new myFun1(3); // NAN
  9. // 第四層的 bind
  10. var obj = { i: 1}
  11. function myFun(a, b, c) {
  12.   console.log(this.i + a + b + c);
  13. }
  14. var myFun1 = myFun._bind(obj, 1, 2);
  15. new myFun1(3); // 7

注意,這里使用的是 bind方法

因此我們需要在 bind 內(nèi)部,對 new 的進行處理。而 new.target 屬性,正好是用來檢測構(gòu)造方法是否是通過 new 運算符來被調(diào)用的。

接下來我們還需要自己實現(xiàn)一個 new ,

而根據(jù) MDN,new 關(guān)鍵字會進行如下的操作:

1.創(chuàng)建一個空的簡單JavaScript對象(即{});

2.鏈接該對象(設(shè)置該對象的constructor)到另一個對象 ;

3.將步驟1新創(chuàng)建的對象作為this的上下文 ;

4.如果該函數(shù)沒有返回對象,則返回this。

 
 
 
 
  1. Function.prototype._bind = function(thisObj) {
  2.  const self = this;
  3.   const args = [...arguments].slice(1);
  4.  return function () {
  5.     const finalArgs = [...args, ...arguments];
  6.   // new.target 用來檢測是否是被 new 調(diào)用
  7.     if(new.target !== undefined) {
  8.       // this 指向的為構(gòu)造函數(shù)本身
  9.       var result = self.apply(this, finalArgs);
  10.       // 判斷改函數(shù)是否返回對象
  11.       if(result instanceof Object) {
  12.         return reuslt;
  13.       }
  14.       // 沒有返回對象就返回 this
  15.       return this;
  16.     } else {
  17.       // 如果不是 new 就原來的邏輯
  18.       return self.apply(thisArg, finalArgs);
  19.     }
  20.   }
  21. }

看到這里,你的造詣已經(jīng)如火純情了,但是最后還有一個小細節(jié)。

第五層 - 保留函數(shù)原型

以上的方法在大部分的場景下都沒有什么問題了,但是,當我們的構(gòu)造函數(shù)有 prototype 屬性的時候,就出問題啦。因此我們需要給 prototype 補上,還有就是調(diào)用對象必須為函數(shù)。

 
 
 
 
  1. Function.prototype._bind = function (thisObj) {
  2.   // 判斷是否為函數(shù)調(diào)用
  3.   if (typeof target !== 'function' || Object.prototype.toString.call(target) !== '[object Function]') {
  4.     throw new TypeError(this + ' must be a function');
  5.   }
  6.   const self = this;
  7.   const args = [...arguments].slice(1);
  8.   var bound = function () {
  9.     var finalArgs = [...args, ...arguments];
  10.     // new.target 用來檢測是否是被 new 調(diào)用
  11.     if (new.target !== undefined) {
  12.       // 說明是用new來調(diào)用的
  13.       var result = self.apply(this, finalArgs);
  14.       if (result instanceof Object) {
  15.         return result;
  16.       }
  17.       return this;
  18.     } else {
  19.       return self.apply(thisArg, finalArgs);
  20.     }
  21.   };
  22.   if (self.prototype) {
  23.     // 為什么使用了 Object.create? 因為我們要防止,bound.prototype 的修改而導致self.prototype 被修改。不要寫成 bound.prototype = self.prototype; 這樣可能會導致原函數(shù)的原型被修改。
  24.     bound.prototype = Object.create(self.prototype);
  25.     bound.prototype.constructor = self;
  26.   }
  27.   return bound;
  28. };

以上就是一個比較完整的 bind 實現(xiàn)了,如果你想了解更多細節(jié)的實踐,可以查看。(也是 MDN 推薦的)

https://github.com/Raynos/function-bind


網(wǎng)頁題目:Js實現(xiàn)Bind的這五層,你在第幾層?
網(wǎng)頁鏈接:http://m.5511xx.com/article/cododsc.html