阅读 48

ES6 新特性-实用笔记(一)

let 与块级作用域

作用域-某个成员能够起作用的范围, 在 ES5  之前只有两种作用域:

  • 全局作用域
  • 函数作用域

ES6 中新增了块级作用域。

在此之前是没有块级作用域的概念,导致在类似 if/for 语句中定义的变量,在全局作用域中也可以获取到,例如:

if(true) {
  var a = 'hello'
}

console.log(a) // 'hello'
复制代码

ES6 中新增了let 关键字,通过let声明的变量只能在声明它的作用域中使用。即,块级作用域内的成员,外部无法获取到。

let 不存在变量提升;

除此之外,还有一个const 关键词, 他用来定义一个衡量或者是一个常量,用来定义一个只读参数;

数组解构

const arr = [1, 2, 4]

// 单独获取成员
const [test1, test2, test3] = arr

// 获取指定位置成员
const [, , test3] = arr

// 提取当前位置开始的所有成员, 只能在最后一个成员上使用
const [test, ...test2] = arr

// 当结构成员长度小于数组长度, 从前到后提取; 结构大于数组长度, 则会返回undefined
const [test] = arr

// 设置解构默认值
const [test1, test2, test3, test4 = 4] = arr
复制代码

对象解构

const obj = {name: 'heihei',  age: 18}

// 获取指定属性
const { name } = obj

// 解构变量重复,使用变量重命名可以解决变量重复的问题, 同时可以设置默认值
const { name: asName, age: asAge = 10 } = obj

console.log(asName === name) // true
复制代码

模版字符串

  • 相较传统字符串, 模板字符串支持换行;
const str = `hello
world !`
复制代码
  • 模板字符串支持插值表达式的方式,嵌入变量|语句
console.log(`ooooooooh! ${str}`)

console.log(`ooooooooh! ${Math.random()}`)
复制代码
  • 标签函数 定义模板字符串之前定义一个标签,这个标签就是一个特殊的函数,添加这个标签,就可以调用这个函数。

作用:对字符串进行加工

const name = "tom"
const gender = '男'

// string 是模板字符串的静态内容,类型为数组
// 模版字符串中出现的剩余变量
// return 返回的字符串终值
const tagFunc = (string, name, gender) => {
  return string[0] + name + string[1] + gender + string[2]
}

const result = tagFunc`hello, ${name} is a ${gender}!`
复制代码

字符串的拓展方法

includes | startWidth | endWidth

参数默认值

es5 中默认值的处理方式:

