听说难倒人的“变量提升”

变量提升是啥

在当前上下文中,JS代码自上而下执行之前,浏览器会提前处理一些事情。其中包括:把当前上下文中所有带varfunction关键字的进行提前声明和定义。

具体的:

  • 带var关键字的只提前声明,即创建变量,不赋值。var a;
  • 带function关键字的会提前声明&提前定义。既创建变量,又为它赋值(函数的堆内存地址)。

两个简单的小例子

例1.

console.log(a);
var a = 12;
a = 13;
console.log(a);

在代码执行前:带var关键字的变量会提前声明但未赋值: var a;
代码开始执行:由于a已声明未赋值,第一个console.log(a)输出undefined。
执行var a = 12时,a已经声明了,所以此时没有重新声明,只是将12赋值给了a.
a = 13, a的值修改为13。最后console.log(a)输出为13。

例1变形:

console.log(a);
a = 13;
console.log(a);

在这里插入图片描述
报错原因:变量a没有用var声明,因此不存在变量提升。

例1再变形:

console.log(a);
let a = 12;
a = 13;
console.log(a);

报错原因:ES6中的let, const关键字定义的变量不存在变量提升。

例2.

func();
function func(){
	console.log("ok");
}

结果输出字符串"ok"
在这里插入图片描述

创建与执行过程如下:
在这里插入图片描述

注:函数在创建时就声明了函数的作用域[[scope]]:EC(G),即创建函数时所在的上下文。

在这里插入图片描述
可以看出,在函数定义前就执行,毫无障碍,并不会报错。但这样似乎不太规范,因此在真实项目中,建议用函数表达式的方式创建函数var func = function(){…}。只带var关键字,在变量提升阶段只声明,不赋值。不能提前执行func()

匿名函数具名化

var func = function AAA(){…}

给这个函数取个名字AAA并在全局下调用它,会报错。
在这里插入图片描述

报错的原因:
当函数执行时,会将AAA作为私有变量,而不会在当前上下文(全局)中创建这个变量。
在这里插入图片描述
递归中常用这种方式,从而可以弃用严格模式下不支持的arguments.callee

变量提升与全局对象(GO)的联系

基于var/function在全局上下文中声明的变量(全局变量),会映射到全局对象GO(window)中一份,作为它的属性。之后,一个会跟着另一个的改变而改变。
在这里插入图片描述

条件语句中的变量提升

在全局上下文中:

console.log(a,func);    // undefined,undefined
if(!("a" in window)){
	var a = 1;
	function func(){…}
}
console.log(a);     // undefined

需要注意的点:

  • 无论条件是否成立,都要进行变量提升。因此,console.log(a,func)输出undefined,undefined。
  • 条件中带有function关键字的,变量提升时:
    • 在老版本浏览器中,声明&赋值
    • 在新版本浏览器中,只声明,不赋值
  • 在全局上下文中,var声明变量(a),同时也向GO(window)中映射一份,作为window的属性,因此a成为window的属性,条件不成立,不为a赋值。输出仍未undefined。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值