Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript深入之变量对象 #5

Open
mqyqingfeng opened this issue Apr 23, 2017 · 154 comments

Comments

@mqyqingfeng
Copy link
Owner

commented Apr 23, 2017

前言

在上篇《JavaScript深入之执行上下文栈》中讲到,当 JavaScript 代码执行一段可执行代码(executable code)时,会创建对应的执行上下文(execution context)。

对于每个执行上下文,都有三个重要属性:

  • 变量对象(Variable object,VO)
  • 作用域链(Scope chain)
  • this

今天重点讲讲创建变量对象的过程。

变量对象

变量对象是与执行上下文相关的数据作用域,存储了在上下文中定义的变量和函数声明。

因为不同执行上下文下的变量对象稍有不同,所以我们来聊聊全局上下文下的变量对象和函数上下文下的变量对象。

全局上下文

我们先了解一个概念,叫全局对象。在 W3School 中也有介绍:

全局对象是预定义的对象,作为 JavaScript 的全局函数和全局属性的占位符。通过使用全局对象,可以访问所有其他所有预定义的对象、函数和属性。

在顶层 JavaScript 代码中,可以用关键字 this 引用全局对象。因为全局对象是作用域链的头,这意味着所有非限定性的变量和函数名都会作为该对象的属性来查询。

例如,当JavaScript 代码引用 parseInt() 函数时,它引用的是全局对象的 parseInt 属性。全局对象是作用域链的头,还意味着在顶层 JavaScript 代码中声明的所有变量都将成为全局对象的属性。

如果看的不是很懂的话,容我再来介绍下全局对象:

1.可以通过 this 引用,在客户端 JavaScript 中,全局对象就是 Window 对象。

console.log(this);

2.全局对象是由 Object 构造函数实例化的一个对象。

console.log(this instanceof Object);

3.预定义了一堆,嗯,一大堆函数和属性。

// 都能生效
console.log(Math.random());
console.log(this.Math.random());

4.作为全局变量的宿主。

var a = 1;
console.log(this.a);

5.客户端 JavaScript 中,全局对象有 window 属性指向自身。

var a = 1;
console.log(window.a);

this.window.b = 2;
console.log(this.b);

花了一个大篇幅介绍全局对象,其实就想说:

全局上下文中的变量对象就是全局对象呐!

函数上下文

在函数上下文中,我们用活动对象(activation object, AO)来表示变量对象。

活动对象和变量对象其实是一个东西,只是变量对象是规范上的或者说是引擎实现上的,不可在 JavaScript 环境中访问,只有到当进入一个执行上下文中,这个执行上下文的变量对象才会被激活,所以才叫 activation object 呐,而只有被激活的变量对象,也就是活动对象上的各种属性才能被访问。

活动对象是在进入函数上下文时刻被创建的,它通过函数的 arguments 属性初始化。arguments 属性值是 Arguments 对象。

执行过程

执行上下文的代码会分成两个阶段进行处理:分析和执行,我们也可以叫做:

  1. 进入执行上下文
  2. 代码执行

进入执行上下文

当进入执行上下文时,这时候还没有执行代码,

变量对象会包括:

  1. 函数的所有形参 (如果是函数上下文)

    • 由名称和对应值组成的一个变量对象的属性被创建
    • 没有实参,属性值设为 undefined
  2. 函数声明

    • 由名称和对应值(函数对象(function-object))组成一个变量对象的属性被创建
    • 如果变量对象已经存在相同名称的属性,则完全替换这个属性
  3. 变量声明

    • 由名称和对应值(undefined)组成一个变量对象的属性被创建;
    • 如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性

举个例子:

function foo(a) {
  var b = 2;
  function c() {}
  var d = function() {};

  b = 3;

}

foo(1);

在进入执行上下文后,这时候的 AO 是:

AO = {
    arguments: {
        0: 1,
        length: 1
    },
    a: 1,
    b: undefined,
    c: reference to function c(){},
    d: undefined
}

代码执行

在代码执行阶段,会顺序执行代码,根据代码,修改变量对象的值

还是上面的例子,当代码执行完后,这时候的 AO 是:

AO = {
    arguments: {
        0: 1,
        length: 1
    },
    a: 1,
    b: 3,
    c: reference to function c(){},
    d: reference to FunctionExpression "d"
}

