深刻理解JS:執行上下文中的this(二)

目錄html

  • 序言
  • Function.prototype.bind() 方法
  • 箭頭函數
  • 參考

1.序言git

深刻理解JS:執行上下文中的this(一) 中,咱們主要深刻分析全局環境和函數環境中函數調用的 this,還留下 bind 方法以及箭頭函數的 this 還沒有分析,所以咱們將在這篇文章進行講解。es6


2.Function.prototype.bind() 方法github

bind() 方法將會建立返回一個新的函數。在 bind() 被調用時,這個新函數的 this 將被指定爲 bind() 的第一個參數,而其他參數將做爲新函數的參數,供調用時使用。算法

ES5 引入了 bind 方法來設置函數的 this 值,而不用考慮函數如何被調用的。app

這裏給出一種 bind() 的實現算法:函數

var slice = Array.prototype.slice;
Function.prototype.bind = function() {
  var thatFunc = this, thatArg = arguments[0];
  var args = slice.call(arguments, 1);
  if (typeof thatFunc !== 'function') {
    throw new TypeError('Function.prototype.bind called on incompatible ' + thatFunc);
  }
  return function(){
    var funcArgs = args.concat(slice.call(arguments))
    return thatFunc.apply(thatArg, funcArgs);
  };
};

注:上述代碼並無徹底按照ES5規範實現,只是做爲一種實現參考,更加完善的解決方案能夠參考 function-bindthis

但不論哪一種實現,其實質上都是經過相似 Function.prototype.apply(thisArg, argArray) 來是實現指定調用函數 this 的。es5


3.箭頭函數prototype

箭頭函數表達式的語法比函數表達式更簡潔,而且沒有本身的 this,arguments,super 或 new.target。它很適合用做匿名函數,而且不能用做構造函數(爲何呢?詳情點擊查看)。

ES6 引入了支持 this 詞法解析的箭頭函數(它在閉合的執行環境內設置 this 的值)。

如何理解箭頭函數在閉合的執行環境內設置 this 的值?

簡單理解,箭頭函數不會建立本身的 this,它的 this 與封閉詞法環境的 this 保持一致,即若是箭頭函數在全局環境中,那麼它的 this 就指向全局對象,若是箭頭函數在某一個函數中,那麼它的 this 就指向所在函數的 this。


咱們來看幾個示例:

(1)全局環境

var global = this

var foo = () => { return this }

var value = 1

var bar = {
  value: 2,
  getValueByArrowFunc: () => {
    return this.value
  },
  getValue: function (){
    return this.value
  },
}

console.log(foo() === global) // true

// 箭頭函數 this => global
console.log(bar.getValueByArrowFunc()) // 1

// 普通函數 this => bar
console.log(bar.getValue()) // 2

(2)函數環境

ES6的語法:

function foo() {
  this.value = 1
  
  // 箭頭函數表達式
  var arr = () => {
    console.log(this.value)
  }
  
  arr()
}

轉化爲ES5:

function foo() {
  var _this = this;

  this.value = 1;

  // 轉化爲普通函數表達式
  var arr = function arr() {
    console.log(_this.value);
  };

  arr();
}

對比轉化先後的代碼能夠看出:箭頭函數會轉化爲一個普通函數,經過一個臨時變量 _this 來傳遞,它以前的 this 就是所在函數的 this


(3)call() 、 apply() 或 bind() 方法

var global = this

var foo = {
	bar: () => {
    return this
  }
}

var obj = { value : 1 }

console.log(foo.bar() === global) // true
console.log(foo.bar.call(obj) === global) // true
console.log(foo.bar.apply(obj) === global) // true

var bind = foo.bar.bind(obj)
console.log(bind() === global) // true

因爲箭頭函數不會建立本身的 this,那麼經過 call() 、 apply() 或 bind() 方法調用一個箭頭函數時,只能傳遞參數,第一個參數會被忽略。


4.參考

this 關鍵字 - JavaScript | MDN - Mozilla

Function.prototype.bind() - JavaScript - MDN - Mozilla

箭頭函數- JavaScript | MDN

ECMAScript5.1中文版

ES6 - Arrow functions

相關文章
相關標籤/搜索