面试官:聊聊作用域问题

504 阅读2分钟

欢迎大家关注我的公众号《人生代码》

大前端博客

一个专注于分享美女小黄图的网站,一个有趣的网站,一个具有后端管理系统,小程序一整套的网站,搜索美女图片功能 确认用户是否是选择男还是女的 图片预览功能 详情 用户点赞,评论,收藏 可以订阅别人的相册 可以创建相册 首页,用户中心,创建相册

全局作用域

script 标签所在的区域就是所谓的全局作用域,全局作用域有一个全局的对象 window

我们所有定义的变量,函数,类,对象等等都是作用域 window 对象身上的

var a = 1
// 就是在window 对象上加上一个 a 属性

局部作用域(特指函数作用域)

function foo(a) {
  console.log(a)
}

foo(2)

会产生一个局部作用域,暂且叫做 fooScope, 这个作用域里面存储着这个局部作用域里面的所有变量定义,函数定义,对象定义等等。 值得注意的是,全局作用域 globalScope 总是被我们忽视了,局部作用域是可以访问全局作用域的。

所以


globalScope(顶层)
    |
    |
fooScope(当前)

发出疑问

  1. 既然局部作用域能够访问全局作用域的变量,那么局部作用域能不能修改全局作用域变量的值呢?

答案是可以的,我们来看个简单的例子

var a = 1
function foo() {
    a = a + 1
    console.log(a); // 2
}
foo()

console.log(a) // 2

函数参数是值引用

var a = 1
function foo(a) {
    a = a + 1
    console.log(a)
}
foo(a) // 2

console.log(a) // 1 说明全局中的 a 与函数参数的 a 存储的地方不一样

嵌套作用域

var a = 1
function foo(a) {
    function bar(a) {
        console.log("bar ===>", a)
        console.log(this)
    }
    console.log("foo", this)
    bar(a)
}
foo(a)

打印出来的顺序如下:

foo: window
bar===> 1
window

先来说说这个 a 的寻找过程:

  1. bar 执行,会在自己的作用域 barScope 找这个变量 a
  2. 发现找不到,会在 fooScope 作用域找,发现找不到
  3. 就找到全局作用域 window 中,发现有 a 这个变量

我们来验证下寻找的过程:

var a = 1
function foo() {
    var a = 2
    function bar() {
        console.log("bar ===>", a)
        console.log(this)
    }
    console.log("foo", this)
    bar()
}
foo()

打印出来如下:

foo:window
bar===>2
bar:window

所以找到要用到的变量之后,就会停止寻找了。

执行顺序

  1. 词法解析

    解析全局作用域,函数,变量

  2. 语法解析

    生成程序结构树

  3. 代码生成

  4. 执行代码

var a = 1
function foo() {
    var a = 2
    function bar(a) {
        console.log("bar ===>", a)
        console.log("bar ===>",this)
    }
    console.log("foo", this)
    bar(a)
}
foo()

所以

解析阶段

  1. 全局作用域 有变量 a
  2. foo 作用域 有 fooScope.a/window.a
  3. bar 作用域 有barScope/fooScope.a/window.a

执行阶段

  1. bar 执行返回,销毁
  2. foo 执行返回,销毁
  3. window

这样就形成了作用域链