博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入理解javascript作用域系列第三篇——声明提升(hoisting)
阅读量:6944 次
发布时间:2019-06-27

本文共 2369 字,大约阅读时间需要 7 分钟。

前面的话

  一般认为,javascript代码在执行时是由上到下一行一行执行的。但实际上这并不完全正确,主要是因为声明提升的存在。本文是深入理解javascript作用域系列第三篇——声明提升(hoisting)

 

变量声明提升

a = 2 ;var a;console.log( a );

  直觉上,会认为是undefined,因为var a声明在a = 2;之后,可能变量被重新赋值了,因为会被赋予默认值undefined。但是,真正的输出结果是2

console.log( a ) ;var a  =  2 ;

  鉴于上面的特点,可能会认为这个代码片段也会同样输出2。但,真正的输出结果是undefined

  所有这些和观感相违背的原因是在于编译器的编译过程

  介绍过作用域的内部原理。引擎会在解释javascript代码之前首先对其进行编译。编译阶段中的一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来

  包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理

var a = 2 ;

  这个代码片段实际上包括两个操作:var a 和 a = 2 

  第一个定义声明是在编译阶段由编译器进行的。第二个赋值操作会被留在原地等待引擎在执行阶段执行

//对变量a的声明提升到最上面后,再执行代码时,控制台输出2var a;a = 2 ;console.log(a);

  声明从它们在代码中出现的位置被“移动”到了最上面,这个过程就叫作提升(hoisting)

  [注意]每个作用域都会进行提升操作

console.log(a);var a = 0;function fn(){    console.log(b);    var b = 1;    function test(){        console.log(c);        var c = 2;    }    test();}fn();
//变量声明提升后,变成下面这样var a ;console.log(a);a = 0;function fn(){    var b;    console.log(b);    b = 1;    function test(){        var c ;        console.log(c);        c = 2;    }    test();}fn();

 

函数声明提升

  声明包括两种:变量声明和函数声明。不仅变量声明可以提升,函数声明也有提升操作

foo();function foo(){    console.log(1);//1}

  上面这个代码片段之所以能够在控制台输出1,就是因为foo()函数声明进行了提升,如下所示:

function foo(){    console.log(1);}foo();

  函数声明会提升,但函数表达式却不会提升 

foo();var foo = function(){    console.log(1);//TypeError: foo is not a function}

  上面这段程序中的变量标识符foo被提升并分配给全局作用域,因此foo()不会导致ReferenceError。但是foo此时并没有赋值,foo()由于对undefined值进行函数调用而导致非法操作,因此会抛出TypeError异常

//变量提升后,代码如下所示:var foo;foo();foo = function(){    console.log(1);}

  即使是具名的函数表达式也无法被提升

foo();//TypeError: foo is not a functionvar foo = function bar(){      console.log(1);};
//声明提升后,代码变为:var foo;foo();//TypeError: foo is not a functionfoo = function bar(){      console.log(1);};

  [注意]函数表达式的名称只能在函数体内部使用,而不能在函数体外部使用

var bar;var foo = function bar(){    console.log(1);};bar();//TypeError: bar is not a function

 

函数覆盖

  函数声明和变量声明都会被提升。但是,函数声明会覆盖变量声明

var a;function a(){}console.log(a);//'function a(){}'

  但是,如果变量存在赋值操作,则最终的值为变量的值

var a=1;function a(){}console.log(a);//1
var a;function a(){};console.log(a);//'function a(){}'a = 1;console.log(a);//1

  [注意]变量的重复声明是无用的,但函数的重复声明会覆盖前面的声明(无论是变量还是函数声明)

  【1】变量的重复声明无用

var a = 1;var a;console.log(a);//1

  【2】由于函数声明提升优先于变量声明提升,所以变量的声明无作用

var a;function a(){    console.log(1);}a();//1

  【3】后面的函数声明会覆盖前面的函数声明

a();//2function a(){    console.log(1);}function a(){    console.log(2);}

  所以,应该避免在同一作用域中重复声明

转载地址:http://otanl.baihongyu.com/

你可能感兴趣的文章
hdu 5437 Alisha’s Party 优先队列
查看>>
【PHP】PHP获得第一章
查看>>
nslookup
查看>>
java05
查看>>
Android UI ActionBar功能-在 Action Bar 上添加按钮
查看>>
每天一个linux命令(10):cat 命令
查看>>
android ScrollView中嵌套listview listview可点击处理,可展开
查看>>
感谢dudu和他的博客园团队
查看>>
一个由proguard与fastJson引起的血案(转)
查看>>
clearing & settlement
查看>>
Lingo 做线性规划 - DEA
查看>>
Axure 全局辅助线(转)
查看>>
Delphi 7下使用VT实现树型列表结合控件
查看>>
【LINUX】——如何配置宿主机和虚拟机IP在同一网段
查看>>
工作介绍xml书包文件
查看>>
POJ 3450 Corporate Identity KMP解决问题的方法
查看>>
js原生设计模式——9外观模式封装2(小型代码库YJ)
查看>>
Sybase常用函数
查看>>
***apache做301重定向的方法
查看>>
关于线上测试环境的思考
查看>>