ES6 - ES12

2022/2/7 JavaScript解构块级作用域

# 字面量的增强

# 对象的字面量

# 属性的简写

var name = "okarin"
var age = 18

var obj = {
    name:name,
    age:age
}
1
2
3
4
5
6
7
var obj = {
    name,
    age
}
1
2
3
4

# 方法的简写

var obj = {
  foo: function () {
      
  },
}

1
2
3
4
5
6
 foo() {
      
  },
1
2
3

# 计算属性名

[name + 123]:"hehehe"
1

# 解构

# 数组的解构

var names = ["abc","cba","nba"]

var item1 = names[0]
var item2 = names[1]
var item3 = names[2]

var [item1,item2,item3] = names

//只解构后面的元素
var [ ,itema , itemb] = names

//解构一个元素,后面的元素放进一个新数组中 
var [itema,...newNums] = names

//解构的默认值
var[itema,itemb,itemc,itemd = 'aaa'] = names
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 对象的解构

var obj = {
  name:"okarin",
  age:18,
  height:1.73
}

var {name , age ,height} = obj

//改变名称
var {name: newName} = obj
console.log(newName)

//对象解构默认值
var {address:newAddress =  "广州市"} = obj

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 解构的应用场景

image-20220207100012880

  • 对变量进行解构使用
  • 对函数的参数进行解构

# let/const

image-20220207101320217

# let/const的作用域提升

console.log(foo)//undefined
var foo = "foo"

console.log(bar)
//ReferenceError(引用错误): Cannot access 'bar' before initialization(初始化)
let bar = "bar"

1
2
3
4
5
6
7

image-20220207102203418

image-20220207102848537

# 和window的关系

我们知道,在全局通过var来声明一个变量,事实上会在window上添加一个属性

但是let、const是不会给window上添加任何属性的。那么我们可能会想这个变量是保存在哪里呢?

我们先回顾一下最新的ECMA标准中对执行上下文的描述

Every execution context has associated with it a variable object.Variables and functions declared in the source text are added as properties of the variable object.For function code,parameters are added as properties of the variable object. 每一个执行上下文会被关联到一个变量环境(variable object,VO),在源代码中的变量和函数声明会被作为属性添加到VO中。对于函数来说,参数也会被添加到VO中。 Every execution context has an associated VariableEnvironment.Variables and functions declared in ECMAScript code evaluated in an execution context are added as bindings in that VariableEnvironment's Environment Record.For function code,parameters are also added as bindings to that Environment Record. 每一个执行上下文会关联到一个变量环境(VariableEnvironment)中,在执行代码中变量和函数的声明会作为环境记录(Environment Record)添加到变量环境中。 对于函数来说,参数也会被作为环境记录添加到变量环境中。

# 变量被保存在VariableMap中

  • 也就是说我们声明的变量和环境记录是被添加到变量环境中的:
    • 但是标准有没有规定这个对象是window对象或者其他对象呢?口其实并没有,那么JS引擎在解析的时候,其实会有自己的实现;
    • 比如v8中其实是通过VariableMap的一个hashmap来实现它们的存储的。
    • 那么window对象呢?而window对象是早期的GO对象,在最新的实现中其实是浏览器添加的全局对象,并且一直保持了window和var之间值的相等性;

# 块级作用域的理解

在ES5中,只有两个东西会形成作用域

  • 全局作用域
  • 函数作用域
function foo(){
    var bar = "foo"
}
console.log(bar) //undefined

1
2
3
4
5

# ES6的块级作用域

{
   var foo = "why"
   function demo(){
   console.log("domo function")
   }
    class Person {}
    
}

console.log(foo)//"why"
demo()//"domo function"
1
2
3
4
5
6
7
8
9
10
11

ES6块级作用域只对let/const/class声明的类型是有效的,对于var声明的变量是无效的。

而对于函数,不同的浏览器有不同的实现方式(大部分浏览器为了兼容以前的代码,让function没有块级作用域)

# if switch for 块级作用域

if (ture){
    var foo  = "foo"
    let bar = "bar"
}

console.log(foo)//"foo"
console.log(bar)// undefined


var color= "red"
switch(color){
    case "red":
        var foo = "foo"
        let bar = "bar"
}

console.log(foo)//"foo"
console.log(bar)// undefined

for(var i = 0 ,i < 10,i++){
   
}
 console.log(i)//10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

if,switch,for语句的代码就是块级作用域

# 块级作用域的应用场景

<body>
    
    <button>按钮1</button>
    <button>按钮2</button>
    <button>按钮3</button>
    <button>按钮4</button>
    
</body>
<script src="./03_块级作用域.js"></script>
1
2
3
4
5
6
7
8
9
const btns = document.getElementsByTagName("button")
console.log(btns)

for (var i = 0; i < btns.length; i++) {
  ;(function (n) {
    btns[i].onclick = function () {
      console.log("第" + (n+1) + "个按钮被点击了")
    }
  })(i)
}
1
2
3
4
5
6
7
8
9
10

由于for的块级作用域问题,之前需要通过闭包解决

for (let i = 0; i < btns.length; i++) {
  btns[i].onclick = function () {
    console.log("第" + (i + 1) + "个按钮被点击了")
  }
}
1
2
3
4
5

在ES6之后通过let解决

# 块级作用域的补充

const names = ["abc", "cba", "nba"]

for (const i = 0; i < names.length; i++) {
  console.log(names[i])
}

//TypeError: Assignment to constant variable.
1
2
3
4
5
6
7

在使用自增或自减的for循环里面,不能使用const定义变量i,因为i会自增,而const定义的值不能改变。

for(const item of names ){
    console.log(item)
}

//abc
//cba
//nba
1
2
3
4
5
6
7

而在for....of...之中可以使用const,因为不涉及自增或自减的改变。

# 暂时性死区

在ES6中,还有一个概念称之为暂时性死区

它表达的意思是在一个代码中,使用let, const声明的变量,在声明之前,变量都是不可以访问的;口我们将这种现象称之为temporal dead zone (暂时性死区, TDZ)

var foo = "foo"

function bar(){
    console.log(foo)
    let foo = "bar"
}


bar()


//ReferenceError: Cannot access 'foo' before initialization
1
2
3
4
5
6
7
8
9
10
11
12

# var、let、const 的选择

那么在开发中,我们到底应该选择使用哪一种方式来定义我们的变量呢?

# 对于var的使用

  1. 我们需要明白一个事实,var 所表现出来的特殊性:比如作用域提升、window全局对象、没有块级作用域等都是一些历史遗留问题;

  2. 其实是JavaScript在设计之初的一种语言缺陷

  3. 当然目前市场上也在利用这种缺陷出一系列的面试题,来考察大家对 JavaScript 语言本身以及底层的理解;

  4. 但是在实际工作中,我们可以使用最新的规范来编写,也就是不再使用var来定义变量了;

# 对于let、const

  1. 对于 letconst 来说,是目前开发中推荐使用的;
  2. 我们会优先推荐使用const,这样可以保证数据的安全性不会被随意的篡改;
  3. 只有当我们明确知道一个变量后续会需要被重新赋值时,这个时候再使用 let
  4. 这种在很多其他语言里面也都是一种约定俗成的规范,尽量我们也遵守这种规范;
Last Updated: 2022/2/14下午9:33:34