javascript中变量声明提升(Hoisting)

JavaScript 会提升变量声明。这意味着 var 表达式和 function 声明都将会被提升到当前作用域的顶部。

bar();
var bar = function() {};
var someValue = 42;

test();
function test(data) {
    if (false) {
        goo = 1;

    } else {
        var goo = 2;
    }
    for(var i = 0; i < 100; i++) {
        var e = data[i];
    }
}

上面代码在运行之前将会被转化。JavaScript 将会把 var 表达式和 function 声明提升到当前作用域的顶部。

// var 表达式被移动到这里
var bar, someValue; // 缺省值是 'undefined'

// 函数声明也会提升
function test(data) {
    var goo, i, e; // 没有块级作用域,这些变量被移动到函数顶部
    if (false) {
        goo = 1;

    } else {
        goo = 2;
    }
    for(i = 0; i < 100; i++) {
        e = data[i];
    }
}

bar(); // 出错:TypeError,因为 bar 依然是 'undefined'
someValue = 42; // 赋值语句不会被提升规则(hoisting)影响
bar = function() {};

test();

 

主意test函数中的goo=1变量, 第一次出现的时候,并没有使用var,在我们的理解中,foo被隐式的声明成了全局变量,

但是 在后面又出现了一个 var goo=2,声明了是一个局部的变量,根据变量提升的规则,

var goo会被提升到顶部, var goo = 'undefined' 

所以 goo是一个局部变量。

 

// 来自 Nettuts+ 的一段代码,生动的阐述了 JavaScript 中变量声明提升规则
var myvar = 'my value';  

(function() {  
    alert(myvar); // undefined  
    var myvar = 'local value';  
})();  

 这一段代码说明了很多问题。

var myvar ='my value';  

(function(){  
  var myvar = undefined // 变量声明被提升到了这个位置。
    alert
(myvar);// undefined  
   
var myvar ='local value';  
})();


在《悟透Javascript》里有这样一个例子
var myFunc = function(){
     alert('Hello');       
}

myFunc(); // 输出Hello

myFunc = function(){
    alert('yeah');
}

myFunc();  第二次调用输出 yeah

这没什么好奇怪的。 然后我们再看下面一段代码

function myFunc(){
   alert('Hello');
}

myFunc(); // 第一次调用 输出yeah;很奇怪吧

function myFunc(){
   alert('yeah');
}

myFunc(); // 还是输出 yeah!



这里面还是变量申明别提前的原因,不做多解释

 引用书中原话

 原来,JavaScript 执行引擎并非一行一行地分析和执行程序,而是一段一段地分析执行的。而且,在
同一段程序的分析执行中,定义式的函数语句会被提取出来优先执行。函数定义执行完之后,才会按顺序
执行其他语句代码。也就是说,在第一次调用 myfunc之前,第一个函数语句定义的代码逻辑,已被第二
个函数定义语句覆盖了。所以,两次都调用都是执行最后一个函数逻辑了。
 
     如果把这个 JavaScript 代码分成两段,例如将它们写在一个html中,并用<script/> 标签将其分成
这样的两块

< script >  
     function myfunc () 
    { 
        alert("hello"); 
    }; 
    myfunc();  // 这里调用 myfunc,输出 hello 
</script >
< script >  
     function myfunc () 
    { 
        alert("yeah"); 
    };     
    myfunc();  // 这里调用 myfunc,输出 yeah 
</script >  

 




所以总结如下:

名称解析顺序

JavaScript 中的所有作用域,包括全局作用域,都有一个特别的名称 this 指向当前对象。

函数作用域内也有默认的变量 arguments,其中包含了传递到函数中的参数。

比如,当访问函数内的 foo 变量时,JavaScript 会按照下面顺序查找:

  1. 当前作用域内是否有 var foo 的定义。
  2. 函数形式参数是否有使用 foo 名称的。
  3. 函数自身是否叫做 foo
  4. 回溯到上一级作用域,然后从 #1 重新开始。
 http://bonsaiden.github.io/JavaScript-Garden/zh/#core.eval

 

 

 

 

posted on 2013-05-16 15:11  专注前端  阅读(494)  评论(0编辑  收藏  举报

导航