顶层对象
在js中,顶层对象是window对象,其属性与全局变量挂钩,被认为js中的败笔之一。
a.但是window又指浏览器窗口对象,是具有实体意义的,这样不合适。
b.引擎预编译的时候不能对未声明变量进行报错,因为不知道是不是window上的属性。
c.顶层变量属性任意地方都可以读写,不利于模块化开发。
(1)let
let在全局作用域中声明的变量不会放在window(目前js中的顶层对象)上,将全局变量与顶层对象脱钩。
let a = 123;
console.log(window.a) // undefined
块级作用域与函数声明。es5浏览器中,不允许在会计作用域中进行函数声明,es6中允许,为了兼顾老代码,所以推荐函数表达式方式。块级作用域中, 函数声明会提升到当前块级作用域头部。
let a = 123;
{
function a (){}
}
//不会报错
(2)const 定义常量
a.声明时,需要进行赋值,定义后不能重新赋值。只要栈内存中的值不变就行,引用的对象可以修改(指针没变)。
b.也会产生块级作用域,不会有变量提升,存在暂时死区。
(3)冻结对象
Object.freeze,可以冻结对象的属性值。但是对象和数组的值依然可以改变(因为修改引用值,所存的指针没有改变)
function freezingTool(obj){
//先冻结原始值
Object.freeze(obj)
//遍历对象,将对象和数组值冻结
//for in 对象,数组都可以遍历
for(var key in obj){
let val = obj[key],
isReference = typeof( val ) === 'object' && val !== null;
if(isReference){
freezingTool(val)
}
}
}
(4)块级作用域的作用
a.避免访问外部变量时,被内部变量覆盖(变量提升)
let a = 123;
(function(){
console.log(a) //本来想要引用外部变量,结果变量提升,打印出undedined
if(1){
var a = 321
}
})()
b.避免循环体产生全局变量,通过var声明的变量会渗透到循环体外部,形成全局变量
for(var a = 0; a < 10; a++){
console.log(a)
}