学习JS(二): 图解作用域面试题

每天对自己多问几个为什么,总是有着想象不到的收获。 一个菜鸟小白的成长之路(copyer)

第二集:图解面试作用域面试题

面试题:

var message = 'copyer'

function foo() {
    
    
    console.log(message);      // copyer
}

function bar() {
    
    
    var message = 'james'
    foo()
}

bar()

在上面的面试题中,答案是 copyer。为什么?

这里就涉及到了作用域链的问题。废话不多说,直接画图。

前面我们知道,在执行代码之前,会被代码进行词法进行解析,并添加在全局的对象中。

所有的代码,都是在JS引擎中的调用栈中执行,也就是执行上下文栈

在这里插入图片描述

在执行代码的前面,会进行词法分析,然后绑定在全局对象(GO)中

var GlobalObject = {
    
    
    window: GlobalObject,
    message: undefined,
    foo: 0x100,
    bar: 0x200
}

所以在分析过程中,就会在堆中创建三个内存地址,存放三个对象。

在这里插入图片描述

值得注意的是,这里 [parent scope] 是在编译的时候,就已经确定父级作用域

词法分析完成后,就开始执行代码,然后给GO里面的变量进行赋值

var GlobalObject = {
    
    
    window: GlobalObject,
    message: 'copyer',
    foo: 0x100,
    bar: 0x200
}

然后就是执行 bar(),调用bar这个函数,这里也会创建函数执行上下文(FEC)

在这里插入图片描述

这里也会 创建一个对象 Activation Object(AO),保存预编译的变量和函数,如果有 函数嵌套就是AO对象中。

然后就是开始执行代码、

var ActivationObject = {
    
    
    message: 'james'
}
foo()

这里执行 foo函数吗,也会在调用栈中创建一个 函数执行上下文,以及在堆中重新创建一个AO对象。这里就不画了。就看看完成的图吧。

在这里插入图片描述

上面就是整体的流程图,执行函数 进栈的操作,执行完函数后,出栈的操作

这下在回头看面试题,在foo函数中并没有message这个变量,(即AO对象中,没有message属性),那么按照作用域链继续查找, 根据scopechainAO 中没有,就去 parentScope里面去找

而这里的 parentScope就是 GO了,这里是在最初的编译的时候,就已经确定了。

所以 GO中的message为copyer, 这下就知道为什么了吧。

目标:

理解 parentScope的指向

理解 scopechain的整体线

猜你喜欢

转载自blog.csdn.net/James_xyf/article/details/121071515
今日推荐