ECMAScript总结

  • 在node环境下,可以使用一个小工具 nodemon来实现自动执行js文件

let、var、const

  • let是没有变量提升的,而var定义的,会被声明到代码最初
  • let是会创造一个块级作用域,每一个作用域中的同名变量都是不同的
  • const 是在let的基础上加了一个只读的特性,声明过后不允许再修改

结构赋值

数组

const arr = [1, 2, 3, 4]
const [a, b, c, d, e = 5] = arr
// 此时a, b, c, d四个变量按位置依次对应,没有对应位置的为undefiend,也可以赋默认值

对象

const obj = { name: '张三', age: 19 }
const { name } = obj
// 此时name变量为张三,也可以重命名,防止冲突
const { name: actName } = obj
// 此时actName变量值为张三

模板字符串

const name = 'tom'
const gender = true
const myTag = (strings, name, gender) => {
  const sex = gender ? 'man' : 'woman'
  return strings[0] + name + strings[1] + sex + strings[2]
}
const result = myTag`hey, ${name} is a ${gender}`
console.log(result)
  • 可以在模板字符串``前边定义一个函数作为模板来使用,可以处理比如一些true, false变汉字了等情况

新增的字符串方法

const message = 'Error: xxxxx.'
console.log(message.startsWith('Error'))
console.log(message.endsWith('.'));
console.log(message.includes('xx'))

startsWith

  • 检查字符串的开头是不是有参数中的内容

endsWith

  • 检查字符串的结尾是不是有参数中的内容

includes

  • 检查字符串中间是不是有参数中的内容

参数默认值

  • 有时候一个函数如果没有传参数进来的话,我们也需要一个默认值,此时可以直接在形参后面跟一个=赋值
const fn = (a, b = 'xxx') => {
  console.log(a, b)
}
fn(11)

另外注意: 赋默认值的形参一定要在参数的后边

剩余参数

  • 可以通过...展开的形式来获取到函数的所剩参数
function fn(a, ...args) {
  // 此时args是一个接收剩余参数的数组,如果括号中只有一个...args,那么args代表所有参数
  console.log(args)
}
fn(1, 2, 3, 4)

展开符

  • 可以把数组按顺序展开
const arr = [1, 2, 3, 4]
console.log(...arr)

对象字面量的增强

const bar = '123'
const obj = {
  name: 'xxx',
  // 如果是同名变量或者是函数,可以省略前面的
  bar,
  // 也可以使用方括号,在对象中放一些表达式
  [1 + 1]: 123
}

Object.assign

  • 合并对象,将后面的对象合并到第一个参数中,也就是目标对象,相同的会覆盖
  • 返回值是一个与目标对象相同的对象
const tar = { a: 1, b: 2 }
const obj = { a: 2, c: 3 }
const result = Object.assign(tar, obj)
console.log(tar) // 输出{ a: 2, b: 2, c: 3 }
console.log(result) // 输出{ a: 2, b: 2, c: 3 }

Object.is(不常用)

  • 判断两个是不是相等
  • 比如NAN和NAN,在===的情况下是不相等的
  • 在Object.is(NAN, NAN)的情况就是相等的

Proxy

  • 可以利用proxy(代理)的方式来给对象增加一个安保角色
  • Proxy接收两个参数,一个是目标处理对象,一个是有着get和set等监视函数的对象
const person = { name: '张三', age: 11 }
const personProxy = new Proxy(person, {
  // get接收两个参数,一个是目标对象,一个是get的属性名
  get(target, property) {
    // 如果get的属性在目标对象中,取出,不在返回默认值
    return property in target ? target[property] : 'default'
	},
  // set接收三个参数,一个是目标对象,一个是set的属性名,一个是set的属性值
  set(target, property, value) {
    // 也可以设定要set的属性值的一个规范要求
    if (property === 'age') {
      // Number.isInteger用来判断参数是不是整数,如果不是,throw(抛出)错误
      if (!Number.isInteger(value)) {
        throw new TypeError(`${value} is not a int`)
      }
    }
    target[property] = value
  }
})
console.log(personProxy.name) // 输出张三
console.log(personProxy.xxxx) // 输出default
personProxy.newProperty = '新的属性'
console.log(personProxy) // 输出{ name: '张三', age: 11, newProperty: '新的属性' }

