深入理解JS:执行上下文中的this(二)

目录

  • 序言
  • Function.prototype.bind() 方法
  • 箭头函数
  • 参考

1.序言

深入理解JS:执行上下文中的this(一) 中,我们主要深入分析全局环境和函数环境中函数调用的 this,还留下 bind 方法以及箭头函数的 this 尚未分析,因此我们将在这篇文章进行讲解。

2.Function.prototype.bind() 方法

bind() 方法将会创建返回一个新的函数。在 bind() 被调用时,这个新函数的 this 将被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

ES5 引入了 bind 方法来设置函数的 this 值,而不用考虑函数如何被调用的。

这里给出一种 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-bind

但不论哪种实现,其实质上都是通过类似 Function.prototype.apply(thisArg, argArray) 来是实现指定调用函数 this 的。

3.箭头函数

箭头函数表达式的语法比函数表达式更简洁,并且没有自己的 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