var、function、let、const变量提升

我通过阅读这两篇文章得出了自己的结论。
如果不明白,可以看这两篇文章:

引擎执行过程中变量的威力分为三。
步骤:注册、初始化、赋值

函数在注册阶段同时初始化和执行,所以无论写到哪里都可以直接调用该函数

>

js的变量提升是如何实现的?

JavaScript引擎的工作方式是,它首先解析代码,获取所有声明的变量,然后逐行执行。
这样,所有变量声明语句都被提升到代码的顶部。
这称为变量提升。
不过,随着let和const的出现,我们可以避免变量提升带来的问题。

js变量声明易混淆的几点知识

变量提升

变量和函数名提升优先级

js作用域内有变量。
这很容易理解,但有一些细节需要考虑。

console.log(foo);//函数functionfoo(){console.log("函数声明");}console.日志(富);//函数varfoo="变量";console.log(foo);//变量

如果变量名和函数名同名,并且都提升,最终的结果是:哪个语句有效?

有两个知识点:1.Varfoo不会覆盖之前的变量。
2.函数提升的优先级高于变量提升,并且不会被变量声明覆盖,而是被变量赋值覆盖,所以上面的代码实际上是

functionfoo(){//优先级最高,提升console.log("函数声明");}varfoo;//只提升声明,不提升赋值,并且函数声明不能​​被覆盖console.log(foo);控制台.log(foo);foo="变量";//可以使用函数声明console.log(foo);覆盖

具有相同赋值的变量提升

varnum1=1;函数fn(num3){console.log(num1);//输出未定义console.log(num3);//输出4console.log(num4);//抛出错误“num4未定义”console.log(num2);//抛出错误“num2未定义”varnum1=num4=2;//jsequals赋值num4不会提升num2=3;//没有变量被包含在全局作用域但没有提升,所以在varnum3=5;之前报错

if决定内部变量提升

if(true){functionfn(){return1}}else{if(false){functionfn(){return2;console.log(fn.toString());console.log(fn())

以下是找到这个例子的原文摘录:chrome和ie都是functionfn(){return2;},但是还是报错火狐。
可以看出,这三个过程并不相同。
变量声明在ff中扩展,但块级作用域中的函数声明不扩展。
Chrome和IE在块级别扩展函数声明,后面的声明会覆盖前面的声明。

函数作用域内的赋值

说到js中的变量赋值,首先要讲的是作用域。
在es6之前,只有函数形成了独立的作用域。
函数的作用域和嵌套就构成了js的作用域链。
父范围中的项目可以在子范围中访问。
函数的作用域是在确定函数时独立于调用而确定的。

//test1varx=1;函数foo(x){varx=3;vary=函数(){x=2;)}y();控制台le.log(x);returny}varz=foo()//22z()//2

这个函数输出三个2指向同一个x,甚至当x变成对象时改变x会更明显

//test2varx="abc";functionfoo(x){varx=c;vary=function(){返回x;}返回y;}varc={a:1}varz=foo();log(b===c);//true

在上面的例子中,y函数被返回并赋值给y函数(函数体)的Z点。
)。
此时z不存在,不在foo函数的作用域内,在此作用域内无法访问x,但z只是一个指向引用类型数据的指针,仅指向与x相同的对象。
当执行z函数时,它返回在中引用的x的值访问函数y。
它是一个基于变量写入位置的范围,不能因调用位置不同而改变。

同时需要注意的是,虽然函数的作用域是在函数编写时就确定的,但具体值与调用的时间有关。

//test3varx="abc";函数foo(x){varx=c;}返回y}varc={a:1}varz=foo();console.log(z())//{a:2}console.log(z())//{a:3}console.log(z())//{a:4}

在这个例子中,同一个对象被输出了3次,但是输出的值不同。
这是因为输出时的值不同,这与调用时的实际值有关。