附录A
动态作用域
大部分语言都是基于词法作用域,JS也是词法作用域
词法作用域是在代码编写时就已经确定好了的(取决于代码编写的位置),除了eval和with
而动态作用域关心的是函数在何处被调用
总结来说,动态作用域的作用域链是基于调用栈的(函数的调用栈),而词法作用域的作用域链是基于作用域的嵌套
附录B
块作用域的替代方案
想要在ES6之前只用块作用域,可以使用catch:
try{throw:2;}catch(a){
console.log(a); //2
}
这段代码虽然可以达到块作用域的效果,但是看起来很不舒服。但是重点是,工具可以将我们写的ES6语法转换为能在ES6之前环境中的代码形式(就像刚才的代码),我们只要在构建时通过工具对代码进行预处理就好了
附录C
this词法
一般写代码会遇到下面问题:
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当做回调函数传入setTimeout时,已经丢了this和该函数之间的绑定。setTimeout函数中调用了比如callback之类的函数,而此时this已经绑定到了window(全局)对象中,所以打印的结果是not awesome
其中,ES6的箭头函数是解决方案之一:
var obj = {
count:0,
cool:function coolFn(){
if(this.count<1){
setTimeout(()=>{
this.count++;
console.log('awesome?');
},100);
}
}
}
obj.cool(); //awesome?
箭头函数可不只是省略function关键词那么简单,其对于this绑定的行为和普通函数是完全不一样的,它是用当前的词法作用域覆盖了this本来的值
但是,据作者所言,箭头函数混淆了this绑定规则和词法作用域规则,并且其只能作为匿名函数,在他看来并不是最合适的解决方案
有一种是作者所推荐的,至少比箭头函数要好:
var obj = {
count:0,
cool:function coolFn(){
if(this.count<1){
setTimeout(function timer(){
this.count++;
console.log('awesome?');
}.bind(this),100);
}
}
}
obj.cool(); //awesome?
这种bind的写法可以手动修改this值的绑定