在执行上下文方面,为什么JavaScript中会出现变量提升

在执行上下文方面,为什么JavaScript中会出现变量提升,javascript,Javascript,我知道变量提升是因为执行上下文中的一些步骤。 那么,为什么在JavaScript中会出现执行上下文方面的变量提升呢 找到一些代码来调用函数 在执行函数代码之前,创建执行上下文。 初始化范围链 创建变量对象: 创建arguments对象,检查参数的上下文,初始化名称和值,并创建引用副本 扫描上下文中的函数声明: 对于找到的每个函数,在变量对象中创建一个属性,该属性是确切的函数名,它有一个指向内存中函数的引用指针 如果函数名已经存在,则引用指针值将被覆盖 对于找到的每个变量声明,在变量对象中创建一个

我知道变量提升是因为执行上下文中的一些步骤。
那么,为什么在JavaScript中会出现执行上下文方面的变量提升呢

找到一些代码来调用函数

在执行函数代码之前,创建执行上下文。 初始化范围链

创建变量对象:

创建arguments对象,检查参数的上下文,初始化名称和值,并创建引用副本

扫描上下文中的函数声明:

对于找到的每个函数,在变量对象中创建一个属性,该属性是确切的函数名,它有一个指向内存中函数的引用指针

如果函数名已经存在,则引用指针值将被覆盖

对于找到的每个变量声明,在变量对象中创建一个属性作为变量名,并将值初始化为未定义

如果变量名已存在于变量对象中,则不执行任何操作并继续扫描

确定上下文中“this”的值

在上下文中运行/解释函数代码,并在代码逐行执行时分配变量值

让我们看一个例子:

function foo(i) {
    var a = 'hello';
    var b = function privateB() {    
    };
    function c() {    
    }
}
foo(22);
On calling foo(22), the creation stage looks as follows:    
fooExecutionContext = {
    scopeChain: { ... },
    variableObject: {
        arguments: {
            0: 22,
            length: 1
        },
        i: 22,
        c: pointer to function c()
        a: undefined,
        b: undefined
    },
    this: { ... }
}
如您所见,创建阶段处理定义属性的名称,而不是为属性赋值,形式参数/参数除外

创建阶段完成后,执行流进入函数,函数完成执行后,激活/代码执行阶段如下所示:

fooExecutionContext = {
    scopeChain: { ... },
    variableObject: {
        arguments: {
            0: 22,
            length: 1
        },
        i: 22,
        c: pointer to function c()
        a: 'hello',
        b: pointer to function privateB()
    },
    this: { ... }
}
一句关于提升的话

您可以在网上找到许多在JavaScript中定义术语提升的资源,解释变量和函数声明被提升到其函数范围的顶部。但是,没有人能详细解释为什么会发生这种情况,并且有了关于解释器如何创建激活对象的新知识,很容易理解为什么会发生这种情况。以下面的代码示例为例:

​(function() {

    console.log(typeof foo); // function pointer
    console.log(typeof bar); // undefined

    var foo = 'hello',
        bar = function() {
            return 'world';
        };

    function foo() {
        return 'hello';
    }

}());​
我们现在可以回答的问题是:

为什么我们可以在声明foo之前访问它? 如果我们遵循创建阶段,我们知道在激活/代码执行阶段之前已经创建了变量。因此,当函数流开始执行时,已经在激活对象中定义了foo。 Foo声明了两次,为什么Foo显示为函数而不是未定义或字符串

尽管foo声明了两次,但我们从创建阶段就知道,函数是在变量之前在激活对象上创建的,如果属性名称已经存在于激活对象上,我们只需绕过减速

因此,首先在激活对象上创建对函数foo()的引用,当我们获取解释器并获取var foo时,我们已经看到属性名foo存在,因此代码不做任何操作并继续。 为什么酒吧没有定义

bar实际上是一个具有函数赋值的变量,我们知道这些变量是在创建阶段创建的,但它们是用未定义的值初始化的


这是语法的一部分,这就是它如何工作的原因。是的,这就是Javascript设计的方式。。或者你可以问Brendan.虽然这个问题是有效的(据我所知),但几乎只有JavaScript的创建者Brendan Eich才能回答这个问题。或者是从事语言规范工作的人。但我不相信它们经常出现堆栈溢出。如果你只是问它是如何工作的,那是另一个故事。你应该更清楚地说明,整个答案都是复制粘贴而来的。我认为这是他问的问题的完整解决方案,所以我做了这个,但如果你这么说,我会做的。谢谢。我认为@Akhilesh是对的。