2014-11-04 136 views
2

我对Javascript中变量提升有疑问。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”的属性,因此该语句将被忽略。

因此typeof myName应该得到返回功能(而不是字符串)

请让我知道我的理解是不正确。

回答

1

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

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

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

最后,您的样品也不过是这样的:

var x = 23; 
x = 'foo'; 

这也能发挥作用,x'foo',其类型将是string。与您的示例唯一的区别在于,在您的示例中,涉及到function类型的值。

-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' 
+0

您从一个函数声明更改为函数表达式在您的示例中,并且 - 不幸的是 - 它们被JavaScript区别对待:在加载函数声明时扫描文件,函数表达式及其赋值在运行时得到解决。因此,不幸的是你的例子解释了一些事情,但没有解释问题。 – 2014-11-04 10:38:50

+0

@GoloRoden - 我已经解释了为什么'myName'变量的类型是'string'而不是'function',接下来我做了一个例子,其中变量的类型是'function' ;-) – 2014-11-04 13:20:06

-1

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

真正发生的并不是“提升”。真正发生的是JavaScript以两个阶段执行代码:编译阶段和eval阶段。 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. 在compliation阶段,解释器会看到你声明一个函数。它还注意到函数名称会隐藏变量名称。所以它创建一个函数“myName”(这意味着此时变量myName指向该函数)。

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

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

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

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

请注意,如果您删除字符串赋值,然后myName将typeof运算“功能”。那是因为在这种情况下,分配给它的最后一件事是声明的功能。

参见造成执行的两个阶段其他微妙之处此相关的问题:JavaScript function declaration and evaluation order

+1

我不'你认为你的解释是正确的。 “提升”是一种语言功能,虽然标准没有使用这个词,但程序是精确记录的 - 请参阅“声明绑定实例化”http://ecma-international.org/ecma-262/5.1/#sec -10.5 – georg 2014-11-04 07:55:38

0

除了其他的答案更要注意的是,如果你申报你的函数以下列方式:

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

或者干脆

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

而不是在 “功能MYNAME。” 语法,然后typeof运算MYNAME将返回“功能“

0

2年过去了,但也许它仍然是相关的人 你是正确的,解释的对象时,的确是这样:

  • 扫描范围内的函数声明

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

    • 对于每个找到的变量声明的背景下,创建在可变对象,它是变量名称的属性,并初始化该值作为未定义
    • 如果变量名已经存在的变量对象,什么也不做,继续扫描

但是看起来这是不是因此对于全球范围。 也就是说当我定义一个对象的输出是完全按照它应该是,当我在全球范围内定义它不是... 仍试图围绕这一个我的头