zoukankan      html  css  js  c++  java
  • JavaScript中变量提升------Hoisting

    原谅链接:http://www.cnblogs.com/damonlan/archive/2012/07/01/2553425.html

    因为这个问题很是经典,而且容易出错,所以在介绍一次。哈哈。莫怪哦。

    一。案发现场

    我们先看一段很简单的代码:

    var v='Hello World';
    alert(v);

     这个没有疑问吧,弹出“Hello World”。OK,我们继续。

    我们在看一段Code:

    var v='Hello World';
    (function(){
        alert(v);
    })()

    经过运行之后,我们发现,还是和我们预期的一样,弹出了“Hello World”。

    好了,有意思的来了。接着在看一段下面的代码:

    var v='Hello World';
    (function(){
        alert(v);
        var v='I love you';
    })()

    如果这个是一个面试题,面试官问你这个结果是多少?你怎么回答?

    我们先看结果吧!

    结果是 undefined?和你上面自己想的一样吗?

    好吧,我就不故弄玄虚了。其实,这里面隐藏了一个陷阱-----JavaScript中的变量提升(Hoisting);

    二。深度剖析

    现在我来解释下提升是什么意思?顾名思义,就是把下面的东西提到上面。在JS中,就是把定义在后面的东东(变量或函数)提升到前面中定义。

    在解释提升之前,我们先来看一下js中的作用域(scoping)问题。

    对于JavaScript新手来说scoping是最令人困惑的部分之一。事实上,不仅仅是新手,我遇到或很多有经验的JavaScript程序员也不能完全理解scoping。JavaScript的scoping如此复杂的原因是它看上去非常像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
    ", x); // 1
    }
    复制代码

    这段程序的输出是1,2,1。这是因为在C系语言有块级作用域(block-level scope),当进入到一个块时,就像if语句,在这个块级作用域中会声明新的变量,这些变量不会影响到外部作用域。但是JavaScript却不是这样。在Firebug中试试下面的代码:

    复制代码
     var x = 1;
        console.log(x); // 1
     if (true) {
       var x = 2;
       console.log(x); //2
    }
     console.log(x);// 2
    复制代码

    在这段代码中,Firebug显示1,2,2。这是因为JavaScript是函数级作用域(function-level scope)。这和C系语言是完全不同的。块,就像if语句,并不会创建一个新的作用域。只有函数才会创建新的作用域。

    对于大部分熟悉C,C++,C#或是Java的程序员来说,这是意料之外并且不被待见的。幸运的是,因为JavaScript函数的灵活性,对于这个问题我们有一个解决方案。如果你必须在函数中创建一个临时的作用域,请像下面这样做:

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

    这种方面确实非常灵活,它使用在任何需要创建一个临时作用域的地方,不仅仅是某个块中。但是,我强烈建议你花点时间好好理解下JavaScript scoping。它实在是非常强力,而且它也是我最喜欢的语言特性之一。如果你很好的理解了scoping,理解hoisting将会更加容易。

    2.1变量提升

    变量提升,很简单,就是把变量提升提到函数的top的地方。我么需要说明的是,变量提升 只是提升变量的声明,并不会把赋值也提升上来。

    比如:

    我们定义三个变量:

    (function(){
        var a='One';
        var b='Two';
        var c='Three';
    })()

    实际上它是这样子的:

    复制代码
    (function(){
        var a,b,c;
        a='One';
        b='Two';
        c='Three';
    })()
    复制代码

    这个时候就把变量提升了呀。

    好,我们现在回到第一段code里面。为什么会报错呢?其实,根据我么根据上面变量提升原件以及js的作用域(块级作用域)的分析,得知 上面代码真正变成如下:

    复制代码
    var v='Hello World';
    (function(){
        var v;
        alert(v);
        v='I love you';
    })()
    复制代码

    所以,才会提示说“undefined”。

    从这里,我们也学习到,我们在写js code 的时候,我么需要把变量放在函数级作用域的顶端,比如我在上面所举的例子:var a,b,c;。以防止出现意外。

    2.2 函数提升

    函数提升是把整个函数都提到前面去。

    在我们写js code 的时候,我们有2中写法,一种是函数表达式,另外一种是函数声明方式。我们需要重点注意的是,只有函数声明形式才能被提升。

    函数声明方式提升【成功】

    复制代码
    function myTest(){
        foo();
        function foo(){
            alert("我来自 foo");
        }
    }
    myTest();
    复制代码

    函数表达式方式提升【失败】

    复制代码
    function myTest(){
        foo();
       var foo =function foo(){
            alert("我来自 foo");
        }
    }
    myTest();
    复制代码

    结果如下:

    左边报错了。没骗你。

    应该到这里基本都可以弄懂了。~

  • 相关阅读:
    基于jQuery的自定义插件:实现整屏分页转换的功能
    蝶恋花
    js中面向对象编程
    移动端web页面列表类上拉加载,查看详情,iframe嵌套第三方页面遇到的问题以及解决办法
    控制使用jquery load()方法载入新页面中的元素
    bootstrap-daterangepicker双日历控件开始日期选择问题
    点击select下拉框获取option的属性值
    bootstrap table表格前台分页,点击tab选项,重新刷新表格
    jquery中使元素显示和隐藏方法之间的区别
    jquery对象和DOM对象的相互转换
  • 原文地址:https://www.cnblogs.com/gavinyyb/p/6277251.html
Copyright © 2011-2022 走看看