变量提升

作用域的一些概念

任何声明在某个作用域内的变量,都将附属于这个作用域。

提升

先看两个例子
eg1

a = 2;
var a;
console.log( a );   //2

eg2

console.log(a);
var a=2; //undefined

对于eg2 js会将其看成两部分,var a ,a=2;所以eg2会变为

var a;
console.log(a);
a=2;
原因

引擎在解释js代码之前首先对其进行编译。编译阶段的一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来。
只有声明本身会被提升,而赋值或其他运行逻辑会留在原地。

  • 函数声明会被提升,但是函数表达式不会被提升
foo();
var foo=function bar(){
  //...
};

这段中变量标识符foo()先被提升并分配给所在作用域,但是foo并没有被赋值,此时foo()是undefined,此时对undefined值进行操作而导致非法操作,抛出TypeError异常。

var foo;
foo();
foo=function bar(){};
  • 即使是具名函数表达式,名称标识符在赋值之前也无法在所在作用域中使用;
foo();//TypeError;
bar();//ReferenceError;
var foo=function bar(){
//...
};

经过变量提升的形式:

var foo;
foo();
bar();
foo=function(){
   var bar=...self...
  //...
};
  • 函数优先
    函数声明和变量声明都会被提升,在多个重复声明的代码中,函数首先被提升,然后是变量;
    且后面的可以覆盖前面的;
foo();//3
function foo(){
console.log(1);
}
var foo=function(){
console.log(2);
};
function foo(){
console.log(3);
}

总结

预编译:函数声明整体提升,变量声明提升(赋值不提升)。
几个概念:
1.暗示全局变量(implyglobal):变量未经声明就赋值,此变量属于全局变量。
2.一切声明的变量,都是全局的属性
作用域做题四部曲:
1.创建AO对象(作用域、执行器上下文)
2.找形参和变量声明,将其作为AO对象的属性名,值为undefined
3.形参和实参相统一
4.在函数体里找函数声明,将值赋予函数体。
(var b=function(){}叫函数表达式 不在考虑里)预编译出现在函数声明的前一刻

题:

function fn(a){
	console.log(a);
	var a = 123;
	console.log(a);
	function a(){}
	console.log(a);
	var b= function(){}
	console.log(b);
	function d(){}
}
fn(1);
//function a(){}
//123
//123
//function (){}

在这里插入图片描述
步骤三:

AO{
a:function a(){},
b:undefined,
d:function d(){}
}

再按照顺序执行。

参考:你不知道的JaveScript上卷——提升

原文地址:https://www.cnblogs.com/xmjs/p/14019897.html