zoukankan      html  css  js  c++  java
  • JS 作用域与变量提升---JS 学习笔记(三)

    你知道下面的JavaScript代码执行时会输出什么吗?

    var foo = 1;
    function bar() {
        if (!foo) {
            var foo = 10;
        }
        console.log(foo);
    }
    bar();

    答案是“10”,吃惊吗?那么下面的可能会真的让你大吃一惊:

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

    答案是 “1”。为什么会这样呢,这就涉及到 JS 里面的作用域、作用域链和提升的相关知识了。

    首先要明白 作用域和作用域链的内容(点击阅读),现在主要介绍提升。

    在 JavaScript 中,当遇到 var a = 1; 这个语句时,我们可能会这么认为,“为一个变量分配内存,给这个变量命名为 a,再把 1 保存进去”。然而这个过程并不完全正确。当编译器遇到 var a = 1 时,会做以下两个步骤:

    1. 遇到 var a ,首先会先看看当前的作用域中是否已经有 a,若有,就不再声明 a,若没有,就会在当前的作用域,创建一个 a

    2. 然后处理 a = 1 。先查看当前作用域,是否有 a 。如果有,就把 1 赋值给 a 。如果没有,就向上一个作用域中寻找 a,直到寻找到全局作用域。全局作用域中如果还没有,就会抛出异常。

    所以,当我们看到 var a = 1; 会认为这是一个声明,实际上这是两个声明, var a 和 a = 1 。第一个声明会在编译阶段进行,第二个声明会在原地等待执行。函数声明和变量声明总会被 JavaScript 的编译器提升到他们所在作用域的顶部。有了这些知识就可以解释上面的代码了

    第一段代码实际上如下图:在遇到并执行 bar()函数时,执行到 if 语句里面的 foo,此时会先查询 bar()函数的作用域内有没有声明 foo:

    若没有声明,就像上一个作用域中寻找 foo 有没有被声明。

    若声明了,就直接将声明提升到 bar 作用域里的顶部(foo = 10 留在原地按顺序等待执行),这样,foo 就是 undefined,!foo 就是 true,可以进入 if 循环。

    第二段代码实际上如下图:执行 b()时,首先就是 a = 10;这条语句,执行这条语句之前,先看 a 在 b 中是否被声明,若没有被声明就向上一个作用域中寻找 a ,现在的情况是,在 b 函数内部,a 以函数声明的方式,被声明了,那么就要把这个 a 函数声明提升到 a 所在的作用域的顶部,再按顺序执行后面的代码。

    对于提升总结的知识点:

    1. 函数声明和变量声明都会提升,但在同一个作用域相同名字的函数声明优先于变量声明。

    2. 变量声明会提升,但变量赋值的过程不会提升,会在原地等待被执行。

    3. 提升后,赋值语句会向前覆盖提升的内容。例子 2 中,b 函数的内部,最开始 a 是函数提升,a 的本质是函数,但是函数提升后,执行了一个赋值语句:a = 10;此时,a 就是一个 number 类型的变量了。

     

    对于这种情况,我们在写 JavasScript 代码的时候该怎么做呢?

    使用单 var 模式:避免变量提升所带来的问题

    /*jslint onevar: true [...] */
    function foo(a, b, c) {
        var x = 1,
            bar,
            baz = "something";
    }

    本文参考以下资料:

    颜海镜的博客:JavaScript作用域链和提升机制

    你不知道的JavaScript

    JavaScript高阶程序设计

  • 相关阅读:
    leetcode Convert Sorted List to Binary Search Tree
    leetcode Convert Sorted Array to Binary Search Tree
    leetcode Binary Tree Level Order Traversal II
    leetcode Construct Binary Tree from Preorder and Inorder Traversal
    leetcode[105] Construct Binary Tree from Inorder and Postorder Traversal
    证明中序遍历O(n)
    leetcode Maximum Depth of Binary Tree
    限制 button 在 3 秒内不可重复点击
    HTML 和 CSS 画三角形和画多边行基本原理及实践
    在线前端 JS 或 HTML 或 CSS 编写 Demo 处 JSbin 与 jsFiddle 比较
  • 原文地址:https://www.cnblogs.com/rougan/p/10606755.html
Copyright © 2011-2022 走看看