重温JS——预编译、全局预编译、作用域链
一、预编译
1、分析代码是否正确、符号、词法分析等
2、隐式操作==>预编译==> (形 [形参、变量] 实 函 运 )
函数再调用之后,在运行代码之前会生成一个对象==> 执行期对象AO==> activation Object(执行期上下文)==>每次调用就会创建一个AO对象 形:将 函数内部的 局部变量 和 形参变量 添加到AO对象内,作为AO对象的属性名。但是属性值是undefined。==》变量和形参名提升 实:把传入的实参赋值给AO对象的属性(如果实参是变量,那应该先取值后再传入) 函:局部函数声明、赋值。把局部函数的名字让AO对象也有一个一样的成员名,把函数体赋值给这个属性。==>函数整体提升
3、运行代码:
运:运行代码。 函数运行完毕,AO就释放了
二、全局预编译
全局作用域运行代码时,也有预编译==> 全局预编译==> 形 [变量] 函 运 1、生成一个对象Global Object ( GO:{ } ) 2、把所有的全局变量设置为GO的属性名 3、把所有函数名作为GO的成员名,把哈桑农户体赋值给这个成员 全局编译还有一步,不同的环境中JS代码不一样 如果是浏览器,还会执行异步GO给window对象共享成员 GO对象的成员全部浅拷贝给环境对象window (node.js 环境中没有这一步) 4、执行代码
拓展:关于访问成员: console.log(a) 访问的是GO对象的成员,如果作用域链中都没有就报错 console.log(window.a) 原型链上如果都没有就返回undefined,不会报错
三、作用域链
closure:闭包
JS对象有两种成员: 1、上文成员(JS语法可以直接访问的成员) 2、下文成员(底层语法访问的成员)==> [[]]括起来的成员名,就是下文成员
函数的属性: length、name、[[scoped]] ==> [[scoped]] ==> 这个“对象”内存保存的就是函数的作用域。可以通过console.dir(fn)看见。 函数在定义/声明的时候,就有了[[scoped]] (只能引擎使用),里面保存了上层的AO对象 ==> 函数调用时会生成AO对象,AO保存在[[scoped]] 对象内部,每次调用都会放在scoped的上面,先放的就放在下面 每个函数scopes数组天生就有一个AO对象,就是这个函数的上层的AO 总结: 函数定义/声明 ==> 生成scopes,并将本来就有的GO/AO放入到scopes的最下面 函数调用 == > 生成AO
function fn(a) { function fm() { var b=20 console.log(a) } fm() } var c=2 fn(10) fn(20)
AO会被销毁
下一篇:
Java实现自动猜数(猜数游戏进阶版)