成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

解析 Bind 原理,并手寫 Bind 實現

開發 前端
bind() 方法創建一個新的函數,在 bind() 被調用時,這個新函數的 this 被指定為 bind() 的第一個參數,而其余參數將作為新函數的參數,供調用時使用。

[[437702]]

 bind()

bind() 方法創建一個新的函數,在 bind() 被調用時,這個新函數的 this 被指定為 bind() 的第一個參數,而其余參數將作為新函數的參數,供調用時使用。

— MDN

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

來個例子說明下:

  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); // 直接執行了函數 
  14. // {value: 1, name"Jack", age: 20} 
  15.  
  16. let bindFoo1 = bar.bind(foo, "Jack", 20); // 返回一個函數 
  17. bindFoo1(); 
  18. // {value: 1, name"Jack", age: 20} 
  19.  
  20. let bindFoo2 = bar.bind(foo, "Jack"); // 返回一個函數 
  21. bindFoo2(20); 
  22. // {value: 1, name"Jack", age: 20} 

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

1、指定 this

2、傳入參數

3、返回一個函數

4、柯里化

模擬實現:

  1. Function.prototype.bind = function (context) { 
  2.     // 調用 bind 的不是函數,需要拋出異常 
  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 指向調用者 
  8.     var self = this; 
  9.     // 實現第2點,因為第1個參數是指定的this,所以只截取第1個之后的參數 
  10.     var args = Array.prototype.slice.call(arguments, 1);  
  11.      
  12.     // 實現第3點,返回一個函數 
  13.     return function () { 
  14.         // 實現第4點,這時的arguments是指bind返回的函數傳入的參數 
  15.         // 即 return function 的參數 
  16.         var bindArgs = Array.prototype.slice.call(arguments); 
  17.         // 實現第1點 
  18.         return self.apply( context, args.concat(bindArgs) ); 
  19.     } 

但還有一個問題,bind 有以下一個特性:

一個綁定函數也能使用 new 操作符創建對象:這種行為就像把原函數當成構造器,提供的 this 值被忽略,同時調用時的參數被提供給模擬函數。

來個例子說明下:

  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 

上面例子中,運行結果 this.value 輸出為 undefined ,這不是全局 value 也不是 foo 對象中的 value ,這說明 bind 的 this 對象失效了,new 的實現中生成一個新的對象,這個時候的 this 指向的是 obj 。

這個可以通過修改返回函數的原型來實現,代碼如下:

  1. Function.prototype.bind = function (context) { 
  2.     // 調用 bind 的不是函數,需要拋出異常 
  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 指向調用者 
  8.     var self = this; 
  9.     // 實現第2點,因為第1個參數是指定的this,所以只截取第1個之后的參數 
  10.     var args = Array.prototype.slice.call(arguments, 1); 
  11.      
  12.     // 創建一個空對象 
  13.     var fNOP = function () {}; 
  14.      
  15.     // 實現第3點,返回一個函數 
  16.     var fBound = function () { 
  17.         // 實現第4點,獲取 bind 返回函數的參數 
  18.         var bindArgs = Array.prototype.slice.call(arguments); 
  19.         // 然后同傳入參數合并成一個參數數組,并作為 self.apply() 的第二個參數 
  20.         return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs)); 
  21.         // 注釋1 
  22.     } 
  23.      
  24.     // 注釋2 
  25.     // 空對象的原型指向綁定函數的原型 
  26.     fNOP.prototype = this.prototype; 
  27.     // 空對象的實例賦值給 fBound.prototype 
  28.     fBound.prototype = new fNOP(); 
  29.     return fBound; 

注釋1 :

  • 當作為構造函數時,this 指向實例,此時 this instanceof fBound 結果為 true ,可以讓實例獲得來自綁定函數的值,即上例中實例會具有 habit 屬性。
  • 當作為普通函數時,this 指向 window ,此時結果為 false ,將綁定函數的 this 指向 context

注釋2 :

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

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

詳情可前往 深度解析bind原理、使用場景及模擬實現 查看

補充:柯里化

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

  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 

這里定義了一個 add 函數,它接受一個參數并返回一個新的函數。調用 add 之后,返回的函數就通過閉包的方式記住了 add 的第一個參數。所以說 bind 本身也是閉包的一種使用場景。

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

責任編輯:武曉燕 來源: 三分鐘學前端
相關推薦

2022-07-13 09:00:06

BindNew 操作

2024-03-15 08:21:17

bindJavaScrip函數

2021-11-30 06:56:58

CallApply函數

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

2021-05-12 10:46:23

漏洞BINDDNS服務器

2024-08-26 14:35:19

JavaScript關鍵字對象

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-23 07:00:00

C++函數

2020-10-10 07:00:16

LinuxSocketTCP

2020-03-16 09:10:41

bindDNS服務器系統運維

2011-03-17 15:48:32

jQuery

2021-12-05 08:27:56

Javascript 高階函數前端

2022-07-08 08:21:26

JSbind 方法
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品久久网 | 在线观看a视频 | 亚洲精品一区二区 | 国产.com| 久久久久久亚洲精品不卡 | 在线a视频网站 | 一久久久 | 亚洲精品美女 | 久久精彩视频 | 国产精品久久久久久久久久 | 91色啪| 古装人性做爰av网站 | 免费观看色 | 午夜影院黄 | 成人午夜电影在线观看 | 国产三区在线观看视频 | 亚洲日本中文字幕在线 | 国产福利在线免费观看 | 免费看黄色视屏 | 亚洲精品成人免费 | 不卡av电影在线播放 | 殴美黄色录像 | 精品久久久久国产免费第一页 | 成人精品国产免费网站 | 亚洲二区视频 | re久久 | 亚洲欧洲中文 | 毛片的网址 | 日韩中文字幕网 | 网色 | 久久av一区二区三区 | 成人在线视频看看 | 玖玖视频 | 91色综合| 91亚洲国产成人精品一区二三 | 亚洲精品日韩在线 | 正在播放国产精品 | 国产一区二区三区不卡av | 久久久久久亚洲精品 | 亚洲精品福利视频 | 欧美 视频|