Appearance
let 和 const
JS 作用域:全局作用域(var 声明,变量提升)、函数作用域、块级作用域(es6 新增)
let
let 关键字:声明的变量只在当前代码块中生效(块级作用域)
- 可以重新赋值
- 不能在同一作用域重复声明
- 无变量提升 - 防止变量声明前使用变量
解决问题:
- 解决 i 丢失的问题 - 不同于 var全局有效,每次循环let都是重新声明的变量
- 内层变量可能会覆盖外层变量
- 替代匿名函数
const
const 声明为只读常量,声明后不可改
- 必须给初始值
- 只在声明所在的块级作用域内有效
- 存在暂时性死区
只读常量:变量指向的内存地址不能改动,只影响一层。
js
const foo = {}
// 为 foo 添加一个属性,可以成功
foo.prop = 123
foo.prop // 123
// 将 foo 指向另一个对象,就会报错
foo = {} // TypeError: "foo" is read-only对象冻结,应该使用Object.freeze方法,冻结后添加新属性不起作用
js
const foo = Object.freeze({})
// 常规模式时,下面一行不起作用;
// 严格模式时,该行会报错
foo.prop = 123不同类型值存放情况
普通类型:值保存在变量指向内存地址 引用类型:变量指向存放实际数据的指针
六种声明变量方法 :
var、function、let、const、import、class
暂时性死区
ES6 规定,区块中存在let和const命令,区块对let const声明的变量,形成了封闭作用域。声明之前就使用这些变量,就会报错,称为暂时性死区(temporal dead zone)
本质:进入作用域,变量就已经存在了,但是不可获取,只有声明变量的那一行代码之后(tdz 结束),才可以获取和使用该变量。
typeof 不再 百分百安全
js
typeof x // ReferenceError隐蔽的死区
js
function bar(x = y, y = 2) {
return [x, y]
}
bar() // 报错js
var x = x // 不报错
let x = x // 报错块级作用域
为什么需要块级作用域
在块级作用域出现之前,会出现不合理场景。
第一种场景,内层变量可能会覆盖外层变量。
js
var tmp = new Date()
function f() {
console.log(tmp)
if (false) {
var tmp = 'hello world'
}
}
f() // undefined第二种场景,循环变量泄露为全局变量
js
var s = 'hello'
for (var i = 0; i < s.length; i++) {
console.log(s[i])
}
console.log(i) // 5块级作用域
ES6 允许块级作用域的任意嵌套,并且每层都有单独作用域
js
{
{
{
{
let insane = 'Hello World'
{
let insane = 'Hello World'
}
}
}
}
}块级作用域与函数声明
示例
js
function f() {
console.log('I am outside!')
}
;(function () {
if (false) {
function f() {
console.log('I am inside!')
}
}
f()
})()ES5:输出 I am inside!,它将 f 函数 提升到函数顶部
js
;(function () {
function f() {
console.log('I am inside!')
}
if (false) {
}
f()
})()ES6:报错 Uncaught TypeError: f is not a function。遵循以下三条规则
- 允许在块级作用域内声明函数。
- 函数声明类似于
var,即会提升到全局作用域或函数作用域的头部。 - 同时,函数声明还会提升到所在的块级作用域的头部。
js
;(function () {
var f = undefined
if (false) {
function f() {
console.log('I am inside!')
}
}
f()
})()ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。
顶层对象
顶层属性和全局变量挂钩的问题
- 无法在编译阶段报出变量未声明错误
- 误创全局变量
- 顶层对象可读写,不利于模块化
- window 有实体意义
从 ES6 开始
var、function声明的全局变量,依旧是顶层对象的属性
let、const、class声明的全局变量,不属于顶层对象的属性
globalThis 对象
浏览器:顶层对象 window,node 和 Web Worker 没有
浏览器、Web Worker :顶层对象self,node 没有
Node :顶层对象global,其他环境没有
js
// 方法一
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')
}ES2020 引入globalThis作为顶层对象,指向全局环境下的this。