Javascript变量提升示例

时间:2014-11-04 07:23:01

标签: javascript hoisting

我对Javascript中的变量提升有疑问。

考虑以下示例;

var myName = "Richard"; // Variable assignment (initialization)
​
​function myName () {
console.log ("Rich");
}
​
console.log(typeof myName); // string 

我真的很困惑为什么typeof myName作为字符串返回。

根据我的理解,这个例子将按以下方式进行;

  1. 首先,函数声明(function myName ())将被提升到顶部,然后
  2. JS解释器将读取行var myName = "Richard"(因为函数声明优先于变量声明)。但是,由于已存在名为“myName”的属性,因此将忽略此语句。
  3. 因此typeof myName应该以函数(而不是字符串)的形式返回

    请告诉我我的理解不正确的地方。

5 个答案:

答案 0 :(得分:1)

JavaScript具有动态类型系统,即变量类型可能随时间而变化。基本上,你写的是正确的:首先,函数声明运行(加载文件时),但是变量myName中存储的函数被字符串覆盖。

唯一被忽略的是调用var,因为变量实际上已经被声明了。

重新定义变量完全有效(这就是你在这里所做的,通过指定一个新值)。

最后,你的样本就是这样:

var x = 23;
x = 'foo';

这也可行,x将为'foo',其类型将为string。与您的样本的唯一区别在于,在您的样本中,涉及function类型的值。

答案 1 :(得分:0)

除了其他答案之外,应该注意的是,如果您按以下方式声明您的功能:

var myName = function() {
  console.log('Rich');
}

或只是

myName = function(){
  console.log('Rich')
}

而不是“function myName ...”语法,那么typeof myName将返回“function”

答案 2 :(得分:0)

2年过去了,但也许它仍然与某人有关 你是对的,在解释一个对象时确实如此:

  • 扫描上下文以获取功能声明

    • 对于找到的每个函数,在变量对象
    • 中创建一个属性
    • 如果函数名已存在,则将覆盖引用指针值
  • 扫描上下文以获取变量声明

    • 对于找到的每个变量声明,在变量对象中创建一个属性作为变量名称,并将值初始化为undefined
    • 如果变量名称中已存在变量名称,则不执行任何操作并继续扫描

然而,就全球范围而言,这似乎并非如此。 即当我定义一个对象时,输出完全是应该的,当我在全局范围内定义它时,它不是...... 还是试着绕着这个人开始。

答案 3 :(得分:-1)

由于Hoisting您的变量和函数定义被移到顶部,因此您拥有:

var myName;
// moved to top
function myName () {
  console.log ("Rich");
}

// next your code
myName = "Richard";

console.log(typeof myName); // string 

如果您重写代码如下:

var myName = "Richard"; // Variable assignment (initialization)
​
myName = ​function () {  // Variable redefinition
  console.log ("Rich");
}
​
console.log(typeof myName); // function

您的myName变量现在是一个函数,因为只有myName变量为hoisted

var myName;

myName = "Richard";     // Variable assignment (initialization)
myName = ​function () {  // Variable redefinition
  console.log ("Rich");
}
​
console.log(typeof myName); // outputs 'function'

答案 4 :(得分:-1)

"吊装"的想法是一种了解正在发生的事情的坏方法。换句话说,在我看来"吊装"对吊装来说是一个糟糕的解释。

真正发生的事情不是"吊装"。真正发生的是javascript在两个阶段执行代码:编译阶段和eval阶段。 javascript社区称之为"吊装"的症状。但是大多数人都不明白为什么要提升升降机,因为他们认为javascript解释器有这个功能叫做#34;吊装" (他们不会)。

实际发生的事情比起吊的想法更容易解释。规则是:

  1. Javascript总是从上到下解析代码。它从不重新排序代码(它从不提升)。

  2. 执行分为两个阶段:编译和评估。

  3. 所有声明都在编译阶段处理,在编译阶段不会评估任何表达式(因为"评估"事情在评估阶段完成)。

  4. 所有表达式和其他需要评估的内容都将在评估阶段进行处理。

  5. 记住规则1,所有解析都是自上而下完成的,没有回溯,也没有提升。

    让我们举个例子,并通过记住javascript的编译和评估阶段来尝试理解它:

        var myName = "Richard"; // Variable assignment (initialization)
    ​    
     ​   function myName () {
           console.log ("Rich");
        }
    
    ​    console.log(typeof myName); // string 
    
    1. 在编译阶段,解释器会看到您声明一个变量。它为此变量分配一个内存区域,并为其赋值undefined

    2. 在compliation阶段,解释器会看到您声明一个函数。它还注意到函数名称隐藏变量名称。所以它创建了一个函数" myName" (这意味着此时变量myName指向函数)。

    3. 编译阶段结束。现在我们进入评估阶段。

    4. 在评估阶段,口译员会看到您将字符串分配给myName

    5. 当我们到达函数声明时没有什么要评估的,因为声明是在编译阶段处理的。

    6. 在评估阶段,解释程序会向您发送控制台。记录myName的类型。由于分配给它的最后一件事是一个字符串,它打印"字符串"。

    7. 请注意,如果删除字符串分配,则myName将为typeof" function"。那是因为在这种情况下,分配给它的最后一件事是声明的函数。

      请参阅此相关问题,了解由执行的两个阶段引起的其他细微差别:JavaScript function declaration and evaluation order