1.let和const不存在变量提升,并会导致暂时性死区
什么是变量提升?
es5之前的var 变量提升情况:
console.log(foo); //undefined
var foo=2;
let之后
console.log(foo); //ReferenceError
let foo=2;
什么是暂时性死区? 在代码块内,使用let命令声明变量之前,该变量都是不可用的,语法上成为暂时性死区(temporal dead zone)
{
tmp='abc' //ReferenceError
console.log(tmp) //ReferenceError
let tmp;
console.log(tmp) //undefined
tmp=123;
console.log(tmp) //123
}
暂时性死区的本质是:只要进入当前作用域,要使用的变量已经存在,但是不可获取,只有等声明变量的那一行代码出现,才可以获取和使用该变量。
2.块级作用域解决变量提升问题
var test=aaa;
function f(){
console.log(test)
if(false){
var test = '111'
}
}
f() //undefined
变量提升导致了内层的test变量覆盖了外层的test变量
另一个常见的就是for循环的i
var s='hiabu'
for(var i=0;i<s.length;i++){
...
}
console.log(i) //5
i只控制循环,但循环结束后,它并没有消失,而是泄露成了全局变量
块级作用域下:
let n=5;
{
let n=10;
}
console.log(n) //5
3.块级作用域与函数声明 ES6中规定: *允许块级作用域内声明函数 *函数声明类似于var 会提升到全局作用域或函数作用域的头部 *函数声明还会提升到所在的块级作用域头部
function f(){console.log('i am out')}
(function(){
if(false){
function f(){console.log('i am in')}
}
f(); //f is not a function
}())
--如果确实需要声明 应使用函数表达式的形式,而非函数语句--
let f =function(){} //表达式
function f(){} //语句
另外,块级作用域不含返回值,如果需要返回值可以借助do表达式
let x=do{
let t =f();
t*t+1;
}
4.const 只声明不赋值会报错
const foo;//会报错
const保证值不得改变,实际上是变量指向的内存地址不得改动,对于简单的数据,值就保存在变量指向的内存地址中,因此等同于常量。而复合类型的数据,变量指向的内存地址保存的是一个指针,const只能保证这个指针是固定的
const a =[];
a.push('hi'); //可执行
a.length=0; //可执行
a=['aaa'] //会报错
如果想要冻结对象,可以使用 Object.freeze方法 将对象彻底冻结的函数如下:
var constant = (obj) =>{
Object.freeze(obj);
Object.keys(obj).forEach((key,i)=>{
if(typeof obj[key]==='object'){
constant(obj[key]);
}
})
}
5.顶层对象 ES6开始,全局变量于顶层对象属性相隔离
var a=1;
window.a //1
let b=1;
window.b //undefined
获取顶层对象方法
var getGlobal=function(){
if(typeof self !=='undefined'){return self;}
if(typeof window !=='undefined'){return window;}
if(typeof global !=='undefined'){return global;}
throw new Error('unable to locate global object')
}