Proxy对比defineProperty所存在的优势

    1. defineProperty只能监视属性的读写,而Proxy有着很多完善的对象操作
    • 例如deleteProperty
const person = { name: '张三', age: 11 }
const personProxy = new Proxy(target, {
  deleteProperty(target, property) {
    // 利用delete操作符
    delete target[property]
	}
})
delete personProxy.age
console.log(personProxy) // 输出 { name: '张三' }
    1. Proxy能够更好的支持数组对象的监视
const list = []
const listProxy = new Proxy(list, {
  set(target, property, value) {
    // property相等于下标
    console.log('set->', property, value)
    target[property] = value
    return true
  }
})
listProxy.push(1)
console.log(listProxy)
    1. Proxy以非侵入的方式监管了对象的读写

Reflect

  • Reflect是一个内置对象,提供一些拦截js对象的一些方法
  • 以往操作对象有的是用像in ,delete的操作符,有的是用Object.keys等的一些api方法,Reflect正是解决了这个问题,把两者进行了统一

class 继承

class Person{
  constructor(name) {
    this.name = name
  }
  say() {
    console.log(`${this.name} say hello`)
  }
}
const person = new Person('张三')
person.say()
class Students extends Person{
  // Students类继承Person类的name属性以及say方法
  constructor(name, code) {
    super(name)
    this.code = code
  }
  logCode() {
    console.log(this.code)
  }
}
const students = new Students('李四', 001)
students.say()
students.logCode()

Set集合

  • Set当中里面是没有重复的,最常用的是给数组去重
const arr = [1, 2, 3, 1, 3]
const result = Array.from(new Set(arr))
console.log(result) // 输出[1, 2, 3]

add(添加集合元素)

forEach(遍历集合)

for...of(同上)

size(集合长度)

has(判断集合中是否拥有这个元素)

delete(删除集合中的某个元素)

clear(清除集合内所以元素)

Map键值对

  • 在日常工作中,可能会遇到拿一个对象来做唯一键,此时如果放在对象里,我们取出来的键是[Object Object]
  • Map键值对就是来解决这个问题的,它可以将任何数据类型来作为键
const m = new Map()
const tom = { name: '张三' }
m.set(tom, 10) // 添加一条键值对
console.log(m) // 输出{ { name: '张三' } => 10 }
m.has() // 判断是否拥有参数键
m.delete() // 删除参数键
m.clear() // 清除这个键值对Map
m.forEach((val, key) => console.log(val, key))

Symbol

  • 唯一符号,多用来为对象添加一个独一无二的属性名
console.log(Symbol('foo') === Symbol('foo')) // 因为Symbol返回的独一无二的,所以为false
console.log(Symbol.for('foo') === Symbol.for('foo')) // Symbol的for方法就是传入相同的字符串,返回相同的Symbol,任何参数都会转成字符串
  • 对象的toString标签
const obj = {}
console.log(obj.toString()) // 输出[object Object]

为了不与对象的内置属性重名,所以js规定用Symbol来自定义toString标签

const obj = {
  [Symbol.toStringTag]: 'XObject'
}
console.log(obj.toString()) // 输出[object XObject]
  • 遍历和取键
    • 像Object.keys了,for...in...了,都是只取普通属性
    • 可以通过Object.getOwnPropertySymbols(obj)来取Symbol属性
  • 所以Symbol非常适合做对象的私有属性

for...of...

  • 可以遍历所有的数据类型

  • 举例1

const m = new Map()
m.set('aaa', 111)
m.set('bbb', 222)
for(let i of m) {
  console.log(i) // 输出的是['aaa', 1], ['bbb', 222]
}
// 所以我们可以通过解构的方式
for (let [key, val] of m) {
  // 拿到key 和 val
}

迭代器模式

const obj = {
  work: ['撸代码', '画画', '搬砖'],
  life: ['吃饭', '睡觉', '打豆豆']
}
// 如果我们要拿到这里面数组所有数据,只能通过分别取出work,life的方式
for (let i of obj.work){}
for(let i of obj.life){}
  • 这样的问题,代码耦合太高,上面改了,下面也得改,所以可以添加一个each方法
