资讯专栏INFORMATION COLUMN

进击JavaScript之(一)变量声明提升

LeexMuller / 1203人阅读

摘要:如下代码输出的结果是代码执行分为两个大步预解析的过程代码的执行过程预解析与变量声明提升程序在执行过程中,会先将代码读取到内存中检查,会将所有的声明在此进行标记,所谓的标记就是让解析器知道有这个名字,后面在使用名字的时候不会出现未定义的错误。

如下代码输出的结果是?

var num = 123;
function foo1(){
    console.log( num );    //undefined
    var num = 456;
   console.log( num );    //456
}
foo1();

Javascript代码执行分为两个大步:

预解析的过程
代码的执行过程

1.预解析与变量声明提升

程序在执行过程中,会先将代码读取到内存中检查,会将所有的声明在此进行标记,所谓的标记就是让JS解析器知道有这个名字,后面在使用名字的时候不会出现未定义的错误。这个标记过程就是提升。

声明:

名字的声明,标识符声明(变量名声明)

名字的声明就是让解析器知道有这个名字

名字没有任何数据与之对应

函数的声明

函数声明包含两部分

函数声明与函数表达式有区别,函数声明是多带带写在一个结构中,不存在任何语句,逻辑判断等结构中

function f() {}
function func() { // 函数声明
} 
if ( true ) {
    function func2 () {} //函数表达式
}
var f = function func3 () {}; //函数表达式
this.sayHello = function () {}; //函数表达式
var i= 1;
function func4 () {}    // 函数声明
    var j = 2;
}

首先函数声明告诉解析器有这个名字存在,该阶段与名字声明一样
告诉解析器,这个名字对应的函数体是什么

var num = 1;
function num () {
    alert( num );
}
num();    // 报错

分析

预解析代码,提示名字

首先提升名字num

再提升函数名,但是名字已经存在,因此只做第二部,让名字与函数体对应上

结论就是 代码中已经有一个函数 num 了

开始执行代码,第一句话从赋值语句开始执行

给num赋值为1

覆盖了函数

调用num,由于num中存储的是数组1,因此报错

2.代码分析举例 程序1
var num = 123;
function foo1(){
    console.log( num );    //undefined
    var num = 456;
    console.log( num );    //456
}
foo1();

预解析,提升 num 名字和 foo1 函数

执行第一句话:num = 123;

执行函数调用

函数调用进入函数的一瞬间也要进行预解析,此时解析的是变量名 num

在函数内部是一个独立的空间,允许使用外部的数据,但是现在 num 声明同名,即覆盖外面的

执行第一句 打印num,没有数据,undefined

执行第二句 赋值:num = 456;

执行第三句 打印num,结果456

程序2
if ( ! "a" in window ) {
    var a = 123;
}
console.log( a );

首先,预解析,读取提升 a ,有一个名字 a 存在了

其次,in 运算符:判断某一个字符串描述的属性名是否在对象中

var o = { name:"jim" }; "name" in o,"age" in o

执行第一个判断:! "a" in window

"a" in window 结果为真

!得到假

if内部的赋值不进行

最后,打印结果 a 的值为 undefined

程序3
if ( false ) {
    function f1 () {
        console.log( "true" );
     }
} else {
    function f1 () {
        console.log( "false" );
     }
}
f1();

预解析:提升 f1 函数,只保留提升后的内容,所以打印是 false

执行代码,第一句话就是一个空的if结构

if ( true ) {
} else {
}

执行函数调用,得到 false

3.问题
function foo () } {}
var foo = function () {};

上面的语法是声明,可以提升,因此在函数上方也可以调用

下面的语法是函数表达式,函数名就是foo ,他会提升,提升的不是函数体

函数表达式也是支持名字语法

var foo = function func1 () {};
func();

函数有一个属性name,表示的是函数名,只有带有名字的函数定义,才会有name属性值,否则是“”

但是,函数表达式的名字,只允许在函数内部使用,IE8可以访问

()可以将数据转化为表达式

新的浏览器中,写在if、while、do..while结构中的函数,都会将函数的声明转换成特殊的函数表达式
将代码

if (...) {
    function foo () { ... }
}

转换成

if (...) {
    var foo = function foo () { .... }
}

完。

推荐阅读

进击JavaScript之(二)词法作用域与作用域链

进击JavaScript之(三)玩转闭包

进击JavaScript之(四)原型与原型链

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80050.html

相关文章

  • 进击JavaScript(五) 立即执行函数与闭包

    摘要:匿名函数是不能单独写的,所以就提不上立即执行了。六立即执行函数在闭包中的应用立即执行函数能配合闭包保存状态。来看下上节内容中闭包的例子现在,我们来利用立即执行函数来简化它第一个匿名函数执行完毕后,返回了第二个匿名函数。 前面的闭包中,提到与闭包相似的立即执行函数,感觉两者还是比较容易弄混吧,严格来说(因为犀牛书和高程对闭包的定义不同),立即执行函数并不属于闭包,它不满足闭包的三个条件。...

    vincent_xyb 评论0 收藏0
  • 进击JavaScript(三) 函数执行过程

    摘要:中没有可执行的函数了,执行完出栈。当某个函数被调用时,会创建一个执行环境及相应的作用域链。检查当前环境中的函数声明使用声明的。确定指向所以说的指向,是在函数执行时确定的。 理解js 的执行过程是很重要的,比如,作用域,作用域链,变量提升,闭包啊,要想明白这些,你就得搞懂函数执行时到底发生了什么! 一、执行环境(Execution Context)又称执行上下文 当代码执行时都会产生一个...

    netmou 评论0 收藏0
  • 进击JavaScript(二)词法作用域与作用域链

    摘要:一作用域域表示的就是范围,即作用域,就是一个名字在什么地方可以使用,什么时候不能使用。概括的说作用域就是一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量。 一、作用域 域表示的就是范围,即作用域,就是一个名字在什么地方可以使用,什么时候不能使用。想了解更多关于作用域的问题推荐阅读《你不知道的JavaScript上卷》第一章(或第一部分),从编译原理的角度说明什么是作用域。概...

    denson 评论0 收藏0
  • 前端进击的巨人():执行上下文与执行栈,变量对象

    摘要:在中,通过栈的存取方式来管理执行上下文,我们可称其为执行栈,或函数调用栈。而处于栈顶的是当前正在执行函数的执行上下文,当函数调用完成后,它就会从栈顶被推出理想的情况下,闭包会阻止该操作,闭包后续文章深入详解。 写在开篇 已经不敢自称前端小白,曾经吹过的牛逼总要一点点去实现。 正如前领导说的,自己喝酒吹过的牛皮,跪着都得含着泪去实现。 那么没有年终完美总结,来个新年莽撞开始可好。 进击巨...

    _Suqin 评论0 收藏0
  • 进击JavaScript(四) 闭包

    摘要:此时产生了闭包。导致,函数的活动对象没有被销毁。是不是跟你想的不一样其实,这个例子重点就在函数上,这个函数的第一个参数接受一个函数作为回调函数,这个回调函数并不会立即执行,它会在当前代码执行完,并在给定的时间后执行。 上一节说了执行上下文,这节咱们就乘胜追击来搞搞闭包!头疼的东西让你不再头疼! 一、函数也是引用类型的。 function f(){ console.log(not cha...

    Anleb 评论0 收藏0

发表评论

0条评论

LeexMuller

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<