關於Function.prototype.bind

bind()方法會建立一個新函數,稱爲綁定函數。當調用這個綁定函數時,綁定函數會以建立它時傳入bind()方法的第一個參數做爲 this,傳入 bind() 方法的第二個以及之後的參數加上綁定函數運行時自己的參數按照順序做爲原函數的參數來調用原函數。javascript

實際使用中咱們常常會碰到這樣的問題:java

 

js 代碼:瀏覽器

  1. function Person(name){
  2. this.nickname = name;
  3. this.distractedGreeting = function() {
  4.  
  5. setTimeout(function(){
  6. console.log("Hello, my name is " + this.nickname);
  7. }, 500);
  8. }
  9. }
  10.  
  11. var alice = new Person('Alice');
  12. alice.distractedGreeting();
  13. //Hello, my name is undefined

這個時候輸出的this.nickname是undefined,緣由是this指向是在運行函數時肯定的,而不是定義函數時候肯定的,再由於setTimeout在全局環境下執行,因此this指向setTimeout的上下文:window緩存

之前解決這個問題的辦法一般是緩存this,例如:app

 

js 代碼:函數

  1. function Person(name){
  2. this.nickname = name;
  3. this.distractedGreeting = function() {
  4. var self = this; // <-- 注意這一行!
  5. setTimeout(function(){
  6. console.log("Hello, my name is " + self.nickname); // <-- 還有這一行!
  7. }, 500);
  8. }
  9. }
  10.  
  11. var alice = new Person('Alice');
  12. alice.distractedGreeting();
  13. // after 500ms logs "Hello, my name is Alice"

這樣就解決了這個問題,很是方便,由於它使得setTimeout函數中能夠訪問Person的上下文。可是看起來稍微一種蛋蛋的憂傷。this

可是如今有一個更好的辦法!您可使用bind。上面的例子中被更新爲:spa

 

js 代碼:prototype

  1. function Person(name){
  2. this.nickname = name;
  3. this.distractedGreeting = function() {
  4. setTimeout(function(){
  5. console.log("Hello, my name is " + this.nickname);
  6. }.bind(this), 500); // <-- this line!
  7. }
  8. }
  9.  
  10. var alice = new Person('Alice');
  11. alice.distractedGreeting();
  12. // after 500ms logs "Hello, my name is Alice"

bind() 最簡單的用法是建立一個函數,使這個函數不論怎麼調用都有一樣的 this 值。JavaScript新手常常犯的一個錯誤是將一個方法從對象中拿出來,而後再調用,但願方法中的 this 是原來的對象。(好比在回調中傳入這個方法。)若是不作特殊處理的話,通常會丟失原來的對象。從原來的函數和原來的對象建立一個綁定函數,則能很漂亮地解決這個問題:code

 

js 代碼:

  1. this.x = 9;
  2. var module = {
  3. x: 81,
  4. getX: function() { return this.x; }
  5. };
  6.  
  7. module.getX(); // 81
  8.  
  9. var getX = module.getX;
  10. getX(); // 9, 由於在這個例子中,"this"指向全局對象
  11.  
  12. // 建立一個'this'綁定到module的函數
  13. var boundGetX = getX.bind(module);
  14. boundGetX(); // 81

瀏覽器支持:

Browser Version support
Chrome 7
Firefox (Gecko) 4.0 (2)
Internet Explorer 9
Opera 11.60
Safari 5.1.4

很不幸,Function.prototype.bind 在IE8及如下的版本中不被支持,因此若是你沒有一個備用方案的話,可能在運行時會出現問題。bind 函數在 ECMA-262 第五版才被加入;它可能沒法在全部瀏覽器上運行。你能夠部份地在腳本開頭加入如下代碼,就能使它運做,讓不支持的瀏覽器也能使用 bind() 功能。

幸運的是,MDN爲沒有自身實現 .bind() 方法的瀏覽器提供了一個絕對可靠的替代方案:

 

js 代碼:

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

參考閱讀:

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

http://www.smashingmagazine.com/2014/01/23/understanding-javascript-function-prototype-bind/

http://krasimirtsonev.com/blog/article/JavaScript-bind-function-setting-a-scope

語法

fun.bind(thisArg[, arg1[, arg2[, …]]])

參數

thisArg
當綁定函數被調用時,該參數會做爲原函數運行時的 this 指向.當使用new 操做符調用綁定函數時,該參數無效.
arg1, arg2, …
當綁定函數被調用時,這些參數加上綁定函數自己的參數會按照順序做爲原函數運行時的參數.

描述

bind() 函數會建立一個新的函數(一個綁定的函數)有一樣的函數體(在 ECMAScript 5 規範內置 Call 屬性),當該函數(綁定函數的原函數)被調用時 this 值綁定到 bind() 的第一個參數,該參數不能被重寫。綁定函數被調用時,bind() 也接受預設的參數提供給原函數。一個綁定函數也能使用 new 操做符 建立對象:這種行爲就像把原函數當成構造器。提供的 this 值被忽略,同時調用時的參數被提供給模擬函數。

相關文章
相關標籤/搜索