const obj = {
  work: ['撸代码', '画画', '搬砖'],
  life: ['吃饭', '睡觉', '打豆豆'],
  each: function(callback) {
    // 统一在这边处理
    const all = [...this.work, ...this.life]
    for (let i of all) { callback(i) }
	}
}
obj.each((i) => console.log(i)) // 这样就拿到所有数据了

不过这样,还是存在着要根据情况来实现的这么一个弊端

  • 所以,迭代器模式的出现,就解决了这么一个问题

Iterable(可迭代接口)

​ for...of...是可以遍历所有数据类型的,我们通过观察数组了,Set了,Map了,他们都有一个公共的Symbol.iterator方法

​ 同时这个方法的执行结果是一个有着next方法的对象,可以返回一个对象{ value: xx, done: false }

​ 当数据全部输出一遍以后,返回{ value: undefined, done: true }

  • 这也是对象无法直接使用for...of...的原因,所以我们可以手动写入一个Symbol.iterator方法
const obj = {
  work: ['撸代码', '画画', '搬砖'],
  life: ['吃饭', '睡觉', '打豆豆'],
  [Symbol.iterator]: function() {
    const all = [...this.work, ...this.life]
    let index = 0
    return {
      next: function() {
        return { value: all[index], done: index++ >= all.length }
      }
    }
  }
}
for (let i of obj) {
  console.log(i)
}

生成器Generator

function * createGenerator() {
	yield 100
}
console.log(createGenerator().next()) // 输出{ value: 100, done: false }
  • 可以通过yield关键字来实现函数的惰性执行,它会将函数暂停下来,调用一次next()方法,便继续执行,并且把yiled的值返回过去

  • 箭头函数暂无生成器写法

  • 案例1 --发号器

function *createIdMaker(){
  let id = 1
  while(true) {
    yield id++
  }
}
// 在这里将createIdMaker()存到执行栈,不会被执行立即被弹出
const idMaker = createIdMaker()
for(let i = 0; i < 10; i++){
  console.log(idMaker.next())
}
  • 案例二 -- 可以简化迭代器函数
const obj = {
  work: ['撸代码', '画画', '搬砖'],
  life: ['吃饭', '睡觉', '打豆豆'],
  [Symbol.iterator]: function *() {
    const all = [...this.work, ...this.life]
    for (let i of all) yield i
  }
}

includes

  • 在之前的版本,如果要查找一个元素在不在数组中,用的是arr.indexOf()来判断返回的是不是-1,但是这样,如果要判断的元素是NAN的话,就算是有,也返回-1
  • 所以就可以直接用arr.includes(),直接返回true或者false

指数运算符

  • 之前是通过Math.pow(2, 10) 来算2的10次方
  • 现在可以通过两个乘法运算符来直接写指数运算了
console.log(2 ** 10) // 输出1024

ES2017

Object.values

const obj = { name: '张三', age: 16 }
console.log(Object.values(obj)) // 输出[ '张三', 16 ]

Object.entries和Object.fromEntries

// 大家熟悉的Object.entries()是把一个对象变成一个自身的键值对数组 例如:
const a = { name: '张三', age: 16 }
console.log(Object.entries(a)) // 得到[['name', '张三'], ['age', 16]]
// Object.fromEntries()则与Object.entries()相反,是把键值对数组转成自身对象 例如:
const a = [['name', '张三'], ['age', 16]]
console.log(Object.fromEntries(a)) // 得到{ name: '张三', age: 16 }

Object.getOwnPropertyDescriptors和Object.defineProperties

const o1 = {
  name: 'xxx',
  val: 'bbb',
  // es2015新增的get方法和set方法
  get label() {
    return this.name + ' ' + this.val
  }
}
console.log(o1.label)
let o2 = Object.assign({}, o1)
o2.val = 'qqq'
console.log(o2.label) // 此时输出的还是xxx bbb
// 因为Object.assign没有复制到get和set属性,所以要复制的话需要用到下面这俩
const descriptors = Object.getOwnPropertyDescriptors(o1)
const o2 = Object.defineProperties({}, descriptors)
o2.val = 'www'
console.log(o2.label)
posted on 2021-05-10 16:01  Huskie!  阅读(74)  评论(0编辑  收藏  举报