JS 里存在两类块
,一种是 block {},另一种是 function body (){}(包括 method),这两种块对不同的变量声明会有不同的作用域效果,下面就来看看。
varif (false) {
var a = 1
}
console.log(a) // undefinedvar 是一种历史悠久的变量,他不认识 block {},会直接提升到第一个 function body 区,即使是 Dead-code 也不例外。
let, constlet a = 1
if (true) {
const a = 2
}
console.log(a) // 1let 和 const 严格存在于当前 block 内,不会发生任何变量提升。
functionif (false) {
function foo() {}
}
console.log(foo) // undefinedfunction 也是一种定义变量的方式,他和 var 一样悠久,提升规则和 var 几乎一样,但有两点不同:
const a = 1
if (false) {
var a = 2 // SyntaxError: Identifier 'a' has already been declared
}const foo = 1
if (true) {
function foo() {}
}
console.log(foo) // 1var 会不择手段地提升,碰到 const, let 之类硬茬就会爆炸;而 function 则温和很多。console.log(a, foo()) // undefined, 2
var a = 1
function foo() {
return 2
}var 只送一个 undefined 不同,function 会连着定义一起送出去,我们可以 看起来 在定义之前就使用他。实际上,可以认为 function 连着内容一起被提升到了当前函数块的顶部执行。另外,当整个 function 作为表达式而不是语句存在时,其名称只会被限定在函数体内可以访问:
$button.onclick = function hello() {
console.log(hello.name) // 'hello'
}
console.log(hello) // ReferenceError: hello is not definedclassconst A = 1
if (true) {
class A {}
A = 2
}
console.log(A) // 1class 创造的变量约等于 let,不过需要注意的是,在 class 的静态表达式中是可以直接访问到其类名的,而 let 需要先执行完 class,反而不能这么使用:
class A {
static a = A.name // 'A'
static b = this.name // can also use `this`
}let A = class {
static a = A.name // ReferenceError: A is not defined
static b = this.name // 'A'
}注意到最后一个例子,A.b 可以拿到 'A',这是因为匿名类会被自动赋予左边的变量名。当左边不是一个变量的时候该类的名字就是空了:
console.log(
class {
static b = this.name
}.b,
) // ''