一道JS作用域面试题解析(了解原理,类似都是通用的)

今天学习了coderwhy老师的JS高级课程,对作用域有了更深的了解,也理解了常见的作用域面试题的解题思路,以下仅作记录。
题目:

var message = "Hello Global"
function foo() {
    console.log(message)
}
function bar() {
    var message = "Hello Bar"
    foo()
}
bar()

首先全局对象Global Object会在编译阶段对所有定义的变量进行添加,则

{
	window: Object,
	xxx: ...
	message: undefined,
	foo: 0xa00,
	bar: 0xb00
}

其中由于foo和bar为函数,全局环境记录的是它们的引用地址(这里用0xa00模拟),而函数自身的Activation Object也会在编译阶段添加函体定义的变量,同时会记录自己的父级作用域[parent scope](在这里是GO,如果函数里面嵌套函数的话,也是一层层的记录则形成作用域链,比如变量m如果在函数体AO内找不到,会到它的父级作用域[parent scope]寻找变量m,如果没有就一直找到全局对象为止)。
foo函数对象0xa00

[parent scope]:Global Object
函数体:代码块(函数体内没有定义变量,编译阶段无需初始化)

bar函数对象0xa00

[parent scope]:Global Object
函数体:代码块({message: undefined})

所有VO(包含GO和AO编译完成后),执行上下文调用栈(ECStack)开始从上到下按顺序执行代码
1.全局message赋值为Hello Global
2.调用bar函数(bar函数执行上下文(FEC)进入调用栈,直到函数执行完成就退出栈)
3.bar函数内message赋值为Hello Bar
4.调用foo函数(foo函数执行上下文(FEC)进入调用栈,直到函数执行完成就退出栈)
5.foo函数打印message变量
6.因为foo自身的AO无该变量,才到父级作用域[parent scope]寻找
7.它的父级作用域是GO,找到message变量,输出Hello Global(执行完毕,退出栈)

按照先编译后执行的顺序,即可完成题目,注意的是如函数体内var a = b = 100,如果b在函数体内无声明,会被添加到父级作用域的AO上,还有如果函数体内return语句后还有代码如var c = 10;那么它在编译阶段不会受影响还是会被添加到自身AO上,但该代码不会被执行即c为undefined不会赋值为10

总结(coderwhy老师原话,不是我总结的)
基于早期ECMA的版本规范:
每一个执行上下文会被关联到一个变量环境(variable object,VO),在源代码中的变量和函数声明会被作为属性添加到VO中。对于函数来说,参数也会被添加到VO中。
最新的ECMA的版本规范中:
每一个执行上下文会关联到一个变量环境(VariableEnvironment)中,在执行代码中变量和函数的声明会作为环境记录(Environment Record)添加到变量环境中。对于函数来说,参数也会被作为环境记录添加到变量环境中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值