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

前端瓶子君

共 5377字,需浏览 11分钟

 · 2021-09-05

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

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

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

老版本浏览器中,放在{}【排除:函数、对象】中的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

最后

欢迎关注【前端瓶子君】✿✿ヽ(°▽°)ノ✿
回复「算法」,加入前端编程源码算法群,每日一道面试题(工作日),第二天瓶子君都会很认真的解答哟!
回复「交流」,吹吹水、聊聊技术、吐吐槽!
回复「阅读」,每日刷刷高质量好文!
如果这篇文章对你有帮助,在看」是最大的支持
 》》面试官也在看的算法资料《《
“在看和转发”就是最大的支持
浏览 20
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报