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() {}
// 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
下面看一下三块代码的运行结果,比较一下区别
当代新版本浏览器
一方面兼容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
前端路漫漫其修远兮,吾将上下而求索,一起加油,学习前端吧!
转自:狸不开
https://juejin.cn/post/6994620925501177863
最后
评论