JavaScript中this

@wanqiuz 2018-04-25 14:18:14发表于 wanqiuz/blog-articles JavaScriptthis

1 词法作用域 vs 动态作用域

词法作用域(static scope == Lexical scope)的函数中遇到既不是形参也不是函数内部定义的局部变量的变量时,去函数定义时的环境中查询。

动态作用域(dynamic scope)的函数中遇到既不是形参也不是函数内部定义的局部变量的变量时,到函数调用时的环境中查。

2 ES5三种函数调用形式下的this

JS(ES5)里面有三种函数调用形式,ES5中函数中的this是由调用时的形参决定的,与静态作用域或者动态作用域无关。

func(p1, p2) ;
obj.child.method(p1, p2);
func.call(context, p1, p2); // 先不讲 apply

前两种都是语法糖,第三种才是正常调用形式:

func(p1, p2); 
// 等价于
func.call(undefined, p1, p2);

obj.child.method(p1, p2); 
// 等价于
obj.child.method.call(obj.child, p1, p2);

先看 func(p1, p2) 中的 this 如何确定:

function func(){
  console.log(this)
}

func();

等价于

func.call(undefined) // 可以简写为 func.call()

按理说打印出来的 this 应该就是 undefined 了吧,但是浏览器里有一条规则:

如果你传的 context 是 null 或者 undefined。
非严格模式下,默认的 context是window 对象;
严格模式下,默认的 context 是 undefined。

因此上面的打印结果是 window。

如果你希望这里的 this 不是 window,很简单:

func.call(obj) // 那么里面的 this 就是 obj 对象了

再看 obj.child.method(p1, p2) 的 this 如何确定

var obj = {
  foo: function(){
    console.log(this)
  }
}
obj.foo() ;

按照「转换代码」,我们将 obj.foo() 转换为

obj.foo.call(obj); // 好了,this 就是 obj。搞定。

[ ] 语法

function fn (){ console.log(this) };
var arr = [fn, fn2];
arr[0](); // 这里面的 this 又是什么呢?

我们可以把 arr[0]( ) 想象为arr.0( ),虽然后者的语法错了,但是形式与转换代码里的 obj.child.method(p1, p2) 对应上了,于是就可以愉快的转换了:arr[0]() 假想为arr.0(),然后转换为 arr.0.call(arr),那么里面的 this 就是 arr 了 :)

3 ES6箭头函数的this

ES6中箭头函数式因为不接受this传入,所以this既不是形参也不是函数内部定义的局部变量,就是运用JavaScript静态作用域规则在函数定义时的环境中查找。

参考并感谢: