zoukankan      html  css  js  c++  java
  • 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)
    
  • 相关阅读:
    lucene复合条件查询案例——查询name域 或 description域 包含lucene关键字的两种方式
    谈谈你对spring的理解?
    模拟Http请求的几种常用方式
    idea破解教程
    Pycharm 或者 idea 注册码 (亲测可用)
    超详细虚拟机工具和Centos7 Linux系统安装
    严重: Error loading WebappClassLoader context:异常的解决方法(转)
    spring cloud 笔记记录
    近一周学习之-----vue学习快乐之旅(1)
    近一周学习之-----vue开发工具visual studio code
  • 原文地址:https://www.cnblogs.com/Huskie-/p/14751441.html
Copyright © 2011-2022 走看看