前言
js属于解释型语言,在执行过程中顺序执行,但是会分块先预编译然后执行。因此在js中存在一种变量提升的现象。因为有了js的预编译所以才有我们说的变量提升。
javascript 代码运行的三大步骤
- 词法分析:就是检查一遍js代码里有无语法错误(比如少分号,多括号等),语法分析期间不会执行代码。
- 预编译:这个阶段发生在代码执行的前一刻,就是在内存里创建一个空间,用来存放定义的变量和函数。
- 解释执行:执行代码。
变量提升
变量提升规则
函数声明整体提升(无论函数调用和声明的位置是前是后,系统总是把函数声明移到调用前面)
变量声明替僧呢(无论变量调用和声明的位置是前是后,系统总会把声明移到调用前,仅仅只是声明,值仍是undefined,只有在执行阶段才会进行变量初始化。匿名函数不参与预解析。)
变量提升概念
js在代码执行前,会将所有变量的定义提到最前面,声明的函数也有这样的效果。
console.log(a);
var a = 123;
// undefined
console.log(bbb);
var bbb
/// undefined
console.log(b)
function b(){
console.log('你好,吃了吗?');
}
//ƒ b(){console.log('你好,吃了吗?');}
变量未声明直接使用的情况下,浏览器会报错 xxx is not defined。
console.log(aaa);
ReferenceError: aaa is not defined
全局变量
在浏览器中,在全局作用域下声明的变量。-- 显式声明
var a = 123 // window.a 123
变量未经声明,直接赋值的变量。-- 隐式声明
b = 123
function c(){
d = 123
}
c()
// window.b window.d 123
使用window声明的变量。全局变量全是window的属性。
function c(){
window.dd = 123
}
c()
// window.dd 123
预解析
概念
预解析代码,主要会把var、function、参数等一些东西存储到内存里。
- var一般用于声明变量,预解析代码的时候,等号后面的赋值过程不会执行。
- function函数预解析时候,值就是函数里面的内容。
Global Object 和 Activation Object
js 在执行前会产生一个GO,就是全局作用域。当一个方法被调用时,会形成一个局部作用域AO。
GO对象的预编译过程如下:
创建GO对象
寻找变量声明(var),值为undefined
-
寻找函数声明,将函数名作为GO的属性名,值为函数体
function test(){ var a = b = 123 } test() // GO:{ test:test() }
AO对象的预编译过程如下:
- 创建AO对象
- 找函数的形参和变量声明(var),作为AO属性名,值为undefined
- 形参和实参统一,赋值
- 找函数声明,将函数名作为AO属性名,值为函数
function fn(){
console.log(a);
var a = 123;
console.log(a);
function a(){}
console.log(a);
var b = function(){}
console.log(b);
function d(){}
}
fn(1)
* AO:{
* a:fn
* b:undefined
* d:fn
* }
// fn 123 123 fn