《你不知道的JavaScript-上》附录-动态作用域与this词法

动态作用域是JS另一个重要机制this的表亲。

词法作用域是一套关于引擎如何寻找变量以及会在何处找到变量的规则。
词法作用域最重要的特征是它的定义过程发生在代码的书写阶段。

1
2
3
4
5
6
7
8
9
10
11
12
function foo(){
console.log(a); //2
}

function bar(){
var a=3;
foo();
}


var a=2;
bar();

词法作用域让foo()中的a通过RHS引用到了全局作用域中的a,因此输出2。

动态作用域并不关心函数和作用域是如何声明以及在何处声明,只关心它们从何处调用。换句话说,作用域链是基于调用栈的,而不是代码中的作用域嵌套。
如果JS具有动态作用域,理论上,下面代码中foo()在执行时会输出3

1
2
3
4
5
6
7
8
9
10
11
12
function foo(){
console.log(a); //3(不是2)
}

function bar(){
var a=3;
foo();
}


var a=2;
bar();

WHY:foo()无法找打到a的变量引用时,会顺着调用栈在调用foo()的地方查找a,而不是在嵌套的词法作用域链中向上查找。

主要区别: 词法作用域是写在代码或者定义时确定的,而动态作用域是在运行时确定的(this也是这样)。词法作用域关注函数在何处声明,而动态作用域关注函数从何处调用。

箭头函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var foo=a => {
console.log(a);
};

foo(2); //2
```


以下是`this`在闭包中会出现的问题和解决方法:
```javascript
var obj={
id: "awesome",
cool: function coolFn(){
console.log(this.id);
}
};

var id="not awesome";

obj.cool(); //awesome

setTimeout(obj.cool,100); //not awesome

obj.cool函数丢失同this之间的绑定。最常用的解决方法是var self=thisvar that=this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var obj={
count: 0,
cool: function coolFn(){
var self=this;

if(self.count<1){
setTimeout(function timer(){
self.conunt++;
console.log("awesome?");
},100);
}
}
};

obj.cool(); //awesome?

self只是一个可以通过词法作用域和闭包进行引用的标识符,不关心this绑定的过程中发生了什么。

ES6中的箭头函数引入一个叫做this词法的行为:

1
2
3
4
5
6
7
8
9
10
11
12
13
var obj={
conut: 0,
cool: function coolFn(){
if(this.conut<1){
setTimeout( () => {
this.count++;
console.log("awesome?");
},100);
}
}
};

obj.cool(); //awesome?

上面代码中this继承了cool函数的this绑定。

ES6中this绑定规则:用当前词法作用域覆盖了this本来的值。

但是箭头函数还不够理想,因为她是匿名而非具名的。

一种更合适的办法加入bind()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var obj={
count: 0,
cool: funtion coolFn(){
if(this.count<1){
setTimeout(function timer(){
this.count++; //this是安全的
//因为bind(..)
console.log("more awesome");
}.bind(this),100);
}
}
}

obj.cool(); //more awesome
liborn wechat
欢迎您扫一扫上面的微信二维码,订阅我的公众号!