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

解析 Bind 原理,并手寫 Bind 實(shí)現(xiàn)

開發(fā) 前端
bind() 方法創(chuàng)建一個(gè)新的函數(shù),在 bind() 被調(diào)用時(shí),這個(gè)新函數(shù)的 this 被指定為 bind() 的第一個(gè)參數(shù),而其余參數(shù)將作為新函數(shù)的參數(shù),供調(diào)用時(shí)使用。

[[437702]]

 bind()

bind() 方法創(chuàng)建一個(gè)新的函數(shù),在 bind() 被調(diào)用時(shí),這個(gè)新函數(shù)的 this 被指定為 bind() 的第一個(gè)參數(shù),而其余參數(shù)將作為新函數(shù)的參數(shù),供調(diào)用時(shí)使用。

— MDN

bind 方法與 call / apply 最大的不同就是前者返回一個(gè)綁定上下文的函數(shù),而后兩者是直接執(zhí)行了函數(shù)。

來(lái)個(gè)例子說(shuō)明下:

  1. let value = 2; 
  2. let foo = { 
  3.     value: 1 
  4. }; 
  5. function bar(name, age) { 
  6.     return { 
  7.   value: this.value, 
  8.   namename
  9.   age: age 
  10.     } 
  11. }; 
  12.  
  13. bar.call(foo, "Jack", 20); // 直接執(zhí)行了函數(shù) 
  14. // {value: 1, name"Jack", age: 20} 
  15.  
  16. let bindFoo1 = bar.bind(foo, "Jack", 20); // 返回一個(gè)函數(shù) 
  17. bindFoo1(); 
  18. // {value: 1, name"Jack", age: 20} 
  19.  
  20. let bindFoo2 = bar.bind(foo, "Jack"); // 返回一個(gè)函數(shù) 
  21. bindFoo2(20); 
  22. // {value: 1, name"Jack", age: 20} 

通過(guò)上述代碼可以看出 bind 有如下特性:

1、指定 this

2、傳入?yún)?shù)

3、返回一個(gè)函數(shù)

4、柯里化

模擬實(shí)現(xiàn):

  1. Function.prototype.bind = function (context) { 
  2.     // 調(diào)用 bind 的不是函數(shù),需要拋出異常 
  3.     if (typeof this !== "function") { 
  4.       throw new Error("Function.prototype.bind - what is trying to be bound is not callable"); 
  5.     } 
  6.      
  7.     // this 指向調(diào)用者 
  8.     var self = this; 
  9.     // 實(shí)現(xiàn)第2點(diǎn),因?yàn)榈?個(gè)參數(shù)是指定的this,所以只截取第1個(gè)之后的參數(shù) 
  10.     var args = Array.prototype.slice.call(arguments, 1);  
  11.      
  12.     // 實(shí)現(xiàn)第3點(diǎn),返回一個(gè)函數(shù) 
  13.     return function () { 
  14.         // 實(shí)現(xiàn)第4點(diǎn),這時(shí)的arguments是指bind返回的函數(shù)傳入的參數(shù) 
  15.         // 即 return function 的參數(shù) 
  16.         var bindArgs = Array.prototype.slice.call(arguments); 
  17.         // 實(shí)現(xiàn)第1點(diǎn) 
  18.         return self.apply( context, args.concat(bindArgs) ); 
  19.     } 

但還有一個(gè)問題,bind 有以下一個(gè)特性:

一個(gè)綁定函數(shù)也能使用 new 操作符創(chuàng)建對(duì)象:這種行為就像把原函數(shù)當(dāng)成構(gòu)造器,提供的 this 值被忽略,同時(shí)調(diào)用時(shí)的參數(shù)被提供給模擬函數(shù)。

來(lái)個(gè)例子說(shuō)明下:

  1. let value = 2; 
  2. let foo = { 
  3.     value: 1 
  4. }; 
  5. function bar(name, age) { 
  6.     this.habit = 'shopping'
  7.     console.log(this.value); 
  8.     console.log(name); 
  9.     console.log(age); 
  10. bar.prototype.friend = 'kevin'
  11.  
  12. let bindFoo = bar.bind(foo, 'Jack'); 
  13. let obj = new bindFoo(20); 
  14. // undefined 
  15. // Jack 
  16. // 20 
  17.  
  18. obj.habit; 
  19. // shopping 
  20.  
  21. obj.friend; 
  22. // kevin 

上面例子中,運(yùn)行結(jié)果 this.value 輸出為 undefined ,這不是全局 value 也不是 foo 對(duì)象中的 value ,這說(shuō)明 bind 的 this 對(duì)象失效了,new 的實(shí)現(xiàn)中生成一個(gè)新的對(duì)象,這個(gè)時(shí)候的 this 指向的是 obj 。

這個(gè)可以通過(guò)修改返回函數(shù)的原型來(lái)實(shí)現(xiàn),代碼如下:

  1. Function.prototype.bind = function (context) { 
  2.     // 調(diào)用 bind 的不是函數(shù),需要拋出異常 
  3.     if (typeof this !== "function") { 
  4.       throw new Error("Function.prototype.bind - what is trying to be bound is not callable"); 
  5.     } 
  6.      
  7.     // this 指向調(diào)用者 
  8.     var self = this; 
  9.     // 實(shí)現(xiàn)第2點(diǎn),因?yàn)榈?個(gè)參數(shù)是指定的this,所以只截取第1個(gè)之后的參數(shù) 
  10.     var args = Array.prototype.slice.call(arguments, 1); 
  11.      
  12.     // 創(chuàng)建一個(gè)空對(duì)象 
  13.     var fNOP = function () {}; 
  14.      
  15.     // 實(shí)現(xiàn)第3點(diǎn),返回一個(gè)函數(shù) 
  16.     var fBound = function () { 
  17.         // 實(shí)現(xiàn)第4點(diǎn),獲取 bind 返回函數(shù)的參數(shù) 
  18.         var bindArgs = Array.prototype.slice.call(arguments); 
  19.         // 然后同傳入?yún)?shù)合并成一個(gè)參數(shù)數(shù)組,并作為 self.apply() 的第二個(gè)參數(shù) 
  20.         return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs)); 
  21.         // 注釋1 
  22.     } 
  23.      
  24.     // 注釋2 
  25.     // 空對(duì)象的原型指向綁定函數(shù)的原型 
  26.     fNOP.prototype = this.prototype; 
  27.     // 空對(duì)象的實(shí)例賦值給 fBound.prototype 
  28.     fBound.prototype = new fNOP(); 
  29.     return fBound; 

注釋1 :

  • 當(dāng)作為構(gòu)造函數(shù)時(shí),this 指向?qū)嵗?,此時(shí) this instanceof fBound 結(jié)果為 true ,可以讓實(shí)例獲得來(lái)自綁定函數(shù)的值,即上例中實(shí)例會(huì)具有 habit 屬性。
  • 當(dāng)作為普通函數(shù)時(shí),this 指向 window ,此時(shí)結(jié)果為 false ,將綁定函數(shù)的 this 指向 context

