javascript代码实例教程-Javascript 作用域和变量提升

发布时间:2019-04-10 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了javascript代码实例教程-Javascript 作用域和变量提升脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
小宝典致力于为广大程序猿(媛)提供高品质的代码服务,请大家多多光顾小站,小宝典在此谢过。

下面的程序是什么结果?

 VAR foo = 1; 
function bar() { 
    if (!foo) { 
        var foo = 10; 
    } 
    alert(foo); 

bar(); 

结果是10;

 

那么下面这个呢?

 var a = 1; 
function b() { 
    a = 10; 
    return; 
    function a() {} 

b(); 
alert(a); 

结果是1.

 

吓你一跳吧?发生了什么事情?这可能是陌生的,危险的,迷惑的,同样事实上也是非常有用和印象深刻的javascript语言特性。对于这种表现行为,我不知道有没有一个标准的称呼,但是我喜欢这个语:“Hoisting (变量提升)”。这篇文章将对这种机制做一个抛砖引玉式的讲解,但是,首先让我们对javascript的作用域有一些必要的理解。

Javascript的作用域
对于Javascript初学者来说,一个最迷惑的地方就是作用域;事实上,不光是初学者。我就见过一些有经验的javascript程序员,但他们对scoPE理解不深。javascript作用域之所以迷惑,是因为它程序语法本身长的像C家族的语言,像下面的c程序

 
#include <stdio.h> 
int main() { 
    int x = 1; 
    PRintf("%d, ", x); // 1 
    if (1) { 
        int x = 2; 
        printf("%d, ", x); // 2 
    } 
    printf("%d/n", x); // 1 

输出结果是1 2 1,这是因为C家族的语言有块作用域,当程序控制走进一个块,比如if块,只作用于该块的变量可以被声明,而不会影响块外面的作用域。但是在Javascript里面,这样不行。看看下面的代码:

 
var x = 1; 
console.LOG(x); // 1 
if (true) { 
    var x = 2; 
    console.log(x); // 2 

console.log(x); // 2 

结果会是1 2 2。因为javascript是函数作用域。这是和c家族语言最大的不同。该程序里面的if并不会创建新的作用域。

 

对于很多C,c++,java程序员来说,这不是他们期望和欢迎的。幸运的是,基于javascript函数的灵活性,这里有可变通的地方。如果你必须创建临时的作用域,可以像下面这样:

 
function foo() { 
    var x = 1; 
    if (x) { 
        (function () { 
            var x = 2; 
            // some other code 
        }()); 
    } 
    // x is still 1. 

这种方法很灵活,可以用在任何你想创建临时的作用域的地方。不光是块内。但是,我强烈推荐你花点时间理解javascript的作用域。它很有用,是我最喜欢的javascript特性之一。如果你理解了作用域,那么变量提升就对你显得更有意义。

 

变量声明,命名,和提升
在javascript,变量有4种基本方式进入作用域:

1 语言内置:所有的作用域里都有thisarguments;(译者注:经过测试arguments在全局作用域是不可见的)
2 形式参数:函数的形式参数会作为函数体作用域的一部分;
3 函数声明:像这种形式:function foo(){};
4 变量声明:像这样:var foo;
函数声明和变量声明总是会被解释器悄悄地被“提升”到方法体的最顶部。这个意思是,像下面的代码:

 
function foo() { 
    bar(); 
    var x = 1; 

实际上会被解释成:

 
function foo() { 
    var x; 
    bar(); 
    x = 1; 

无论定义该变量的块是否能被执行。下面的两个函数实际上是一回事:

 
function foo() { 
    if (false) { 
        var x = 1; 
    } 
    return; 
    var y = 1; 

function foo() { 
    var x, y; 
    if (false) { 
        x = 1; 
    } 
    return; 
    y = 1; 

请注意,变量赋值并没有被提升,只是声明被提升了。但是,函数的声明有点不一样,函数体也会一同被提升。但是请注意,函数的声明有两种方式:

 
function test() { 
    foo(); // TypeError "foo is not a function" 
    bar(); // "this will run!" 
    var foo = function () { // 变量指向函数表达式 
        alert("this won't run!"); 
    } 
    function bar() { // 函数声明 函数名为bar 
        alert("this will run!"); 
    } 

test(); 

这个例子里面,只有函数式的声明才会连同函数体一起被提升。foo的声明会被提升,但是它指向的函数体只会在执行的时候才被赋值。

 

上面的东西涵盖了提升的一些基本知识,它们看起来也没有那么迷惑。但是,在一些特殊场景,还是有一定的复杂度的。

变量解析顺序
最需要牢记在心的是变量解析顺序。记得我前面给出的命名进入作用域的4种方式吗?变量解析的顺序就是我列出来的顺序。一般来说,如果一个名称已经被定义,则不会被其他相同名称的属性覆盖。这是说,(译者没理解这句,所以先做删除样式) 函数的声明比变量的声明具有高的优先级。这并不是说给那个变量赋值不管用,而是声明不会被忽略了。 (译者注: 关于函数的声明比变量的声明具有高的优先级,下面的程序能帮助你理解)

 
<script> 
function a(){    

var a; 
alert(a);//打印出a的函数体 
</script> 
 
<script> 
 
var a; 
function a(){    

alert(a);//打印出a的函数体 
</script> 
//但是要注意区分和下面两个写法的区别: 
<script> 
var a=1; 
function a(){    

alert(a);//打印出1 
</script> 
 
<script> 
function a(){    

 
var a=1; 
 
alert(a);//打印出1 
</script> 


这里有3个例外:
1 内置的名称arguments表现得很奇怪,他看起来应该是声明在函数形式参数之后,但是却在函数声明之前。这是说,如果形参里面有arguments,它会比内置的那个有优先级。这是很不好的特性,所以要杜绝在形参里面使用arguments;
2 在任何地方定义this变量都会出语法错误,这是个好特性;
3 如果多个形式参数拥有相同的名称,最后的那个具有优先级,即便实际运行的时候它的值是undefined;

 

命名函数
你可以给一个函数一个名字。如果这样的话,它就不是一个函数声明,同时,函数体定义里面的指定的函数名( 如果有的话,如下面的sPAM, 译者注)将不会被提升, 而是被忽略。这里一些代码帮助你理解:

 
foo(); // TypeError "foo is not a function" 
bar(); // valid 
baz(); // TypeError "baz is not a function" 
spam(); // ReferenceError "spam is not defined" 
 
var foo = function () {}; // foo指向匿名函数 
function bar() {}; // 函数声明 
var baz = function spam() {}; // 命名函数,只有baz被提升,spam不会被提升。 
 
foo(); // valid 
bar(); // valid 
baz(); // valid 
spam(); // ReferenceError "spam is not defined" 

 

怎么写代码
现在你理解了作用域和变量提升,那么这对于javascript编码意味着什么?最重要一点是,总是用var定义你的变量。而且我强烈推荐,对于一个名称,在一个作用域里面永远只有一次var声明。如果你这么做,你就不会遇到作用域和变量提升问题。

语言规范怎么说
我发现ECMAScript参考文档总是很有用。下面是我找到的关于作用域和变量提升的部分:
如果变量在函数体类声明,则它是函数作用域。否则,它是全局作用域(作为global的属性)。变量将会在执行进入作用域的时候被创建。块不会定义新的作用域,只有函数声明和程序(译者以为,就是全局性质的代码执行)才会创造新的作用域。变量在创建的时候会被初始化为undefined。如果变量声明语句里面带有赋值操作,则赋值操作只有被执行到的时候才会发生,而不是创建的时候。

我期待这篇文章会对那些对javascript比较迷惑的程序员带来一丝光明。我自己也尽最大的可能去避免带来更多的迷惑。如果我说错了什么,或者忽略了什么,请告知。

 

觉得可用,就经常来吧! 脚本宝典 欢迎评论哦! js脚本,巧夺天工,精雕玉琢。小宝典献丑了!

脚本宝典总结

以上是脚本宝典为你收集整理的javascript代码实例教程-Javascript 作用域和变量提升全部内容,希望文章能够帮你解决javascript代码实例教程-Javascript 作用域和变量提升所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。