自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Js 實(shí)現(xiàn) Bind 的這五層,你在第幾層?

開發(fā) 前端
最近在幫女朋友復(fù)習(xí) JS 相關(guān)的基礎(chǔ)知識(shí),遇到不會(huì)的問(wèn)題,她就會(huì)來(lái)問(wèn)我。

 [[398743]]

本文轉(zhuǎn)載自微信公眾號(hào)「秋風(fēng)的筆記」,作者藍(lán)色的秋風(fēng) 。轉(zhuǎn)載本文請(qǐng)聯(lián)系秋風(fēng)的筆記公眾號(hào)。

最近在幫女朋友復(fù)習(xí) JS 相關(guān)的基礎(chǔ)知識(shí),遇到不會(huì)的問(wèn)題,她就會(huì)來(lái)問(wèn)我。

這不是很簡(jiǎn)單?三下五除二,分分鐘解決。

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

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

這時(shí)候立馬被女朋友進(jìn)行了一連串的靈魂拷問(wèn)。

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

[[398746]]

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

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

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

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

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

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

第二層 - 改變 this 的指向

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

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

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

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

可能很多朋友都止步于此了,因?yàn)樵谝话愕拿嬖囍?,特別是一些校招面試中,可能你只需要知道前面兩個(gè)就差不多了。但是想要在面試中驚艷所有人,仍然是不夠的,接下來(lái)我們繼續(xù)我們的探索與研究。

第三層 - 支持柯里化

函數(shù)柯里化是一個(gè)老生常談的話題,在這里再?gòu)?fù)習(xí)一下。

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

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

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

  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.   } 

通過(guò)以上代碼,讓我們 bind 方法,越來(lái)越健壯了。

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

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

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

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

這一點(diǎn)我們通過(guò)原生 bind 和我們第四層的 _bind 來(lái)進(jìn)行驗(yàn)證對(duì)比。

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

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

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

接下來(lái)我們還需要自己實(shí)現(xiàn)一個(gè) new ,

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

1.創(chuàng)建一個(gè)空的簡(jiǎn)單JavaScript對(duì)象(即{});

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

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

4.如果該函數(shù)沒(méi)有返回對(duì)象,則返回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 用來(lái)檢測(cè)是否是被 new 調(diào)用 
  7.     if(new.target !== undefined) { 
  8.       // this 指向的為構(gòu)造函數(shù)本身 
  9.       var result = self.apply(this, finalArgs); 
  10.       // 判斷改函數(shù)是否返回對(duì)象 
  11.       if(result instanceof Object) { 
  12.         return reuslt; 
  13.       } 
  14.       // 沒(méi)有返回對(duì)象就返回 this 
  15.       return this; 
  16.     } else { 
  17.       // 如果不是 new 就原來(lái)的邏輯 
  18.       return self.apply(thisArg, finalArgs); 
  19.     } 
  20.   } 

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

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

以上的方法在大部分的場(chǎng)景下都沒(méi)有什么問(wèn)題了,但是,當(dāng)我們的構(gòu)造函數(shù)有 prototype 屬性的時(shí)候,就出問(wèn)題啦。因此我們需要給 prototype 補(bǔ)上,還有就是調(diào)用對(duì)象必須為函數(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 用來(lái)檢測(cè)是否是被 new 調(diào)用 
  11.     if (new.target !== undefined) { 
  12.       // 說(shuō)明是用new來(lái)調(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? 因?yàn)槲覀円乐?,bound.prototype 的修改而導(dǎo)致self.prototype 被修改。不要寫成 bound.prototype = self.prototype; 這樣可能會(huì)導(dǎo)致原函數(shù)的原型被修改。 
  24.     bound.prototype = Object.create(self.prototype); 
  25.     bound.prototype.constructor = self; 
  26.   } 
  27.   return bound; 
  28. }; 

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

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

 

責(zé)任編輯:武曉燕 來(lái)源: 秋風(fēng)的筆記
相關(guān)推薦

2021-12-10 09:11:36

TypeScript 函數(shù)重載 TS 前端

2022-08-29 08:48:59

Go函數(shù)工廠模式

2021-12-16 06:52:33

Ceph分布式對(duì)象

2009-05-25 15:00:20

2021-10-29 21:26:39

前端引擎層類型

2024-03-15 08:21:17

bindJavaScrip函數(shù)

2016-09-23 16:09:01

2022-04-05 11:29:40

Linux安裝操作系統(tǒng)

2021-12-01 06:40:32

Bind原理實(shí)現(xiàn)

2009-01-14 17:46:01

RHELBindDNS

2022-01-18 16:42:03

區(qū)塊鏈加密信息資源

2012-06-21 15:50:20

JavaScript

2022-03-07 10:22:07

DevOps開發(fā)工具

2025-04-03 09:56:40

Python算法開發(fā)

2024-11-14 07:20:00

2023-04-24 08:11:02

圖片alt語(yǔ)音

2022-07-08 08:21:26

JSbind 方法

2016-08-22 23:56:48

超融合HCI

2016-03-28 17:00:32

互聯(lián)網(wǎng)運(yùn)維體系運(yùn)維

2015-08-18 09:52:19

app推廣規(guī)劃
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)