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

301次阅读  |  发布于3年以前

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

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

当代新版本浏览器

机制:如果当前函数使用了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

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8