Skip to content

Latest commit

 

History

History
276 lines (150 loc) · 4.44 KB

1、块级作用域绑定.md

File metadata and controls

276 lines (150 loc) · 4.44 KB

块级作用域绑定

介绍ECMAScript 6新引入的块级作用域绑定机制及其最佳实践

var声明及变量提升

变量提升(Hoisting):在函数作用域或全局作用域通过关键字var声明的变量,无论实际上是在哪里声明的,都会被当成在当前作用域顶部声明的变量

function getValue () {
   if(condition) {
       var value = "blue"
   }
   else {
       // 此处可以访问value,为undefined
   	return null
   }
}

变量value的声明被提升至函数顶部,而初始化操作依然留在原处执行

为此,ECMAScript6引入块级作用域来强化对变量生命周期的控制

块级声明

块级声明用于声明在指定块的作用域之外无法访问的变量

亦称为词法作用域,存在于

  • 函数内部
  • 块中(字符{}之间的区域)

let声明

用法与var相同,用let替代var来声明变量,就可以把变量的作用域限制在当前代码块中

let声明不存在变量提升,因此,一般将let声明语句放在封闭代码块的顶部,以便整个代码块都可以访问

function getValue () {
	if(condition) {
        let value = "blue"
    }
    else {
        // value不存在
		return null
    }
}

代码块执行完,变量立刻被销毁

禁止重声明

如果作用域中已经存在某个标识符,若再使用let声明则会报错

var count = 30
let count = 40 // 报错

即同一作用域中不能用let重复定义已经存在的标识符

如果作用域中嵌套另一个作用域,则可以再内嵌的作用域中用let声明同名变量

var count = 30 
if(condition) {
    let count = 40
}

内部块中的count会遮蔽全局的count

const声明

const关键字,使用const声明的是常量,必须进行初始化,其值被设定后不可更改

const maxItems = 30
const name // 错误
maxItems = 0 // 错误

const与let声明的都是块级标识符,常量也只在当前代码块内有效,执行到块外会立即销毁

在同一作用域用const声明已经存在的标识符也会导致语法错误,无论该标识符是var、let或const声明的

var message = "Hello"
let age = 25

// 报错
const message = "bye"
const age = 30

const声明对象,可以修改对象的属性值

const person = {
    name: "Nicholas"
}
// 正确
person.name = "Tom"
// 错误
person = {
    name: "Tom"
}

临时死区

Temporal Dead Zone

用var声明的变量会变量提升,将其提升到作用域顶部

用let或const声明的变量,将其放到TDZ中,访问TDZ中的变量会报错,执行变量声明语句后,变量才会从TDZ中移出,可以正常访问

// 正常 undefined
console.log(typeof value)
var value = 1
// 报错
console.log(typeof a) 
let a = 1 // const a = 1

循环中的块作用域绑定

for(var i = 0; i < 10; i++) {

}
console.log(i) // 10

由于变量提升,循环结束后仍可访问i

for(var i = 0; i < 10; i++) {

}
console.log(i) // 报错

使用let声明的i只在循环内有效,执行完for循环后,i立刻被销毁

循环中的函数

var funcs = []
for(var i = 0; i < 10; i++) {
    funcs.push(function () {
        console.log(i)
    })
}
funcs.foreach(function(func) {
    func() // 输出10次10
})

循环里的每次迭代同时共享着i,循环内部创建的函数全都保留了对相同变量的引用,循环结束时变量i的值为10,因此每次调用都会打印10

可以使用立即执行函数优化

循环中的let声明

var funcs = []
for(let i = 0; i < 10; i++) {
    funcs.push(function () {
        console.log(i)
    })
}
funcs.foreach(function(func) {
    func() // 输出0-9
})

每次循环时let声明都会创建一个新变量i,每次创建的函数都能获得单独的变量i

循环中的const声明

标准中未明确指明不允许在循环中使用const声明

当循环中不会修改该变量时,可以使用const声明

var obj = {
	a : 1,
    b : 2,
    c : 3
}
for(const key in obj) {
    // 
}

全局块作用域绑定

在全局作用域中使用var声明某个变量时,会创建一个新的全局变量挂载到全局对象(window对象),所以可能会无意中覆盖一个已经存在的全局属性

在全局作用域中使用let或const,不会添加为全局对象的属性