到这里变量对象的创建过程就介绍完了,让我们简洁的总结我们上述所说:

  1. 全局上下文的变量对象初始化是全局对象

  2. 函数上下文的变量对象初始化只包括 Arguments 对象

  3. 在进入执行上下文时会给变量对象添加形参、函数声明、变量声明等初始的属性值

  4. 在代码执行阶段,会再次修改变量对象的属性值

思考题

最后让我们看几个例子:

1.第一题

function foo() {
    console.log(a);
    a = 1;
}

foo(); // ???

function bar() {
    a = 1;
    console.log(a);
}
bar(); // ???

第一段会报错:Uncaught ReferenceError: a is not defined

第二段会打印:1

这是因为函数中的 "a" 并没有通过 var 关键字声明,所有不会被存放在 AO 中。

第一段执行 console 的时候, AO 的值是:

AO = {
    arguments: {
        length: 0
    }
}

没有 a 的值,然后就会到全局去找,全局也没有,所以会报错。

当第二段执行 console 的时候,全局对象已经被赋予了 a 属性,这时候就可以从全局找到 a 的值,所以会打印 1。

2.第二题

console.log(foo);

function foo(){
    console.log("foo");
}

var foo = 1;

会打印函数,而不是 undefined 。

这是因为在进入执行上下文时,首先会处理函数声明,其次会处理变量声明,如果如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性。

下一篇文章

《JavaScript深入之作用域链》

本文相关链接

《JavaScript深入之执行上下文栈》

深入系列

JavaScript深入系列目录地址:https://github.com/mqyqingfeng/Blog

JavaScript深入系列预计写十五篇左右,旨在帮大家捋顺JavaScript底层知识,重点讲解如原型、作用域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等难点概念。

如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎star,对作者也是一种鼓励。

@jDragonV

This comment has been minimized.

Copy link

commented May 10, 2017

Arguments对象是什么 - -。

@mqyqingfeng

This comment has been minimized.

Copy link
Owner Author

commented May 10, 2017

引用《JavaScript权威指南》回答你哈:调用函数时,会为其创建一个Arguments对象,并自动初始化局部变量arguments,指代该Arguments对象。所有作为参数传入的值都会成为Arguments对象的数组元素。

@jDragonV

This comment has been minimized.

Copy link

commented May 12, 2017

VO 和 AO 到底是什么关系。

@jawil

This comment has been minimized.

Copy link

commented May 12, 2017

未进入执行阶段之前,变量对象(VO)中的属性都不能访问!但是进入执行阶段之后,变量对象(VO)转变为了活动对象(AO),里面的属性都能被访问了,然后开始进行执行阶段的操作。

它们其实都是同一个对象,只是处于执行上下文的不同生命周期。@jDragonV

@mqyqingfeng

This comment has been minimized.

Copy link
Owner Author

commented May 12, 2017

@jawil 非常感谢回答,一语中的。

@alexzhao8326

This comment has been minimized.

Copy link

commented May 23, 2017

@mqyqingfeng 楼主,有幸拜读你的深入系列,收获颇多,但也存在一些疑问。比如变量对象留给我们的思考题的第二题,按照你的写法:

console.log(foo);

function foo(){
    console.log("foo");
}

var foo = 1; // 打印函数

但个人觉得这句“这是因为在进入执行上下文时,首先会处理函数声明,其次会处理变量声明,如果如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性。”解释得有点欠完整,如果我把代码改写成下面这样:

var foo = 1;
console.log(foo);
function foo(){
    console.log("foo");
};

这次打印结果就是“1”;

所以我觉得这么解释比较好:

进入执行上下文时,首先会处理函数声明,首先会处理函数声明,其次会处理变量声明,如果如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性。

进入代码执行阶段,先执行console.log(foo),此时foo是函数的应用,再执行var foo = 1;将foo赋值为1,而在我改写的例子里中,先执行var foo = 1;再执行console.log(foo),所以打印1。我觉得加上代码执行阶段会更清晰,哈哈哈

@jawil

This comment has been minimized.

Copy link

commented May 23, 2017

一个执行上下文的生命周期可以分为两个阶段。

  1. 创建阶段

