2

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

考虑以下示例:​</p>

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

我实际上很困惑为什么typeof myName返回为string

根据我的理解,该示例将按如下方式进行;

  1. 首先,函数声明 ( function myName ()) 将被提升到顶部,然后
  2. JS 解释器将读取该行var myName = "Richard"(因为函数声明优先于变量声明)。但是,由于已经有一个名为“myName”的属性,因此该语句将被忽略。

因此typeof myName应该作为函数(而不是字符串)返回。

我的理解哪里不对?

4

5 回答 5

1

JavaScript 有一个动态类型系统,即变量的类型可以随时间改变。基本上,您写的内容是正确的:首先,函数声明开始运行(在加载文件时),但随后存储在变量中的函数myName被字符串覆盖。

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

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

最后,您的样本不过是这样:

var x = 23;
x = 'foo';

这也将起作用,x将是'foo',并且它的类型将是string。您的样本的唯一区别是,在您的样本中,function涉及类型值。

于 2014-11-04T07:24:59.590 回答
0

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

  • 扫描函数声明的上下文

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

    • 对于找到的每个变量声明,在变量对象中创建一个属性,即变量名,并将值初始化为未定义
    • 如果变量名已经存在于变量对象中,什么都不做,继续扫描

但是,对于全球范围而言,情况似乎并非如此。即,当我定义一个对象时,输出完全符合它应该是的,当我在全局范围内定义相同时,它不是......仍然试图围绕这个

于 2016-09-17T12:06:22.253 回答
0

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

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

或者干脆

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

与“function myName ...”语法相反,typeof myName 将返回“function”

于 2015-08-27T21:17:27.240 回答
-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'
于 2014-11-04T07:36:05.830 回答
-1

“提升”的想法是了解正在发生的事情的不好方法。换句话说,在我看来,“吊装”是对吊装的不好解释。

真正发生的不是“吊装”。真正发生的是javascript分两个阶段执行代码:编译阶段和评估阶段。javascript 社区将这种症状称为“提升”,但大多数人无法理解为什么要提升提升,因为他们认为 javascript 解释器具有称为“提升”的功能(他们没有)。

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

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

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

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

  4. 所有表达式和任何其他需要评估的东西都在评估阶段进行处理。

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

让我们以您的示例为例,并通过记住 javascript 的编译和评估阶段来尝试理解它:

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

​    console.log(typeof myName); // string 
  1. 在编译阶段,解释器看到你声明了一个变量。它为这个变量分配一个内存区域,并为其赋值undefined

  2. 在编译阶段,解释器看到你声明了一个函数。它还注意到函数名隐藏了变量名。因此它创建了一个函数“myName”(这意味着此时变量myName指向该函数)。

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

  4. 在评估阶段,解释器会看到您将字符串分配给myName.

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

  6. 在评估阶段,解释器看到你 console.logging typeof myName。由于分配给它的最后一个东西是一个字符串,它打印“字符串”。

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

有关由两个执行阶段引起的其他细微差别,请参阅此相关问题:JavaScript 函数声明和评估顺序

于 2014-11-04T07:47:16.533 回答