js作用域(scope)的学习
v8引擎的原理
js源代码->parse(解析)->ast->lgnition(v8的库(模块)) -> 字节码(bytecode) -> cpu可以运行的代码
bytecoed的优势,就是跨平台
全局代码执行过程
console.log(num); // undefined vo找GO的num值,执行第一行num值为undefined -> 作用域提升
var name = 'Fhup'
var num = 3 // 解析时加入GO 默认值为undefined
console.log(window);
/**
* 1. js源代码被解析,v8引擎内部帮助我们在堆内存创建一个对象 (globalObject => GO)
* 2. 运行代码
* 2.1 v8为了执行代码,内部有一个 执行上下文栈(ECStack) (函数调用栈)
* 2.2 全局执行的代码,会创建 全局执行上下文(Global Execution Content GEC) (全局代码执行时才会创建)
* 2.2.1 全局执行上下文里面有VO (VO指向GO)
* 2.3 开始执行代码(在VO中按顺序执行),同时确定其父类作用域 vo指向go,改变默认的undefined值
*
*
* 解析时发现是函数(数组也是一样):
* 1.1 开始解析时发现是函数,堆内存中创建该函数对象,确定父类作用域和函数体
* 1.2 执行函数时,创建一个 函数执行上下文(FEC) 内部维持VO:->AO, 在堆内存中创建AO对象.对函数体
* 内容进行解析执行
*/
var globalObject = {
String:'类',
Data:'类',
setTimeoutL:'函数',
window:globalObject,
name: '' | '执行时赋值',
num: undefined
}
// 全局对象里面还有全局对象 GO里面的window又指向GO
console.log(window.window.window.window);
函数执行过程
var name = 'Fhup'
foo(9)
// 函数的执行在 函数执行上下文(FEC) 里面,里面也有VO,而VO对应AO(AO称为函数的活跃对象但会被销毁)
function foo(num) {
console.log(h); // undefined
var f = 100
var h = 300 // 将f,h提升到AO中且值为undefined,而AO与GO相似
console.log(name); /// name=Fhup 查找变量时,沿着作用域链来查找.作用域链为AO(当前)+GO(父类作用域)
}
// 执行完,VO弹栈,AO销毁
var globalObject = {
String:'类',
window:globalObject,
name: '' | '执行时赋值',
// 发现是函数,开辟新的内存空间进行存储(称为:存储函数空间).
foo: `0xa00` // 内存地址
}
函数嵌套(作用域链)
var name = 'Fhup'
// 注意: name变量在window对象上存在,一般不使用
foo(9)
function foo(num) {
console.log(h);
var h = 300
function bar() {
console.log(name) // 沿着作用域链找:AO(当前) + parent scope(上层作用域:foo的AO) + GO ,如果还没有,就会报错
}
bar()
// 1.bar执行完后,bar的VO弹栈,bar的AO销毁.
}
// 2.bar的VO弹栈之后,foo执行完,foo的VO弹栈,foo的AO销毁
var globalObject = {
String:'类',
window:globalObject,
name: '' | '执行时赋值',
foo: `0xa00`,
bar: `0xb00` // bar指向oxb00空间
}
函数互调(作用域链)
var mes = 'hello global'
/**
* 父级作用域: 在编译时确定,从上往下(从第一行到最后),与调用无关 foo作用域: AO(当前)+GO
*/
function foo() {
// 在编译时确定foo的父级作用域,为GO
// 不是看代码的父级作用域(跟调用位置无关,跟定义位置有关) 所以mes去GO找mes的值
// 编译时父级作用域就会确定好,执行时不会改变
console.log(mes); // hello global
}
function bar() {
var mes = 'Fhup'
foo()
}
bar()
ECMA规范
/**
* 早期的ECMA版本规范:
* 每一个执行上下文会被关联到一个变量对象(variable object,VO),在源代码中的变量和函数声明会被作为属性添加到VO
* 中。对于函数来说,参数也会被添加到VO中。
*/
/**
* 最新的ECMA版本规范:
* 每一个执行上下文会关联到一个变量环境(VariableEnvironment)中,在执行代码中变量和函数的声明会作为环境记录(E
* Environment Record)环境中。对于函数来说,参数也会被作为环境记录添加到变量环境中。
*
* 注意: 变量环境(VariableEnvironment)和环境记录(Environment Record)存在于词法环境中
*/