js 关于变量提升的两道“变态”面试题,你能做对么?

点击上方 前端瓶子君,关注公众号

回复算法,加入前端编程面试算法每日一题群

老版本浏览器没有块级上下文的概念

老版本浏览器中,放在{}【排除:函数、对象】中的function在变量提升阶段 都是声明+定义

新版本浏览器中

1. 如果function出现在除函数、对象的大括号中,则在变量提升截断,只声明不定义了!

2.如果除了函数和对象的大括号中,只要出现let/const/function关键词,都会产生块级私有上下文【对var无效】

注意:var是不受块的影响的

// 题1
// EC(G)
//  变量提升;
 var a;
 fn=0x000;[[scope]:EC(G)]
 console.log(a); //undefined
 var a=12; 
 function fn(){
     // EC(FN)
     //  作用域链:<EC(FN),EC(G)>
     //  形参赋值:--
     //  变量提升: var a;
     console.log(a); //undefind
     var a=13;   
 }
 fn();   
 console.log(a); // 12


// 题2
// EC(G)
//  变量提升;
     var a;
     fn=0x000;[[scope]:EC(G)]
 console.log(a);  //undefined
 var a=12;
 function fn(){
     // EC(FN)
     //  作用域链:<EC(FN),EC(G)>
     //  形参赋值:--
     //  变量提升: --
     console.log(a);//->不是自己的私有变量,是EC(G)中的全局变量 12
     a=13;
 }
 fn();
 console.log(a); //->13



// EC(G)
//  变量提升;
//     fn=0x000;[[scope]:EC(G)]
console.log(a); //->Uncaught ReferenceError: a is not defined
a=12;
function fn(){
    console.log(a);
    a=13;   
}
fn();
console.log(a);
console.log(foo); //->undefined
{
    console.log(foo);//->foo() {}
    function foo() {}
    foo = 1;//->私有的foo=1
    console.log(foo);//->1
}
console.log(foo);//->ƒ foo() {}
图片.png
// EC(G)
//  变量提升:
//      function foo;
//      function foo;
console.log(foo); //->undefined
{
    // EC(BLOCK)
    //  作用域链<EC(BLOCK,EC(G))>
    //  变量提升:
    //      foo = 0x001;[[scope]:EC(BLOCK)]
    //      foo = 0x002;[[scope]:EC(BLOCK)]
    //      ------
    //      foo=0x002;
\

    console.log(foo);//函数{2}
    function foo() {1}//把之前对foo的操作映射给EC(G)一份=>全局foo=0x002
    console.log(foo);//函数{2}
    foo = 1; //把私有的foo=1
    console.log(foo);//->1
    function foo() {2}//把之前对foo的操作映射给EC(G)一份=>全局foo=1
    console.log(foo); //->1
}
console.log(foo);//->1
图片.png
下面看一下三块代码的运行结果,比较一下区别
图片.png
当代新版本浏览器
  • 一方面兼容ES5语法

  • 一方面还要兼容ES6新语法

机制:如果当前函数使用了ES6中的形参赋值默认值【不论是否生效】,并且函数体中有基于let/const/var声明 的变量【无论变量名称是否和形参一致(注意let/const是不允许重复声明的),则函数在执行的时候,除了形成一个私有的上下文,而且还会把函数体{}当作一个私有的块级上下文[并且块级上下文的上级上下文是私有的那个上下文]

如果函数体中声明的变量和形参变量一直,最开始的时候,会把形参变量的值,同步给私有变量一份

// 符合条件

// 符合条件

function fn(x,y=10){
    var m =20;
}
fn(1,2)

尽可能不要使用形参赋值默认值

var x = 1;
function func(x,y=function anonymous1(){x =2}){
    var x = 3;
    var y = function anonymous1(){x = 4}
    console.log(x); 
}
func(5);
console.log(x); 


// 分析

var x = 1;
function func(x,y=function anonymous1(){x =2}){
    // EC(FUNC)
    //  作用域链<EC(FUNC),EC(G)>
    //  初始化this:window
    //  形参赋值:
    //      x=5;
    //      y=0x001;[[scope]:EC(FUNC)]
    // EC(BLOCK)
    //  作用域链<EC(BLOCK),EC(FUNC)>
    //  变量提升:
    //      var x; ->copy 5 ->3 ->4
    //      var y; ->copy 0x001 ->0x002 [[scope]:EC(BLOCK)]
    var x = 3;
    var y = function anonymous1(){x = 4}
    console.log(x);  // =>4
}
func(5);
console.log(x); //=>1
图片.png

前端路漫漫其修远兮,吾将上下而求索,一起加油,学习前端吧!

转自:狸不开

https://juejin.cn/post/6994620925501177863

最后

欢迎关注【前端瓶子君】✿✿ヽ(°▽°)ノ✿

回复「算法」,加入前端编程源码算法群,每日一道面试题(工作日),第二天瓶子君都会很认真的解答哟!

回复「交流」,吹吹水、聊聊技术、吐吐槽!

回复「阅读」,每日刷刷高质量好文!

如果这篇文章对你有帮助,「在看」是最大的支持

 》》面试官也在看的算法资料《《

“在看和转发”就是最大的支持

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值