zoukankan      html  css  js  c++  java
  • js 变量、函数提升 与js的预编译有关

    参考网址:http://www.codesec.net/view/178491.html

    先简单理解下作用域的概念,方便对变量与函数提升的概念的理解

    function foo() {
    var x = 1;
    if (x) {
    var x = 2;
    }
    console.log(x);
    }
    foo();// 2

    结果为2,可见js中并没有块级作用域的概念
    可以使用下面的方法创造自己的作用域,这样不会干扰到外部变量

    function foo() {
    var x = 1;
    if (x) {
    (function() {var x = 2;
    }());
    }
    console.log(x);
    }
    foo();// 1

    结果为1,可见js中的作用域是以函数为边界的

    1.变量提升:

    变量提升与js的预编译有关,下面通过例子辅助说明

    var a = 100;
    var b = 200;
    function foo(){
    console.log(a);// undefined
    a = 10;
    console.log(a);// 10
    var a = 1;
    console.log(a);// 1
    console.log(b);// 200
    } 
    foo();

    js预编译时会先在当前作用域中找到var声明的变量分配空间,赋值为undefined,如果找不到就会到下一级作用域中找

    上面的代码的等价代码如下:

    var a = 100;
    var b = 200;
    function foo(){
    var a;
    console.log(a);// undefined
    a = 10;
    console.log(a);// 10
    a = 1;
    console.log(a);// 1
    console.log(b);// 200
    } 
    foo();

    这样看是不是容易理解多了。第一行var声明了a,但是没有赋值,因此为undefined,下面打印10、1也就顺理成章了。

    至于变量b,它在当前作用域中找不到,因此需要到外层作用域中找,在window下找到了变量b,可以看到它的值为200

    2.函数提升

    首先要明确两点:

    <1> 只有函数声明才会进行函数提升

    <2> 函数提升会将函数体一起提升上去,这点与变量提升有所不同

    下面来证明函数表达式不能进行函数提升:

    ~function() {
    alert(typeof next); // undefined
    ~function next() {
    alert(typeof next); // function
    }()
    }()

    函数前面加个~的目的是将函数声明变成函数表达式,实际上也可以加其它运算符,比如+,-,!等,总之这个函数声明被变成了函数表达式。
    从打印结果来看第一个alert出的是undefined,说明next根本没有发生函数提升。

    下面来接着验证:

    a();// 123
    var a = function(){
    console.log(321);
    }
    a();// 321
    function a(){
    console.log(123);
    }

    从结果可以看出,先打印出来的反而是放在后面的a(),上面代码的等价表示如下:

    var a = function a(){
    console.log(123);
    }
    a();
    a = function(){
    console.log(321);
    }
    a();

    那么如果当变量提升与函数提升同时发生的时候,哪个的优先级更高呢?我们来做个实验:

    function fn(){
    console.log(a);
    var a = 2;
    function a(){}
    console.log(a);
    }
    fn();// function a(), 2

    从打印顺序中可以看出,函数提升比变量提升优先级高,因为函数提升是将函数体整体提升,提升上去后立马赋值。等价代码如下:

    function fn(){
    var a = function(){}
    console.log(a);
    a = 2;
    console.log(a);
    }
    fn();

    下面再来几个有趣的例子:

    B = 100;
    function B(){
    B = 2;
    console.log(B);
    }
    B(); // B is not a function
    //函数提升导致的

    //////////////////// B = 100; var B = function(){ B = 2; console.log(B); } B(); // 2 //函数表达式不存在函数提升

    function change() { alert(typeof fn); // function alert(typeof foo); // undefined function fn() { alert('fn'); } var foo = function(){ alert('foo'); } var fn; } change(); //fn提升了,foo没有提升

    下面还有几个思考题:

    1.

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

    2.

    a = 10;
    (function a(){
    a = 1;
    console.log(a);// ? function b(){a = 1; .....}
    })();

    这段代码难以理解,测试代码为:

    var a = 10;
    var b = 20;
    (function b(){
    a = 1;
    b = 2;
    console.log(a);//
    console.log(b);
    })();
    
    console.log(a);
    console.log(b);

    网上有一段解释是这样的(这样的代码太难理解,最好还是函数和变量不要同名):

    感觉楼主的理解还不够深入,正确理解应该是经过以下过程:
    
    当进入执行上下文(代码执行之前)时,VO(变量对象)里已经包含了下列属性:
    
    函数的所有形参(如果我们是在函数执行上下文中)
    
    — 由名称和对应值组成的一个变量对象的属性被创建;没有传递对应参数的话,那么由名称和undefined值组成的一种变量对象的属性也将被创建。
    
    所有函数声明(FunctionDeclaration, FD)
    
    —由名称和对应值(函数对象(function-object))组成一个变量对象的属性被创建;如果变量对象已经存在相同名称的属性,则完全替换这个属性。
    
    所有变量声明(var, VariableDeclaration)
    
    — 由名称和对应值(undefined)组成一个变量对象的属性被创建;如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性。

    3.

    function a(i) { 
    console.log(i);// ? 10 
    var i = 1; 
    console.log(i);// ? 1
    }; 
    a(10); 

     代码分析如下:

    function a(i) { 
    var i;
    i = i ; //i是传进来的值 console.log(i);
    // ? 10 i = 1; console.log(i);// ? 1 }; a(10);
  • 相关阅读:
    禁止页面全选复制IE,Opera,Mozilla Firefox,Google Chrome,Safari,Flock等主流浏览器测试成功
    Create virtual keyboard using C# Winform Application
    C# 获取Windows语言类型(两种方式)
    Javascript在ASP.NET中的用法:计算还剩余输入多少个字符
    IE和firefox通用的复制到剪贴板的JS函数,Opera测试不成功!
    什么是数据的表分区(文章附上Server 2005分区实施方案)
    JavaScript创建的可编辑表格
    关于ASP.NET页面打印技术的总结
    错误:该行已经属于另一个表
    安装IE7后测试IE6环境的解决办法_IE6Standalone
  • 原文地址:https://www.cnblogs.com/gavinyyb/p/6702875.html
Copyright © 2011-2022 走看看