- JavaScript 引擎的工作方式:先解析代码,获取所有被声明的变量,然后再一行一行地运行。就是所有的变量的声明语句都会被提升到代码头部。
var a = 'a'; // 声明全局变量a全局变量a
fun(); // f是函数,虽然定义在调用的后面,但是函数声明会提升到作用域的顶部。
console.log(a); // a=>'a', 此时是全局变量的a
function fun() {
console.log(a); // 当前的a变量是下面变量a声明提升后,默认值undefined
var a = 'aa';
console.log(a); // a => 'aa'
}
//结果:undefined aa a
var a='a'
function a(){
console.log(a)
}
a()
//结果:a is not a function
function a(){
console.log(a)
}
console.log(a)
var a//声明过的变量不会重复声明,所以在这时候,a是个函数
a='a'//将function->'a'
a()//这时候’a‘已经赋值给a变量了,a()当然会报错了
fun()
var fun = function(){
console.log("aaa");
}
//结果: fun is not a function
//解析
var fun;//这时候fun->undefined
fun(); //foo is not a function
fun = function(){
console.log("aaa");
}
//也可以理解成这样
console.log(a,'a')//a=>undefined那是因为,先声明的变量,然后打印,最后赋值
var a='333'
console.log(fun);
var fun='str';
console.log(fun);
function fun(){}
console.log(fun);
结果:ƒ fun(){} str str
//解析
function fun(){}
var fun;//f声明过的变量不会重复声明
console.log(fun)
fun=10
console.log(fun)//10
console.log(fun)//10
- 总结:
- 函数声明会置顶
- 变量声明也会置顶
- 函数声明会在变量声明上面(函数在变量上面)
- 变量和赋值语句一起书写,在js引擎解析时,会将其拆成声明和赋值2部分,声明置顶,赋值保留在原来位置
- 声明过的变量不会重复声明
暂时性死区:只要一进入当前作用域,所要使用的变量就已经存在,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取、使用该变量。
let(提一下let)
- 以前,我们都是用var来声明变量,而且JS只有函数作用域、全局作用域,没有块级作用域,所以{}限定不了var声明变量的访问范围。
{
var a='a-var'
}
console.log(a)//a-var
{
let b='b-let'// b变量只在 花括号内可获取
console.log(b)//b-let
}
console.log(b)//b is not defined
- let/const:不存在变量提升。要求必须 等let/const声明语句执行完之后,变量才能使用,否则会报错。
- 在代码块内,let命令声明变量之前,该变量都是不可用的,称为“暂时性死区”
console.log(a)//undefined
console.log(b)//报错
var a='a'
let b='b'
var a = 10;
{
console.log(a)//10
var a = 6;
console.log(a)//6
}
console.log(a)//6
var a = 10;
{
// console.log(a)//报错,因为let不变量提升,暂时性死区
let a = 6;
console.log(a)//6
}
console.log(a)//10
{
let b='b-let'
let b='same-b'//报错 Identifier 'b' has already been declared
}
//看下面例子,为什么我同时声明了两次q,却没有报错。因为for 用let声明q跟,for循环体里面用let声明的q不在同一个块级作用域里面
// {
// let q=0
// {
// let q=12
// console.log(q)
// }
// ……
// }
for(let q=0;q<5;q++){
let q=12
console.log(q)// 12
}
- let和var的区别
- 通过var声明的变量没有块作用域,在块{ }内声明的变量可以从块之外进行访问。通过let声明的变量拥有块作用域,在块{ }内声明的变量无法从块外访问
- 通过var重新声明变量会带来问题,在块中声明变量也将重新声明块外的变量,覆盖块外的变量。通过let重新声明的变量不会重新声明块外的变量,会重新声明一个有块作用域的变量
- var会变量提升。let没有变量提升,变量会从块的开头一直处于“暂时性死区”,直到声明为止。
- 通过 var 定义的全局变量属于 window 对象。通过 let 定义的全局变量不属于 window 对象
- let和var的共同点
- 在函数内声明变量时,使用 var 和 let 很相似,它们都有函数作用域
- 在块外声明,var 和 let它们都拥有全局作用域