JS中的变量提升机制

8 篇文章 0 订阅

浏览器加载页面,想让代码执行,首先会形成一个栈内存(ECStack);然后开始让代码准备执行;

=> 最开始执行的一定是全局下的代码,此时形成一个全局的执行环境(全局执行上下文EC(G)),把EC(G)压缩到栈内存中去执行(进栈);每一个函数执行也是这样操作的···

=> 有些上下文在代码执行完成后,会从栈内存中移去(出栈),但是有些情况是不能移出去的(例如:全局上下文就不能移除···)

=> 在下一次有新的执行上下文进栈的时候,会把之前没有移除的都放到栈内存的底部,让最新要执行的在顶部执行。

变量提升

在当前的执行上下文中(不论是全局,还是函数执行私有的),JS代码自上而下执行之前,首先对默认把所有带var和function(判断和循环之外的)关键字的进行声明(declare,创建一个变量)和定义(defined,让变量和值关联在一起)。

带var的只是提前声明;带function的会提前声明+定义

1、在当前执行上下文中,不管条件是否成立,(只要不是在函数里的)变量提升是有效的。旧的浏览器(IE10及以下)function func(){…}声明+定义都处理了,新的浏览器中,用判断或者循环等包裹起来的函数,在变量提升阶段,不论条件是否成立,此处只是先声明。

/*
 * 低版本浏览器(包含IE10及以内) 
 * 全局上下文中变量提升
 *    没有
 */
f=function (){return true;};//给GO中设置一个属性 f = function () {return true;}
g=function (){return false;};//给GO中设置一个属性 g = function () {return false;}
(function () {
// 	/* 
// 	 * 自执行函数执行,形成一个私有的执行上下文
// 	 *    [变量提升]
// 	 *    function g(){return true;}
// 	 */
// 	// 条件解析:
// 	// g() => 私有的G执行 TRUE
// 	// []==![] => []==false => 0==0 => TRUE
		if (g() && [] == ![]) { //=>条件成立
         f = function () {return false;} //f不是自己私有的,则向上查找,属于全局对象中的f,此处是把全局对象中的 f = function () {return false;}
         function g() {return true;} //跳过(变量提升处理过了)
     }
 })();
 console.log(f()); //=>FALSE
 console.log(g()); //=>FALSE  这个G找全局的(函数里面的G是自己私有的)


/*
 * 高版本浏览器 
 * 全局上下文中变量提升:没有
 */
 f=function (){return true;};//给GO中设置一个属性 f = function () {return true;}
 g=function (){return false;};//给GO中设置一个属性 g = function () {return false;}
 (function () {
// 	/* 
// 	 * 自执行函数执行,形成一个私有的执行上下文
// 	 *    [变量提升]
// 	 *    function g; 高版本浏览器中,在判断和循环中的函数,变量提升阶段只声明不定义
// 	 */
// 	// 条件解析:
// 	// g() => undefined() => Uncaught TypeError: g is not a function 下面操作都不在执行了
     if (g() && [] == ![]) {
         f = function () {return false;} 
         function g() {return true;}
     }
 })();
 console.log(f());
 console.log(g());

自执行函数形成一个私有的执行上下文,不再全局里变量提升
2、函数表达式方式创建函数,在变量提升阶段,并不会给函数赋值,只有代码执行过程中,函数赋值后才可以执行(不能再函数赋值之前执行)=>符合严谨的执行逻辑

在全局执行上下文中,带var和不带var定义的区别

带var是创建一个全局变量,存放在全局变量对象VO(G)中

不带var创建的不是一个变量,而是在全局对象GO(global object)的一个属性。(全局对象:浏览器会默认自带很多供JS调取使用的内置API,这些属性都在GO中储存,在浏览器端,把GO对象赋值给window,在node端把GO赋值给global)

总结:在全局上下文中,基于var创建变量,会给VO(G)和GO中各自储存一份,不带var的知识给GO设置一个属性而已,当我们输出这个变量值时,先看是否为全局变量,是的话输出全局变量的值;如果不是,则看它是否为全局对象的属性,如果再不是则报错!!

在JS中一旦当前代码报错,那么下面的代码都不再执行。

浏览器有一个特征:做过的事情不会再重复做第二遍(不会重复声明)
/*
 * 全局上下文中的变量提升
 *     fn = function(){ 1 }  声明+定义
 *        = function(){ 2 }
 *     var fn; 声明这一步不处理了(已经声明过了)
 *        = function(){ 4 }
 *        = function(){ 5 }
 * 结果:声明一个全局变量fn,赋的值是 function(){ 5 }
 */
 fn(); //=>5
 function fn(){ console.log(1); }  //=>跳过(变量提升的时候搞过了)
 fn(); //=>5
 function fn(){ console.log(2); }  //=>跳过
 fn(); //=>5
 var fn = function(){ console.log(3); } //=>var fn; 这一步跳过,但是赋值这个操作在变量提升阶段没有搞过,需要执行一次  => fn = function(){ 3 }
 fn(); //=>3
 function fn(){ console.log(4); } //=>跳过
 fn(); //=>3
 function fn(){ console.log(5); } //=>跳过
 fn(); //=>3
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值