注釋2 :

  • 修改返回函數(shù)的 prototype 為綁定函數(shù)的 prototype,實(shí)例就可以繼承綁定函數(shù)的原型中的值,即上例中 obj 可以獲取到 bar 原型上的 friend
  • 至于為什么使用一個(gè)空對(duì)象 fNOP 作為中介,把 fBound.prototype 賦值為空對(duì)象的實(shí)例(原型式繼承),這是因?yàn)橹苯? fBound.prototype = this.prototype 有一個(gè)缺點(diǎn),修改 fBound.prototype 的時(shí)候,也會(huì)直接修改 this.prototype ;其實(shí)也可以直接使用ES5的 Object.create() 方法生成一個(gè)新對(duì)象,但 bind 和 Object.create() 都是ES5方法,部分IE瀏覽器(IE < 9)并不支

注意: bind() 函數(shù)在 ES5 才被加入,所以并不是所有瀏覽器都支持,IE8 及以下的版本中不被支持,如果需要兼容可以使用 Polyfill 來(lái)實(shí)現(xiàn)

詳情可前往 深度解析bind原理、使用場(chǎng)景及模擬實(shí)現(xiàn) 查看

補(bǔ)充:柯里化

在計(jì)算機(jī)科學(xué)中,柯里化(Currying)是把接受多個(gè)參數(shù)的函數(shù)變換成接受一個(gè)單一參數(shù)(最初函數(shù)的第一個(gè)參數(shù))的函數(shù),并且返回接受余下的參數(shù)且返回結(jié)果的新函數(shù)的技術(shù)。這個(gè)技術(shù)由 Christopher Strachey 以邏輯學(xué)家 Haskell Curry 命名的,盡管它是 Moses Schnfinkel 和 Gottlob Frege 發(fā)明的。

  1. var add = function(x) { 
  2.   return function(y) { 
  3.     return x + y; 
  4.   }; 
  5. }; 
  6.  
  7. var increment = add(1); 
  8. var addTen = add(10); 
  9.  
  10. increment(2); 
  11. // 3 
  12.  
  13. addTen(2); 
  14. // 12 
  15.  
  16. add(1)(2); 
  17. // 3 

這里定義了一個(gè) add 函數(shù),它接受一個(gè)參數(shù)并返回一個(gè)新的函數(shù)。調(diào)用 add 之后,返回的函數(shù)就通過(guò)閉包的方式記住了 add 的第一個(gè)參數(shù)。所以說(shuō) bind 本身也是閉包的一種使用場(chǎng)景。

柯里化是將 f(a,b,c) 可以被以 f(a)(b)(c) 的形式被調(diào)用的轉(zhuǎn)化。JavaScript 實(shí)現(xiàn)版本通常保留函數(shù)被正常調(diào)用和在參數(shù)數(shù)量不夠的情況下返回偏函數(shù)這兩個(gè)特性。

責(zé)任編輯:武曉燕 來(lái)源: 三分鐘學(xué)前端
相關(guān)推薦

2022-07-13 09:00:06

BindNew 操作

2024-03-15 08:21:17

bindJavaScrip函數(shù)

2021-11-30 06:56:58

CallApply函數(shù)

2011-08-25 13:58:08

bind中文man

2020-12-18 05:42:46

reduxactions

2013-03-01 11:17:38

BIND10DNS

2009-01-14 17:46:01

RHELBindDNS

2024-01-29 00:41:14

2024-08-26 14:35:19

JavaScript關(guān)鍵字對(duì)象

2021-05-12 10:46:23

漏洞BINDDNS服務(wù)器

2021-05-11 09:37:00

JsBind代碼

2016-11-02 18:54:01

javascript

2010-01-14 17:13:28

centos bind

2021-06-18 07:16:17

JavaScript apply()方法call()方法

2020-10-10 07:00:16

LinuxSocketTCP

2020-10-23 07:00:00

C++函數(shù)

2020-03-16 09:10:41

bindDNS服務(wù)器系統(tǒng)運(yùn)維

2011-03-17 15:48:32

jQuery

2021-12-05 08:27:56

Javascript 高階函數(shù)前端

2022-07-08 08:21:26

JSbind 方法
點(diǎn)贊
收藏

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