ES6入门详解(一) let const
在es6之前 JS实际上并没有块级作用域的概念 只有词法作用域 在es6中的let 与 const 就实现了块级作用域 和天然的模块化 var标签直接挂载到全局对象的特性无法实行模块化
let 用于for循环 let支持块级作用域 所以每次循环都是一个 单独的作用域 而重新定义循环变量 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i
时,就在上一轮循环的基础上进行计算。另外,for
循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
let命令不存在变量声明提升
let 与 const 命令会形成暂时性死区
let temp = '234' if(true){ console.log(temp) let temp = '123' }
上面代码就是暂时性死区的运行 如果在块级作用域内 已经存在了 let const 声明的变量 那么 在这之前的范围都属于死区范围 同样 typeof 在判断未声明的变量时 会返回undefined但是在判断暂时性死区的变量就会抛出引用错误 所以在这里还是遵守规范变量先声明再使用
在定义函数时也会出现暂时性死区的概念
function fn(x = y , y = 2) { return x + y } fn()
这个时候因为y 还没有执行到 所以这时候引用Y 就会报错 如果用下面方式运行就不会报错了
function fn1(x = 2 , y = x){ return x+y } console.log(fn1())
因为var的 变量声明提升机制 所以 var x = x 这是可以被执行的 结果是 undefined 但是let 并不会存在变量声明提升 let x = x 就是引用了一个不存在的变量会报错
所以暂时性死区就是说 当程序一执行到当前作用域 变量就已经存在 但是不能引用 只有在变量声明之后才可以调用
无论是const 还是let 都不允许 在同一作用域下 重复声明
const x = 2 const x = 2
下面来说一下块级作用域下的函数声明 这是个大坑 在es6标准中 块级作用域的funcion 声明类似于let 在块级作用域外不能被访问但实际是可以的
if(true){ function fn(){ console.log(111) } }else{ function fn2(){ console.log(2222) } } console.log(fn) console.log(fn2)
首先上述代码的执行按照标准应该报错 但实际是可以的
好这里也就是说 在node 与 浏览器环境下 块级作用域内声明的函数 依然可以被外部 引用 并且 类似var 首先js会预处理所有的function声明 将其提升到当前词法作用域顶部 值为undefined 因为这种声明不可控性 太高而且巨坑 所以尽可能使用 函数表达式声明函数
最后说一下const const声明的是常量
const
实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const
只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
因为这种特性所以如果真的想彻底冻结对象需要使用 Object.freeze
const foo = Object.freeze({});
如果想要冻结对象的所有属性 可以通过递归的形式来完成
let congelation = obj => { Object.freeze(obj); //枚举对象所有的属性 Object.keys(obj).forEach((key , i ) => { if(typeof obj[key] === 'object'){ congelation(obj[key]) } }) } let obj = { a : {}, b:{}, c:2 } congelation(obj) obj.ss = {} console.log(obj)
同一段代码为了能够在各种环境,都能取到顶层对象,现在一般是使用this
变量,但是有局限性。
全局环境中,this
会返回顶层对象。但是,Node 模块和 ES6 模块中,this
返回的是当前模块。函数里面的this
,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this
会指向顶层对象。但是,严格模式下,这时this
会返回undefined
。不管是严格模式,还是普通模式,new Function('return this')()
,总是会返回全局对象。但是,如果浏览器用了 CSP(Content Security Policy,内容安全政策),那么eval
、new Function
这些方法都可能无法使用。
如果想要在所有环境都拿到全局对象有几个方法
// 方法一 (typeof window !== 'undefined' ? window : (typeof process === 'object' && typeof require === 'function' && typeof global === 'object') ? global : this); // 方法二 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'); };