最近在看《你不知道的javaScript》系列书籍,这里做一些记录。
上卷主要分两部分,分别是作用域和闭包,this 和 对象原型。
下面我就分别介绍这两部分的内容。
作用域
作用域是什么
作用域是为了存储变量,并且之后可以方便地找到这些变量所设计的一套良好的规则;也可以说是根据名称查找变量的一套规则。
理解作用域
当你看见var a = 2;这段程序时,很可能认为这是一句声明。
事实上编译器会进行如下处理。
- 遇到var a,编译器会询问作用域是否已经有一个该名称的变量存在于同一个作用域的集合中。如果是,编译器会忽略该声明,继续进行编译;否则它会要求作用域在当前作用域的集合中声明一个新的变量,并命名为a。
- 接下来编译器会为引擎生成运行时所需的代码,这些代码被用来处理a = 2这个赋值操作。引擎运行时会首先询问作用域,在当前的作用域集合中是否存在一个叫作a的变量。如果是,引擎就会使用这个变量;如果否,引擎会继续查找该变量(查看1.3节)。如果引擎最终找到了a变量,就会将2赋值给它。否则引擎就会举手示意并抛出一个异常!
总结:变量的赋值操作会执行两个动作,首先编译器会在当前作用域中声明一个变量(如果之前没有声明过),然后在运行时引擎会在作用域中查找该变量,如果能够找到就会对它赋值。
LHS 和 RHS
查找变量的过程由作用域进行协助,但是引擎执行怎样的查找,会影响最终的查找结果。
当变量出现在赋值操作的左侧时进行LHS查询,出现在右侧时进行RHS查询。
下面有一个示例来具体分清 LHS 和 RHS
1 | function foo( a ){ |
1.找出所有的LHS查询(这里有3处!)c=.. a=1 b=..
2.找出所有的RHS查询(这里有4处!)foo(2.. =a a.. ..b
作用域嵌套
当一个块或函数嵌套在另一个块或函数中时,就发生了作用域的嵌套。因此,在当前作用域中无法找到某个变量时,引擎就会在外层嵌套的作用域中继续查找,直到找到该变量,或抵达最外层的作用域(也就是全局作用域)为止。也就是所谓的作用域链。
词法作用域
作用域查找会在找到第一个匹配的标识符时停止。在多层的嵌套作用域中可以定义同名的标识符,这叫作遮蔽效应(内部的标识符“遮蔽”了外部的标识符)
欺骗词法作用域下面两种方法不提倡使用
eval函数,修改词法作用域
with关键字,创建词法作用域
函数作用域和块作用域
函数的块级作用域是从最小特权原则中引申出来的,也叫最小授权或最小暴露原则。这个原则是指在软件设计中,应该最小限度地暴露必要内容,而将其他内容都“隐藏”起来,比如某个模块或对象的API设计。
另一个好处就是可以规避冲突。“隐藏”作用域中的变量和函数所带来的另一个好处,是可以避免同名标识符之间的冲突,两个标识符可能具有相同的名字但用途却不一样,无意间可能造成命名冲突。冲突会导致变量的值被意外覆盖。
提升
let 的「创建」过程被提升了,但是初始化没有提升。所以 let 会有暂时死区
var 的「创建」和「初始化」都被提升了。
function 的「创建」「初始化」和「赋值」都被提升了。所以同名时,函数权重最重
闭包
闭包,有权访问另外一个函数的变量标识符的函数。
比较常见的一个闭包问题,就是for循环。
1 | for(var i = 1; i <= 5; i++) { |
会发现每一次输出的都是6。是因为所有的回调函数回在循环结束后才会执行(event loop)
解决办法:
1 | // IIFE 闭包 |
另外一个闭包常用的场景,就是模块暴露
1 | function coolModule(){ |
this 和 对象原型
this
如果要判断一个运行中函数的this绑定,就需要找到这个函数的直接调用位置。
找到之后就可以顺序应用下面这四条规则来判断this的绑定对象。优先级由低到高
1.由new调用?绑定到新创建的对象。
1 | function foo(a){ |
2.由call或者apply(或者bind)调用?绑定到指定的对象。
1 | function foo() { |
3.由上下文对象调用?绑定到那个上下文对象。
1 | function foo() { |
4.默认:在严格模式下绑定到undefined,否则绑定到全局对象。
1 | function foo() { |
一定要注意,有些调用可能在无意中使用默认绑定规则。
ES6中的箭头函数并不会使用四条标准的绑定规则,而是根据当前的词法作用域来决定this,具体来说,箭头函数会继承外层函数调用的this绑定(无论this绑定到什么)。
这其实和ES6之前代码中的self = this机制一样。
今天先到这里,还有原型对象的部分,下一篇文章在写。
- 本文作者: Jambo
- 版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!