作用域 & 作用域链
在JS中,作用域是通过函数划分的,函数的作用域在定义阶段就已经确定:
- 最外层函数,和最外层定义的变量,拥有全局作用域
- 未声明,直接赋值的变量,拥有全局作用域
- 函数内部定义的变量,拥有局部作用域
- 另外,所有的window对象的属性和方法拥有全局作用域,因此我们调用
alert()和window.alert()效果是一样的。(window对象更多方法,参考JavaScript基础三)
当出现函数嵌套时,就会出现作用域链。解释器在查找变量时,会根据作用域链,从内到外寻找,找到就停止,找不到抛出异常。
AO对象 & 词法分析
JS代码运行分为两个阶段:先进行词法分析,再执行。
一个函数被调用的一瞬间,产生一个活动对象AO(Active Object),词法分析会为该对象填充属性。
词法分析根据作用域链,从外到里进行分析,分为三步:
- 分析形参/实参
- 分析变量声明(注意,变量的值是在执行时候决定的)
- 分析函数声明
下面通过一个例子来说明:
function bar(age) {
console.log(age);
var age = 99;
var sex= 'male';
console.log(age);
function age() {
alert(123)
}
console.log(age);
return 100;
}
bar(5);
/* 运行结果
ƒ age() { alert(123) }
99
99
100 - 返回值
*/
说明:
- 调用bar函数的瞬间,生成AO
- 分析形参/实参:
- 函数声明时的形参,作为AO的属性,默认值undefined,即AO.age = undefined
- 接收实参5,给AO.age属性赋值,即AO.age = 5
- 分析变量声明:
- 如果AO还没有该属性,添加;如果有(相当于重新声明),不执行任何操作,原来的值不会消失
- 第3行,找到声明
var age,判断已经存在AO.age,不作任何处理 - 第4行,找到声明
var sex,添加AO.sex = undefined
- 分析函数声明:
- 如果AO还没有该属性,添加;如果有,则直接覆盖(太霸道了。。。)
- 第7行,找到
function age() {...}声明,则覆盖原来的AO.age = 5,变为AO.age = function age() {}
- 执行过程:
- 执行第2行
console.log(age)时,当前AO.age = function age() {…} —— 输出函数 - 执行第3行
age = 99时,对AO.age赋值 99 - 执行第4行
sex= 'male'时,对AO.sex赋值 male - 执行第5行
console.log(age)时,AO.age = 99 —— 输出99 - 注意,第7行
function age() {...}函数声明,不进行任何操作,因为词法分析阶段已经完成了。 - 执行第11行,
console.log(age)时,AO.age还是99 —— 输出99 - foo函数返回100
- 执行第2行
1544

被折叠的 条评论
为什么被折叠?