在这个阶段中,执行上下文会分别创建变量对象,建立作用域链,以及确定this的指向。

  1. 代码执行阶段

创建完成之后,就会开始执行代码,这个时候,会完成变量赋值,函数引用,以及执行其他代码。

都没有错,博主讲的主要是针对变量对象,而变量对象的创建是在EC(执行上下文)的创建阶段,所以侧重点主要是EC的生命周期的第一个阶段,我觉得再执行var foo = 1这句话有点不妥,应该是给foo赋值,应该是执行foo=1这个操作,因为在EC创建阶段var已经被扫描了一遍。

@alexzhao8326

@alexzhao8326

This comment has been minimized.

Copy link

commented May 23, 2017

是的,显然你的说法更严谨,也符合分析的过程! 学习了@jawil

@mqyqingfeng

This comment has been minimized.

Copy link
Owner Author

commented May 23, 2017

@jawil 哈哈,十分感谢回答~~~ @alexzhao8326 这道题应该是因为没有分成两个阶段来讲,所以让你觉得分析得不是很完整吧。我在写的时候,觉得毕竟是思考题,讲清楚问题的关键点即可,所以也没有给出完整的分析。如果你看完前面的内容,相信你一定能明白结果为什么会是这样,对于你修改后的例子,相信你也能解释的了。当然了,学习时严谨的态度还是要有的,感谢指出,o( ̄▽ ̄)d

@mqyqingfeng

This comment has been minimized.

Copy link
Owner Author

commented May 26, 2017

@wedaren 进入执行上下文时,初始化的规则如下,从上到下就是一种顺序:

default

@zuoyi615

This comment has been minimized.

Copy link

commented May 26, 2017

var foo = 1;
console.log(foo);
function foo(){
  console.log("foo");
};
这次打印结果就是“1”;

分解
var foo; // 如果如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性
foo = 1;// 代码执行。PS: 如果没有这行,打印结果是 function foo(){console.log('foo')};
console.log(foo); // 1
function foo(){
  console.log("foo");
};

执行上下文的时候:

VO = {
    foo: reference to function foo(){}
}

然后再执行了 foo = 1 的操作,修改变量对象的 foo 属性值

AO = {
    foo:  1
}

执行代码 console.log(foo) 的结果: 1

@mqyqingfeng

This comment has been minimized.

Copy link
Owner Author

commented May 26, 2017

@zuoyi615 感谢写下自己的分析过程,如果这段代码是在全局环境下执行的,变量对象应该用 VO 表示,此时也没有 arguments 属性

@mqyqingfeng

This comment has been minimized.

Copy link
Owner Author

commented May 27, 2017

@zuoyi615 o( ̄▽ ̄)d

@oakland

This comment has been minimized.

Copy link

commented May 29, 2017

@jawil ,你说的有一点误差,AO 实际上是包含了 VO 的。因为除了 VO 之外,AO 还包含函数的 parameters,以及 arguments 这个特殊对象。也就是说 AO 的确是在进入到执行阶段的时候被激活,但是激活的除了 VO 之外,还包括函数执行时传入的参数和 arguments 这个特殊对象。
AO = VO + function parameters + arguments
@jDragonV

@mqyqingfeng

This comment has been minimized.

Copy link
Owner Author

commented May 29, 2017

@oakland 非常感谢补充~~~ 这一点我也没有注意到~ o( ̄▽ ̄)d

@ckclark

This comment has been minimized.

Copy link

commented May 30, 2017

是w3school 不是W3C school

@mqyqingfeng

This comment has been minimized.

Copy link
Owner Author

commented May 31, 2017

@ckclark 哎呀呀,我犯了一个严重的错误,非常感谢指出~o( ̄▽ ̄)d

@MrGoodBye

This comment has been minimized.

Copy link

commented May 31, 2017

思考题第二题:

console.log(foo);

function foo(){
    console.log("foo");
}

var foo = 1;

解:
JavaScript发现了一段可执行代码(executable code),准备创建对应的执行上下文(execution context):

在此之前

因为JavaScript的函数提升特性,将代码等量变换为:(1)

function foo(){// 函数提升
    console.log("foo");
}
console.log(foo);
var foo = 1;