// 有缺陷的设置,当enable 为false, 值会为true
const foo = (enable) => {
  enable = enable || true
  console.log('doSomeThing)
}
// 更科学的设置方法, 用undefined 来判断是否有入参
const foo = (enable) => {
  enable = enable === undefined ? true : enable
  console.log('doSomeThing)
}
复制代码

es6 设置方式, 注意:默认值传参一定要从最后一个参数开始设置。

const foo = (enable = true) => {
  console.log('doSomeThing)
}
复制代码

剩余参数

ES6 中用 ...操作符来设置接收剩余参数。


const foo = (...args) => {
  console.log(args) // [1, 2, 3, 4]
}

const foo1 = (args1, ...args) => {
  console.log(args) // [2, 3, 4]
}

foo(1, 2, 3, 4)
foo1(1, 2, 3, 4)
复制代码

展开数组

ES6 中用 ...操作符来展开数组。

const arr = [1, 2, 3, 4]

// 依次打印出arr 的参数
// es5中的方法
console.log.apply(console, arr)

// 展开数组, 将数组中的每个成员依次展开到新的对象中
console.log(...arr)
复制代码

箭头函数

箭头函数不会改变 this 的指向;

对象字面量的增强

要添加的对象名与对象中的属性名一致时,只需要简写变量名即可:

const bar = 'foo';

const obj = {
  bar
}
复制代码

为对象添加属性方法时, 也可以直接用属性名跟方法体设置:

const obj = {
  method() {
    console.log('doSomeThing')
  }
}
复制代码

为对象添加动态属性名时,还可以使用 计算属性名, 语法: [activeKey]: value:

const obj = {
  [Math.random()]: value
}
复制代码

Proxy 对象代理

Proxy 可以监视 对象的源数据的任何修改, 使用 Proxy:

const person = {
  name: 'hello',
  age: 20
}

const personProxy = new Proxy(person, {
  get (target, property) {
    // doSomething
    return property in target ? target[property] : 'default'
  },
  set (target, property, value) {
    // doSomething
    target[property] = value
  }
})

// 使用
personProxy.gender = 'male'
复制代码

Proxy 对比 defineProperty

  • defineProperty 只能监视对象的读写, Proxy 能够见识到更多对象操作,例如 delete 操作或者方法的调用;

delete 方法监控:

const person = {
  name: 'hello',
  age: 20
}

const personProxy = new Proxy(person, {
  deleteProperty (target, property) {
    // doSomething
    delete target[property]
  }
})

//
delete personProxy.age
复制代码

其它属性: 见图

  • Proxy 更好的支持数组对象的监视;

监视数组:

const list = []

const listProxy = new Proxy(list, {
  set (target, property, value) {
    console.log('set', property, value)
    target[property] = value
    return true //  表示设置成功
  }
})

listProxy.push(100) // 'set' 0 100
复制代码
  • Proxy 是以非侵入的方式监管了对象的读写

defineProperty 需要单独定义被监视的属性,例如:

const person = {
  name: 'hello',
  age: 20
}

// 定义需要被监视的属性
Object.defineProperty(person, 'name', {
  get() {},
  set() {}
})
复制代码

而 Proxy 可以监管整个需要被监视的对象。

Reflect

Reflect 是一个静态类, 无法被实例化。内部封装了一系列对对象的底层操作。Reflect 成员方法就是 Proxy 处理对象的默认实现

const person = {
  name: 'hello',
  age: 20
}

const personProxy = new Proxy(person, {
  // 自定义get,用来处理自定义逻辑
  get(target, property) {
    // doSomeThing

    return Reflect.get(target, property)
  }
})
复制代码

Reflect 的意义在于,统一提供了一套用于操作对象的 API。例如:

const person = {
  name: 'hello',
  age: 20
}
console.log( 'name' in person)
console.log(delete person.name)
console.log(Object.keys(obj))
// ...

// Reflect 统一用法
console.log(Reflect.has(person, 'name'))
console.log(Reflect.deleteProperty(person, 'name'))
console.log(Reflect.ownKeys(obj))
// ...
复制代码

Reflect 目前提供了十三种底层的操作方法。见文档:

Set 数据结构

Set 与传统数组类似,是一个数据集合。

const s = new Set()

// add 方法返回实例本身,所以可以链式调用,set可以对元素去重;
s.add(1).add(2).add(3).add(1)

// 遍历
// forEach
// for of
// 获取数据长度
s.has()
//  删除
s.delete()
// 清空
s.clear()
复制代码

常见用法, 去重:

const arr = [1,2,3,4,3,2,1]

console.log(Array.from(new Set(arr)))
console.log([...new Set(arr)])
复制代码

Map 数据结构

Map 是一个键值对集合,用来映射两个任意数据类型对对应关系:

Map 对应的方法:

  • set
  • get
  • has
  • delete
  • clear
  • 遍历:forEach

Symbol

Symbol 用来表示一个独一无二的数据类型,通过 Symbol 函数创建的值永远不相等:

Symbol() === Symbol() // false

复制代码

Symbol 允许传入描述文本, 对 Symbol 值进行区分:

Symbol('1')
Symbol('2')
复制代码

Symbol 最主要作用就是为对象添加独一无二的属性名:

const name = Symbol()
const person = {
  [name]: 'test',
  say() {
    console.log(this.[name])
  }
}

// 无法直接通过Symbol 获取对象属性
person[Symbol()] // undefined
// 可以通过调用方法来实现读取
person.say() // test
复制代码

Symbol 提供了一个静态方法for, for 方法默认传入 String 变量,如果传入的是非字符串,则会隐式转换为字符串类型:

Symbol('foo') == Symbol('foo') // false
Symbol.for('foo') === Symbol.for('foo') // true
Symbol.for(true) === Symbol.for('true') // true
复制代码

Symbol 属性的用途 1: 为对象添加 toString 属性:

const obj = {}
console.log(obj.toString()) // [object, Object]

//
const objSymbol = {
  [Symbol.toStringTag]: 'XObject'
}

console.log(objSymbol.toString()) // [object, XObject]

复制代码

Symbol 作为对象的属性名,传统方法无法拿到此属性名, 例如:

const obj = {
  [Symbol()]: 'new Symbol',
  foo: 'test'
}

for(let key in obj) {
  console.log(key) // foo
}

console.log(Object.keys(obj)) // ['foo']

console.log(JSON.stringify(obj)) // ["foo": "test]

复制代码

以上的特性使得 Symbol 适合做对象的私有属性。如果要拿到对象的 Symbol 属性,可以使用Object.getOwnPropertySymbols

console.log(Object.getOwnPropertySymbols(obj))
复制代码
文章分类
前端
文章标签