我们调用一个函数时,如果这个函数的变量没有在函数中定义,就去定义该函数的地方查找
以下代码输出10
let x = 10;
function f() {
return x;
}
function g() {
let x = 20;
return f();
}
console.log(g()); // 10
声明提前:提前到函数最顶部
1. 变量声明提前
var声明的变量都是函数作用域,即在函数体内可见,这会带来的一个问题就是声明提前
var x = 1;
function f() {
console.log(x);
var x = 2;
}
f();
相当于
var x = 1;
function f() {
var x
console.log(x);
x = 2;
}
f();
所以上述代码输出undefined
2. 函数声明提前
function f() {
x();
function x() {
console.log(1);
}
}
f();
相当于
function f() {
function x() {
console.log(1);
}
x();
}
f();
3、函数声明和变量声明的优先级
函数声明优先级>变量声明优先级
var x = 1;
function x() {}
console.log(typeof x); // number
解析:x变量先被声明为一个函数,然后当我们再用var声明x的时候,这个var会被忽略,但是x=1的赋值语句会运行,最后x就是1,类型是number
块级作用域
由于变量/函数的声明提前,导致出现bug。es6引入了块级作用域(让变量在指定代码块内才能访问),使用const和let声明变量
原有声明变量的方式var是函数作用域。
function f() {
let y = 1;
if(true) {
var x = 2;
let y = 2;
}
console.log(x); // 2
console.log(y); // 1
}
f();
块级作用域变量提升
提升后的行为跟var不一样,var是读到一个undefined,**而块级作用域的提升行为是会制造一个暂时性死区(temporal dead zone, TDZ)。**暂时性死区的现象就是在块级顶部到变量正式申明这块区域去访问这个变量的话,直接报错,这个是ES6规范规定的。
var x = 1;
if(true) {
console.log(x);
let x = 2;
}
上述代码直接报错