又因为JavaScript的变量提升特性,将代码等量变换为:(2)

function foo(){// 函数提升
    console.log("foo");
}
var foo;// 变量提升
console.log(foo);
foo = 1;

开始创建对应的执行上下文(execution context):(3)

  • 变量对象(Variable object,VO)
  • 作用域链(Scope chain)
  • this

其中,此处探讨的VO只是被初始化(4)

当javaScript扫描到console.log(foo)时,执行代码之前,先进入执行上下文(execution context),(5)

因为在进入执行上下文时,首先会处理函数声明,其次会处理变量声明,如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性。

VO = {
    foo: reference to function foo(){},
    ~foo:undefined// 此处疑问: 此处变量声明的foo是否保存在VO中;以何种形式保存
}

执行代码console.log(foo),查找到了VO中的foo,输出结果.(6)
接着执行foo = 1,执行之后,VO为:(7)

VO = {
    foo: 1
}

解答完毕.

第4处跟第5处都不很确定,其他地方也可能有理解不到位.请大家指出.

@MrGoodBye

This comment has been minimized.

Copy link

commented May 31, 2017

console.log(foo);

function foo(){
    console.log("foo");
}

var foo = 1;
console.log(foo);

var foo = 1;

function foo(){
    console.log("foo");
}

另外,以上两处代码得出的结论一样,说明:

同一作用域下,函数提升比变量提升得更靠前.

大家知道的微微一笑就好了:)

@xumengzi

This comment has been minimized.

Copy link

commented May 31, 2017

根据你们的讨论,关于这一段代码的实现,

console.log(foo);
var foo = 1;
console.log(foo);
function foo(){};

执行结果是函数和1,我可以这样理解么?

foo() 			  //函数提升
var foo			  //和函数重名了,被忽略
console.log(foo);	  //打印函数
foo = 1;		  //全局变量foo
console.log(foo);	  //打印1,事实上函数foo已经不存在了,变成了1

望不吝赐教!

@liuxiumei123

This comment has been minimized.

Copy link

commented Jan 18, 2019

思考题第二题:

console.log(foo);

function foo(){
    console.log("foo");
}

var foo = 1;

解:
JavaScript发现了一段可执行代码(executable code),准备创建对应的执行上下文(execution context):

在此之前

因为JavaScript的函数提升特性,将代码等量变换为:(1)

function foo(){// 函数提升
    console.log("foo");
}
console.log(foo);
var foo = 1;

又因为JavaScript的变量提升特性,将代码等量变换为:(2)

function foo(){// 函数提升
    console.log("foo");
}
var foo;// 变量提升
console.log(foo);
foo = 1;

开始创建对应的执行上下文(execution context):(3)

  • 变量对象(Variable object,VO)
  • 作用域链(Scope chain)
  • this

其中,此处探讨的VO只是被初始化(4)

当javaScript扫描到console.log(foo)时,执行代码之前,先进入执行上下文(execution context),(5)

因为在进入执行上下文时,首先会处理函数声明,其次会处理变量声明,如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性。

VO = {
    foo: reference to function foo(){},
    ~foo:undefined// 此处疑问: 此处变量声明的foo是否保存在VO中;以何种形式保存
}

执行代码console.log(foo),查找到了VO中的foo,输出结果.(6)
接着执行foo = 1,执行之后,VO为:(7)

VO = {
    foo: 1
}

解答完毕.

第4处跟第5处都不很确定,其他地方也可能有理解不到位.请大家指出.

又因为JavaScript的变量提升特性,将代码等量变换为:(2)`

function` foo(){// 函数提升
console.log("foo");
}
var foo;// 变量提升
console.log(foo);
foo = 1;

