提升:1. 变量提升 2. 函数提升
在解释提升之前,有必要先了解一下作用域 和作用域链
注意:以下解释非官方,个人理解
作用域:程序源代码中定义这个变量的区域
作用域链:当代码在一个环境中执行时,会创建变量对象的一个作用域链来保证对执行环境有权访问的变量和函数的有序访问
eg:
var a=2; console.log(a); <!-- a在全局作用域中 输出 2--> function testa(){ var a=3; console.log(a) } <!--a 既在全局作用域中又在局部作用域中,输出 3--> function testaa (){ console.log(a); } <!--a输出 2-->
解释:
a 在全局作用域中,在testa作用域中。
testa()执行时浏览器会询问引擎在哪里见过 a的声明,引擎会优先在当前作用域寻找,找到了 既返回给客户端,所以在testa()执行时,输出的a=3;
testaa()执行时 也是现在testaa的作用域中查找,发现并没有a,然后会顺着作用域链查找到全局作用域中的a,所以在testaa()中输出的不是 undefined 也不是RefrenceError 而是 2
- 变量提升
console.log(a)
var a = 2;
<!--输出 undefined-->
为什么不是RefrenceError?
由于js是编译语言,在引擎进程编译的过程中会先进行变量的声明,然后才会进行赋值操作,所以上述代码实际的执行过程是这样的:
var a ;
console.log(a);
a =2 ;
由于变量存在提升现象,会出现很多问题,其中就包括闭包(这里只简要介绍,详见js基础(2)):
var a=[];
for(var i =0;i<3;i++){
a[i]=function(){
return i;
}
}
console.log(a[0]()); // 3
console.log(a[1]()); // 3
console.log(a[2]()); // 3
为什么会全是3 呢
因为在执行a[0]()
时,在该函数的作用域中没有i的定义,所以回去找全局作用域中的i的值 此时在全局作用域中i 的值为3,所以所有的函数执行之后都是 3;
解决方式:
var a=[];
for(var i =0;i<3;i++){
a[i]=function(i){
return function(){return i}
}(i)
}
console.log(a[0]()); // 0
console.log(a[1]()); // 1
console.log(a[2]()); // 2
相当于在
a[i]
这个函数的作用域中声明了一个i变量 并且赋予了不同的值,所以会输出 0 1 2
ES6 中针对变量的提升给出了一种解决方案,新增了两种变量类型 const 和let,用这两种类型声明的变量存在暂时性死区,并且在编译阶段 由const和let声明的变量是未定义状态,所以就避免了变量提升。
console.log(a) ; //RefrenceError 未定义
let a =3;
var a=[];
for(let i =0;i<3;i++){
a[i]=function(){
return i;
}
}
console.log(a[0]()); // 0
console.log(a[1]()); // 1
console.log(a[2]()); // 2 解决闭包问题
- 函数提升
test(); //输出test
function test(){
console.log('test');
}
test()执行时 并没有报错,这就由于函数提升
由变量定义的函数 不提升,但是也存在变量声明的提升
console.log(test());
var test =function (){
console.log('test');
}
输出 TypeError test不是一个函数 ,
console.log(test);
输出 test为undefined,还是会存在变量提升的现象
console.log(test());
const test =function (){
console.log('test');
}
输出 RefrenceError test 未定义 ,同样说明由const let定义的在预编译阶段都认为没有定义过,只有赋值完成之后才能引用