1.变量声明
if (true) {
var a = "AAA";
}
console.log(a); //"AAA"
//预编译阶段
var a;
//执行阶段
if (true) {
a = "AAA";
}
console.log(a); //"AAA"
var声明的变量存在Js全局作用域中,且在预编译阶段已经执行。
if (false) {
var a = "AAA";
}
console.log(a); //"undefined"
//预编译阶段
var a;
//执行阶段
if (false) {
a = "AAA";
}
console.log(a); //"undefined"
上述代码只声明了color变量却没有赋值,所以显示undefined。 JS编译器会把变量声明分为声明操作和赋值操作。 声明操作在编译阶段进行,声明操作会被提升到执行环境的顶部,值是undefined(表示未初始化); 赋值操作会被留在原地等待执行阶段。注释:声明提前是在JavaScript引擎的预编译时进行,是在代码开始运行之前。
函数声明
创建函数第一种方法
函数声明会在编译阶段将函数和函数体提升到执行环境顶部,所以可以在函数声明前调用函数
sum(10, 10); //20
function sum(n1, n2) {
return n1 + n2;
}
代码经过预编译阶段如下
var sum;
sum = function sum(n1, n2) {
return n1 + n2;
}
sum(10, 10); //20
创建函数第二种方法(函数表达式)
var sum = function sum(n1, n2) {
return n1 + n2;
}
通过匿名函数赋值给变量定义的方法叫做函数表达式,这种方式创建的函数没有函数声明提升
//经过预编译后代码如下
var sum;
sum = function sum(n1, n2) {
return n1 + n2;
}
在函数表达式创建函数前创建函数前调用函数
sum(10, 10) //报错Uncaught TypeError: sum is not a function
var sum = function sum(n1, n2) {
return n1 + n2;
}
因为通过函数表达式创建函数没有函数提升,调用时还没有创建函数,预编译后代码如下:
//预编译阶段
var sum;
//执行阶段
sum(10, 10);
sum = function sum(n1, n2) {
return n1 + n2;
}
可以把函数表达式分为2步,第一步声明变量sum,第二步分给变量sum赋于这个匿名函数,而通过var声明的sum存在变量提升,在预编译阶段会提升到执行环境顶部,然后执行sum(10,10)就会报错,提示sum不是一个函数,undefined当然不是一个函数啦,执行完后,sum才指向了这个函数。
例题
第1题 同时存在函数声明和变量声明(函数声明优先)
getName(); //1
var getName = function () {
console.log(2);
}
function getName() {
console.log(1);
}
getName(); //2
预编译后:
var getName;
function getName() {
console.log(1);
}
getName(); //1
var getName; //再次声明会被忽略
function getName() {
console.log(2);
}
getName(); //2
第2题
var a = 1;
function b() {
a = 10;
return;
function a() {
}
}
b();
console.log(a); //1
b函数内部存在函数变量声明提升,所以return后面的funtion a() {}会提升到当前执行环境顶部,因此b函数内部相当于声明了局部变量a,和全局作用域的a不同,当b执行完,局部变量被销毁。console.log(a)打印变量a的时候会搜索变量a,最后只在全局变量中发现了a。
//预编译后
var a = 1;
function b() {
var a;
function a() {}
a = 10;
return;
}
b();
console.log(a); //1