中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Js實現Bind的使用方法

發布時間:2021-09-17 09:59:20 來源:億速云 閱讀:140 作者:柒染 欄目:web開發

這篇文章給大家介紹Js實現Bind的使用方法,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

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

Js實現Bind的使用方法

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

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

于是我就將這段代碼發了過去

Js實現Bind的使用方法

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

Js實現Bind的使用方法

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

Js實現Bind的使用方法

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

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

Function.prototype._bind = function() {}

這樣,我們就可以在一個構造函數上直接調用我們的bind方法啦~例如像這樣。

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

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

Js實現Bind的使用方法

第二層 - 改變 this 的指向

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

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

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

Function.prototype._bind = function(thisObj) {  const self = this;  return function () {     self.apply(thisObj);   } } var obj = {a:1} function myname() {console.log(this.a)} myname._bind(obj)(); // 1

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

第三層 - 支持柯里化

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

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

不難發現,柯里化使用了閉包,當我們執行 fn1 的時候,函數內使用了外層函數的 x, 從而形成了閉包。

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

Function.prototype._bind = function(thisObj) {  const self = this;   const args = [...arguments].slice(1)  return function () {     const finalArgs = [...args, ...arguments]     self.apply(thisObj, finalArgs);   } }

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

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

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

第四層 - 考慮 new 的調用

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

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

// 原生 var obj = { i: 1} function myFun(a, b, c) {   // 此處用new方法,this指向的是當前函數 myFun    console.log(this.i + a + b + c); } var myFun1 = myFun.bind(obj, 1, 2); new myFun1(3); // NAN  // 第四層的 bind var obj = { i: 1} function myFun(a, b, c) {   console.log(this.i + a + b + c); } var myFun1 = myFun._bind(obj, 1, 2); new myFun1(3); // 7

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

因此我們需要在 bind 內部,對 new 的進行處理。而 new.target 屬性,正好是用來檢測構造方法是否是通過 new  運算符來被調用的。

接下來我們還需要自己實現一個 new ,

而根據 MDN,new 關鍵字會進行如下的操作:

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

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

3.將步驟1新創建的對象作為this的上下文 ;

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

Function.prototype._bind = function(thisObj) {  const self = this;   const args = [...arguments].slice(1);  return function () {     const finalArgs = [...args, ...arguments];   // new.target 用來檢測是否是被 new 調用     if(new.target !== undefined) {       // this 指向的為構造函數本身       var result = self.apply(this, finalArgs);       // 判斷改函數是否返回對象       if(result instanceof Object) {         return reuslt;       }       // 沒有返回對象就返回 this       return this;     } else {       // 如果不是 new 就原來的邏輯       return self.apply(thisArg, finalArgs);     }   } }

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

第五層 - 保留函數原型

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

Function.prototype._bind = function (thisObj) {   // 判斷是否為函數調用   if (typeof target !== 'function' || Object.prototype.toString.call(target) !== '[object Function]') {     throw new TypeError(this + ' must be a function');   }   const self = this;   const args = [...arguments].slice(1);   var bound = function () {     var finalArgs = [...args, ...arguments];     // new.target 用來檢測是否是被 new 調用     if (new.target !== undefined) {       // 說明是用new來調用的       var result = self.apply(this, finalArgs);       if (result instanceof Object) {         return result;       }       return this;     } else {       return self.apply(thisArg, finalArgs);     }   };   if (self.prototype) {     // 為什么使用了 Object.create? 因為我們要防止,bound.prototype 的修改而導致self.prototype 被修改。不要寫成 bound.prototype = self.prototype; 這樣可能會導致原函數的原型被修改。     bound.prototype = Object.create(self.prototype);     bound.prototype.constructor = self;   }   return bound; };

關于Js實現Bind的使用方法就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

沁水县| 南投市| 陈巴尔虎旗| 荔波县| 会泽县| 菏泽市| 凌海市| 察哈| 岑溪市| 乐平市| 肇源县| 航空| 清新县| 华安县| 承德县| 兴文县| 柳河县| 东明县| 富顺县| 沧源| 西盟| 什邡市| 深水埗区| 丘北县| 喀喇| 两当县| 田阳县| 南江县| 修文县| 美姑县| 来安县| 延吉市| 营口市| 同心县| 新邵县| 贵溪市| 丁青县| 建湖县| 达州市| 石楼县| 开封县|