js中,传统声明变量是var、function;es6中是let、const、import。今天说一下前四种的异同。
let 和 const
let
const
都是声明一个变量,但是const声明的变量不允许指针重新指向,且const声明的时候必须赋值,否则会报错。
变量赋值本质上就是一个指针指向的过程。const变量的值如果是引用数据类型的话,那么是可以改变里面的值的(这并不会改变指针的指向)。
let
const
不存在变量提升,所以必须先声明后使用。
3. let
const
声明的变量并不会给全局对象GO(window)增加属性。所以带声明的变量和不带声明的变量是不一样的机制,平时写的时候不要省略。
如果变量不带任何声明,则默认是给全局对象GO(window)增加属性,该变量就不会提前声明。
5. 同一上下文中,let
不允许重复声明
let 的检测是否重复声明发生在词法解析阶段(js代码自上而下执行,浏览器会提前处理很多事情,例如词法解析—>变量提升—>代码执行 等)。一旦在词法解析这一阶段报错,js代码一行都不会执行的。
var 和 function
var
function
声明的变量都存在变量提升机制,而且function
声明的变量会提前声明+定义。- 基于
var
function
声明的全局变量会给全局对象GO(window)增加一个对应的私有属性,它们之间有一个映射机制(一个修改,另一个也会跟着修改)
上下文中变量提升的细节点
代码执行分为:全局代码,函数中的代码,私有块的代码……不同环境下的代码执行都有着自己的上下文。
- 细节点1:不论条件是否成立,都要进行变量提升
if(!("a" in window)){ //"a" in window 检测a是否为window的一个属性 !true =>false
var a = 1;//变量提升
}
console.log(a);//undefined
- 细节点2:除函数/对象的大括号外,如果大括号中出现
let/const/function
,则会产生块级私有上下文
块级上下文中,只有基于let/const/function
声明的变量,才是块级上下文私有的
if(1 == 1){
var n = 12;//此时并没有形成块级私有上下文
}
consolo.log(n);//12
if(1 == 1){
let n = 12;//let !!! 此时形成块级私有上下文
}
consolo.log(n);//Uncaught ReferenceError: n is not defined
if(1 == 1){
var m = 13;//只有let/const/function声明的变量才是块级上下文私有的,所有m是全局的
let n = 12;//let !!! 此时形成块级私有上下文
}
console.log(m);//13
console.log(n);//Uncaught ReferenceError: n is not defined
- 细节点3:块级上下文中,函数的变量提升
在全局中,函数此时是只声明(针对新版本浏览器);在块级私有上下文中,函数是提升声明+定义。
但是在块级私有上下文中,会把里面对function xxx(){}
这一部分代码(包括这一部分)之前的操作“映射”给全局一份,此后的代码操作就是私有的了,与全局无关。
console.log(fn);//函数在全局中只是提前声明=====> undefined
if(1 == 1){
console.log(fn);//块级私有上下文中,函数提前声明+定义===>fn
function fn(){//此时形成块级私有上下文。代码执行到这的时候,会私有上下文中,对fn的操作(包括这一部分代码的操作)“映射”给全局一份,此后的代码操作就是私有的了,与全局的fn没有关系
console.log('ok');
}
fn = 12;
console.log(fn);//12
}
console.log(fn);//私有上下文的对于fn的定义映射给全局一份了=====>fn
- 细节点4:函数中,如果形参有默认值 且 函数体内有基于
var/let/const
声明的变量,也会形成块级私有上下文
注意里面说的两个条件哈,缺一不可!
这里形成块级私有上下文后,只有在里面(函数的大括号)中新声明的变量才是块级上下文私有的。且块级上下文的上级上下文是函数私有上下文
var x = 1;
function func(x,y = function annoymous(){x=2}){
x = 3;//x是func的私有变量,这里改变的是func私有变量x的值
y();
console.log(x);//2
}
func(5)
console.log(x);//1
//这里函数有形参默认值,但是函数体内没有基于var/let/const声明的变量,所以并不满足形成块级私有上下文的条件
var x = 1;
function func(x,y = function annoymous(){x=2}){
var x = 3;//两个条件满足了,形成块级私有上下文
y();//y不是新声明的变量,所以y是函数上下文的变量,执行y,改变的x是函数上下文的私有变量x,和块级上下文的私有变量x没有关系
console.log(x);//3
}
func(5)
console.log(x);//1
var x = 1;
function func(x,y = function annoymous(){x=2}){
var x = 3;//形成块级私有上下文
var y = function annoymous(){x=4};//y是新声明的,执行y,块级私有上下文的x变为4
y();
console.log(x);//4
}
func(5)
console.log(x);//1