这里应该为
function` foo(){// 函数提升
console.log("foo");
}
console.log(foo);
foo = 1;

去掉var foo;首先是函数声明提升,然后是变量声明提升。在变量提升的时候如果和函数名相同,那么会忽略变量声明。

@pinguo-laihouxin

This comment has been minimized.

Copy link

commented Jan 28, 2019

您好博主, 看了您的博客和底下的评论受益匪浅, 假设我有这么一段代码, 不知道我的分析是否正确:

function bar(a, b) {
    console.log(a, b) // 2, b 函数
    var a = 1
    function b() {}
    console.log(a, b) // 1, b 函数
}
bar(2, 3)

个人分析:

在预编译阶段, 函数 bar 的 AO 如下:

AO = {
    arguments: {
        0: 2,
        1: 3,
        length: 2
    },
    a: 2,
    b: reference to function b(){},
}

在执行阶段, 函数 bar 的 AO 如下:

AO = {
    arguments: {
        0: 2,
        1: 3,
        length: 2
    },
    a: 1, // 重新赋值
    b: reference to function b(){},
}

第一个console.log(a, b)的时候, 此时的AO"等同于"预编译时的AO(还没对变量重新赋值), 而第二个console.log(a, b)AO是已经重新赋值的AO, 就是最后执行阶段结束以后的AO.

不知道这样理解是否正确, 本人水平不高, 若有错误还请及时指出!

应该这样理解,刚创建执行上下文的时候:

AO = {
    arguments: {
        0: 2,
        1: 3,
        length: 2
    }
}

然后进入执行上下文,经过变量提升,函数提升,变成:

AO = {
    arguments: {
        0: 2,
        1:  reference to function b(){},
        length: 2
    },
    a: 2,
    b: reference to function b(){},
}
@freewalker8

This comment has been minimized.

Copy link

commented Feb 18, 2019

理解为函数提升和变量提升更好理解
console.log(foo);
function foo(){
console.log("foo");
}
var foo = 1;
执行步奏为:
var foo = function(){console.log("foo")}
console.log(foo)//打印出函数
foo = 1;

console.log(foo);
var foo = 1;
function foo(){
console.log("foo");
}
执行步奏为:
var foo = function(){console.log("foo")}
console.log(foo)//打印出函数
foo = 1;

var foo = 1;
console.log(foo);
function foo(){
console.log("foo");
}
执行步奏为:
var foo = function(){console.log("foo")}
foo = 1
console.log(foo)//打印1

@alexzhao8326

@BinghuiXie

This comment has been minimized.

Copy link

commented Feb 19, 2019

有一个问题想请教一下
我的代码是这样写的
var textObj = 'textObj';
console.log(this.textObj);
打印出来的就是textObj
但是当我将var 换成let 的时候
let textObj = 'textObj';
console.log(this.textObj);
打印出来的就是 undefined
这个是什么原因

@magicstf

This comment has been minimized.

Copy link

commented Mar 16, 2019

@MrGoodBye 在《JavaScript深入之执行上下文栈》中,我以前写错了一点,现在已经修正了,其实是在函数执行的时候,才创建执行上下文,这个可能将你误导了,我很抱歉。

因为第二个例子的代码写在了全局中,所以函数声明和变量声明都是在全局对象中,在代码执行阶段,执行 console.log 时,会创建 console.log 函数的执行上下文,然后读取全局变量中的 foo ,然后因为覆盖规则的原因,打印函数

我觉得不能用覆盖规则解释吧,第二个例子根据js 函数提升,变量提升的规则,可以写成这样
function foo(){
console.log("foo")
}
var foo;
console.log(foo)
foo = 1;

那按照覆盖规则,下面覆盖上面的,那应该是undefined 覆盖函数啊,之所以打印的是函数是因为上面说的
在进入执行上下文时,首先会处理函数声明,其次会处理变量声明,如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性,有个疑问是这个变量声明不干扰已经存在的这类熟悉,这个“不干扰”具体是怎么实现的? 俩个foo 都存在? 还是值存在指向函数引用的foo?

@magicstf

This comment has been minimized.

Copy link

commented Mar 16, 2019

console.log(foo);

function foo(){
console.log("foo");
}

var foo = 1;
VM36186:1 ƒ foo(){
console.log("foo");
}
undefined

我在chrome 控制台运行问题二, 函数和undefined 都打印出来了,这是为什么?

我按照变量提升、函数提升 改造示例二如下:
function foo() {
console.log("foo")
}
var foo;
console.log(foo);
foo = 1
VM36647:5 ƒ foo() {
console.log("foo")
}
1

在控制台输出了函数和1 这又是为什么? 求大神简答

@Yanhua67

This comment has been minimized.

Copy link

commented Mar 22, 2019

@magicstf
js中所有的表达式都会有返回值,如果没有返回值就是undefined,这个返回值就可以作为表达式的一部分。
看一下表达式和语句的区别。。

@Yanhua67

This comment has been minimized.

Copy link

commented Mar 22, 2019

@BinghuiXie 因为let声明的变量不存在于全局,在一个叫做Script的作用域里面。

@Chorer

This comment has been minimized.

Copy link

commented Apr 9, 2019

博主你好,我想问一下ES5提出了词法环境的环境记录这个概念,它和AO/VO扮演的角色很像,即同样存储变量和函数声明,那么基于变量对象和作用域链去认识的闭包的概念应该怎么重新去理解呢?

@wangxiaoxaio

This comment has been minimized.

Copy link

commented Apr 21, 2019

思考题二的执行过程:

function foo(){console.log('foo')};
var foo;
console.log(foo); //[Function:foo]
foo=1;

@Bananaandpen

This comment has been minimized.

Copy link

commented May 5, 2019

有一个问题想请教一下
我的代码是这样写的
var textObj = 'textObj';
console.log(this.textObj);
打印出来的就是textObj
但是当我将var 换成let 的时候
let textObj = 'textObj';
console.log(this.textObj);
打印出来的就是 undefined
这个是什么原因

可以去看一下var和let的区别,var声明的变量和函数是挂载到全局变量也就是window(this)下,而let声明的变量是挂载到global上,window(this)不等于global。所以console.log(this.textObj)打印window下的textObj是undefined

@Bananaandpen

This comment has been minimized.

Copy link

commented May 5, 2019

console.log(foo) //打印函数

function foo(){
console.log('foo')
}
var foo = 1;
console.log(foo) //打印函数

var foo = 1;

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

在预编译阶段,无论是函数foo在变量foo之前,还是变量foo在函数foo之前。在名字相同的情况下,函数声明总是比变量声明优先。^_^

@pinguo-laihouxin

This comment has been minimized.

Copy link

commented Jun 4, 2019

求问博主,想let,const这种变量声明也会保存在活动对象里么?

@zhaofeihao

This comment has been minimized.

Copy link

commented Jun 10, 2019

emmm,那么所谓的变量提升、函数提升都是骗人的。。。果然还是得深挖啊

@fengandzhy

This comment has been minimized.

Copy link

commented Jun 23, 2019

(
    function fn1(){
        console.log('abcd');
    }
);
console.log(fn1);

请教博主及各位同仁,以上代码为什么会报错?

@jugg-chen

This comment has been minimized.

Copy link

commented Jun 28, 2019

console.log(f); // undefined
if (false) { function f() {} }

请教一个问题,为什么此时 f 既不是一个函数也不是未定义,而是 undefined?

@chiyu-git

This comment has been minimized.

Copy link

commented Jul 2, 2019

变量对象是es3时代的标准,es5之后就已经叫词法环境了,es6之后又改动了词法环境和变量环境,现在看来有点不太合适啊,聚聚有没有打算把相关的概念更新一下

@tt905

This comment has been minimized.

Copy link

commented Jul 5, 2019

第二题改正这样:
var foo = 1;
console.log(foo);

    function foo() {
        console.log("foo");
    };
    console.log(foo);

结果打印2个1

@fesweeper

This comment has been minimized.

Copy link

commented Jul 16, 2019

博主写得非常好,拜读中看到一个typo:

其次会处理变量声明,如果如果变量名称跟已经声明的形式参数或函数相同

「如果如果」重复了

@fesweeper

This comment has been minimized.

Copy link

commented Jul 16, 2019

另外建议一些术语比如变量对象,还是直接用英文吧,这样在行文中看起来更清楚些

@BengBu-YueZhang

This comment has been minimized.

@big-show

This comment has been minimized.

Copy link

commented Aug 6, 2019

console.log(foo);

function foo(){
    console.log("foo");
}

var foo = 1;
console.log(foo);

var foo = 1;

function foo(){
    console.log("foo");
}

另外,以上两处代码得出的结论一样,说明:

同一作用域下,函数提升比变量提升得更靠前.

大家知道的微微一笑就好了:)

或许是这个原因吧,如果变量对象已经存在相同名称的属性,则完全替换这个属性

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.