作用域
常见的作用域主要分为几个类型:全局作用域、函数作用域、块状作用域、动态作用域。
对象 | 类型 |
---|---|
global/window | 全局作用域 |
function | 函数作用域(局部作用域) |
{} | 块状作用域 |
this | 动态作用域 |
如果一个 变量 或者其他表达式不在 “当前的作用域”,那么JavaScript机制会继续沿着作用域链上查找直到全局作用域(global或浏览器中的window)如果找不到将不可被使用。 作用域也可以根据代码层次分层,以便子作用域可以访问父作用域,通常是指沿着链式的作用域链查找,而不能从父作用域引用子作用域中的变量和引用
全局作用域
定义全局变量与window的属性
var a = 123 // 全部变量
b = 1234 // => 不加var的定义,会被挂载在window上
// 验证 a 和 b 是否为变量,通过 delete,变量不能被delete,属性可以被delete
delete a // => false 删除失败
delete b // => true 删除成功
在函数中定义window的属性
function test () {
c = 12345
}
test() // 一定要执行一次,执行挂载
console.log(c) // => 12345
函数作用域(局部作用域)
function test () {
var a = 3
return a + 4
}
console.log(test())
作用域链(闭包)
function test () {
var a = 3
function test2 () {
var b = 4
return a + b
}
return test2
}
块状作用域
在ES6之前没用块状作用域,只有全局作用域及函数作用域
没有块状作用域的情况(使用var定义变量)
function test () {
var a = 3
if (a === 3) {
var b = 4 // 没有块状作用域时这个定义跟a是同级的,等同于都在一个函数作用域里
console.log(true)
} esle {
console.log(false)
}
return a + b
}
test() // => 7
在JS中有
变量提升
的概念,在使用var创建变量时会被升级
function test() {
var a = 3
if (a === 3) {
var b = 4
console.log(true)
}
}
// 经过编译升级后,上面的函数等价于下面的函数,最终浏览器执行时也会变成下面的样子执行
function test() {
var a = 3
var b
if (a === 3) {
b = 4
console.log(true)
}
}
使用块状作用域(使用 let 和 const 定义变量)
function test () {
var a = 3
if (a === 3) {
let b = 4 // 块状作用域变量,不会被提升
console.log(b)
} esle {
console.log(false)
}
return a + b // 会报错,因为找不到b,b已经变为块状作用域的变量
}
test() // => 报错
动态作用域
a = 3
function test () {
console.log(this.a) // 此时的 this 为 window
}
test() // => 3
a = 3
function test () {
console.log(this.a) // 此时的 this 为 window
}
test() // => 100
test.bind({a : 100})() // 动态绑定,动态作用域