萬盛學電腦網

 萬盛學電腦網 >> 腳本專題 >> javascript >> javascript中的Function.prototye.bind

javascript中的Function.prototye.bind

   這篇文章主要介紹了javascript中的Function.prototye.bind的相關資料,需要的朋友可以參考下

  函數綁定(Function binding)很有可能是你在開始使用JavaScript時最少關注的一點,但是當你意識到你需要一個解決方案來解決如何在另一個函數中保持this上下文的時候,你真正需要的其實就是 Function.prototype.bind(),只是你有可能仍然沒有意識到這點。

  第一次遇到這個問題的時候,你可能傾向於將this設置到一個變量上,這樣你可以在改變了上下文之後繼續引用到它。很多人選擇使用 self, _this 或者 context 作為變量名稱(也有人使用 that)。這些方式都是有用的,當然也沒有什麼問題。但是其實有更好、更專用的方式。

  我們真正需要解決的問題是什麼?

  在下面的例子代碼中,我們可以名正言順地將上下文緩存到一個變量中:

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var myObj = {   specialFunction: function () {   },   anotherSpecialFunction: function () {   },   getAsyncData: function (cb) { cb(); },   render: function () { var that = this; this.getAsyncData(function () { that.specialFunction(); that.anotherSpecialFunction(); }); } };   myObj.render();

  如果我們簡單地使用 this.specialFunction() 來調用方法的話,會收到下面的錯誤:

  Uncaught TypeError: Object [object global] has no method 'specialFunction'

  我們需要為回調函數的執行保持對 myObj 對象上下文的引用。 調用 that.specialFunction()讓我們能夠維持作用域上下文並且正確執行我們的函數。 然而使用 Function.prototype.bind() 可以有更加簡潔干淨的方式:

  ?

1 2 3 4 5 6 7 8 9 10 11 render: function () {   this.getAsyncData(function () {   this.specialFunction();   this.anotherSpecialFunction();   }.bind(this));   }

  我們剛才做了什麼?

  .bind()創建了一個函數,當這個函數在被調用的時候,它的 this 關鍵詞會被設置成被傳入的值(這裡指調用bind()時傳入的參數)。因此,我們傳入想要的上下文,this(其實就是 myObj),到.bind()函數中。然後,當回調函數被執行的時候, this 便指向 myObj 對象。

  如果有興趣想知道 Function.prototype.bind() 內部長什麼樣以及是如何工作的,這裡有個非常簡單的例子:

  ?

1 2 3 4 5 6 Function.prototype.bind = function (scope) { var fn = this; return function () { return fn.apply(scope); }; }

  還有一個非常簡單的用例:

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var foo = { x: 3 }   var bar = function(){ console.log(this.x); }   bar(); // undefined   var boundFunc = bar.bind(foo);   boundFunc(); // 3

  我們創建了一個新的函數,當它被執行的時候,它的 this 會被設置成 foo —— 而不是像我們調用 bar() 時的全局作用域。

  浏覽器支持

  Browser Version support

  Chrome 7

  Firefox (Gecko) 4.0 (2)

  Internet Explorer 9

  Opera 11.60

  Safari 5.1.4

  正如你看到的,很不幸,Function.prototype.bind 在IE8及以下的版本中不被支持,所以如果你沒有一個備用方案的話,可能在運行時會出現問題。

  幸運的是,Mozilla Developer Network(很棒的資源庫),為沒有自身實現 .bind() 方法的浏覽器提供了一個絕對可靠的替代方案:

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== "function") {   // closest thing possible to the ECMAScript 5 internal IsCallable function throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); }   var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function () {}, fBound = function () { return fToBind.apply(this instanceof fNOP && oThis ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); };   fNOP.prototype = this.prototype; fBound.prototype = new fNOP();   return fBound; }; }

  適用的模式

  在學習技術點的時候,我發現有用的不僅僅在於徹底學習和理解概念,更在於看看在手頭的工作中有沒有適用它的地方,或者比較接近它的的東西。我希望,下面的某些例子能夠適用於你的代碼或者解決你正在面對的問題。

  CLICK HANDLERS(點擊處理函數)

  一個用途是記錄點擊事件(或者在點擊之後執行一個操作),這可能需要我們在一個對象中存入一些信息,比如:

  ?

1 2 3 4 5 6 7 var logger = { x: 0, updateCount: function(){ this.x++; console.log(this.x); } }

  我們可能會以下面的方式來指定點擊處理函數,隨後調用 logger 對象中的 updateCount() 方法。

  ?

1 2 3 document.querySelector('button').addEventListener('click', function(){ logger.updateCount(); });

  但是我們必須要創建一個多余的匿名函數,來確保 updateCount()函數中的 this 關鍵字有正確的值。

  我們可以使用如下更干淨的方式:

  document.querySelector('button').addEventListener('click', logger.updateCount.bind(logger));

  

copyright © 萬盛學電腦網 all rights reserved