1. 程式人生 > >JavaScript之bind及bind的模擬實現

JavaScript之bind及bind的模擬實現

        在JavaScript程式設計中有很多改變this的方法和方式,今天說的bind與眾不同,像call、apply改變this指向的時候會直接執行。而bind則不是,話不多說,直接進入正題。

        bind

        bind是函式原型上的一個方法,作用是改變this指向並且返回一個函式等待被執行。
Function.prototype.bind()
        bind()可以傳入多個引數,第一個引數作為改變this的一個物件,後面的引數作為返回函式的形參。
        然而傳入的第一個引數不同的話,指向也不同,看程式碼
var value = 0;
var obj = {
   value : 1,
}
function(name,age){
    console.log(value);
    console.log(name + " " + age);
}
var newShow = show.bind(obj,abc,18);
newShow();  //返回 1  abc 18
var newShow = show.bind(null,abc,18);
newShow();   //返回 0 abc 18
new newShow();  // 返回 undefined abc 18
        由此我們可以看出,當第一個引數是物件的時候,改變this的指向指向物件,當第一個引數為null的時候,此時的this指向window,當我們用 new newShow() 產生一個物件例項的時候,無論第一個引數填的什麼,this都是指向物件例項。

        bind的運用環境

        當我們在後面進行模組化開發的時候,程式碼量大的時候,最容易犯的錯誤就是變數汙染全域性了,我們可以選擇單變數程式設計來防止這件事情的發生。程式碼如下:
var obj = {
      init : fucntion(){
      },
      bindEvent : function(){
      },
      show : function(){
      }
}
        這種方式就是模組化程式設計,當我們在物件函式中寫進東西的時候,我們想讓這三個函式建立起來聯絡,想讓他們每次的初始this指向這個物件。這是時候就用到bind了。
var obj = {
    init : function(){
       var btn = document.getElementById('btn');
    },
    bindEvent : function(){
       btn.onclick = this.show.bind(this);
    },
    show : function(){
       console.log(this);
    }
}  obj.init()  
        此時我們在這樣呼叫的時候不會因為this指向的問題而 弄不清作用域是什麼。        現在我們開始想著用原生的方法模擬一下這個bind。

        bind的模擬實現

        我們現在想一下這個bind需要什麼。由上面可知,bind第一個引數不用,this所指向不同。而且返回的是一個新的函式。當函式有返回值的時候還需要返回值
Function.prototype.newBind = function(target){
  var target = target || window;
  return function(){
     return  this.apply(target);
  }
}
        我們還知道,在newBind方法呼叫的時候是可以用多個形參的。作為返回函式的引數,而新返回的函式也是可以傳參的,由於引數個數的不同我們可以選擇用arguments來確定引數,這時我們可以用 [].slice.call(grguments);這種方式把類陣列切成陣列
Function.prototype.newBind = function(target){
  var target = target || window;
  var self = this;
  var args = [],slice.call(arguments,1);
  return function(){
     var _args = [].slice.call(arguments,0);
     return  self.apply(target,args.concat(_args));
  }
}
        當我們在原型鏈上程式設計的時候,避免不了用原型上的東西,此時我們bind的方法也是可以繼承原型上的屬性和方法的,這裡是使用聖盃模式的一種思想實現
Function.prototype.newBind = function(target){
   var target = target || window;
   var self = this;
   var args = [].slice.call(arguments,1);
   var temp = function(){};
   var F = function(){
      var _args = [].slice.call(arguments,0);
      return self.apply(this instanceof temp ? this : target , args.concat(_args));
   }
   temp.prototype = this.prototype;
   F.prototype = new temp;
   return F;
}
        這樣我們的bind方法就完全實現了。自己試著用原聲的方法模擬一下bind的實現,也會加深對bind 的理解。