es6巩固

173 阅读4分钟
  • let不会导致变量提升
    let 声明的变量不属于window属性
    let 可以解决重复定义的问题, var 可以被重复声明
    let 会存在暂时性死区
    
  • const 常量(地址不变即可)
    
  • // ... 展开运算符
    运用于对象数组
    
  • 深拷贝、浅拷贝
    1、...只能拷贝一层
    2Object.assign 等价于 ...
    3Json.parse(Json.Stringify())。 缺陷: 不能转换: 函数、正则, undefined。。。 会自动过滤
    4、自己实现深拷贝的方法:(递归)
    

    自己实现深拷贝的方法:(递归)

    // 掌握类型判断 typeof instanceof Object.prototype.toString.call constructor
    function deepClone(obj, hash = new WeakMap ()) { // 增加hash解决循环遍历的问题
        // 判断obj是null还是undefined
        if (obj) return obj
        if (obj instanceof Date) return new Date(obj)
        if (obj instanceof RegExp) return new RegExp(obj)
        // 不是obj直接return
        if (typeof obj !== 'object') return obj
        if (hash.has(obj)) return hash.get(obj) // 如果weakmap中有对象就直接返回
        // 判断是否是数组
        // Object.prototype.toString.call(obj) === ['Object Array'] ? [] : {}
        let clone = new obj.constructor
        // 如果是对象放到weakMap中, 如果在拷贝这个对象 这个对象就存在了 直接返回这个对象即可
        hash.set(obj, clone)
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
               clone[key] = deepClone(obj[key], hash)
            }
        }
        return clone
    }
    
  • set、map
    set 可添加删除,并且没有顺序
    set 并集、交集、差集
    map 是有key的, 不能放重复的
    WeakMap 的key 必须是对象类型
    WeakMap 不会占用空间 会销毁
    map会占用空间
    
  • Object.defineProperty (es5):
    Object.defineProperty 不支持数组的更新
    Object.defineProperty 只能用在对象上, 数组也不识别
    vue 的数据劫持 (把所有的属性都改成 getset 方法)
    通过Object.defineProperty定义的属性 可以增加拦截器,默认是隐藏属性,不可枚举
    
       // vue 的数据劫持 (把所有的属性都改成 get 和set 方法)
       function update () {
           console.log('更新视图')
       }
       function observer (obj) {
           if (typeof obj !== 'object') return obj
           for (let key in obj) {
              defineReactive(obj, key, obj[key])
           }
       }
       function defineReactive (obj, key, value) {
           observer(value)
           Object.defineProperty(obj, key, {
               get () {
                   return value
               },
               set (val) {
                   if (val !== value) {
                       observer(val) // 检测新值
                       update() // 更新视图
                       value = val
                   }
               }
           })
       }
       observer(date)
       let methods = ['push', 'slice', 'pop', 'sort', 'reverse', 'unshift'] // 重写这几个方法,并加上自己的逻辑
       methods.forEach(method => {
           // 面向切面开发 装饰器: 在原有的基础上加上自己的逻辑
           let oldMethod = Array.prototype[method]
           Array.prototype[method] = function () {
               update()
               oldMethod.call(this, ...arguments)
           }
       })
       Vue.prototype.$set = function(obj, key, callback) {
           Object.defineProperty(obj, key,{
               get: callback
           })
       }
    
    let obj = {}
    Object.defineProperty(obj, 'name', {
        enumerable: true,
        configurable: true, // 能否删除此属性
        writable: true, // 是否可以重写
        // 拦截器
        get () {
            return 123
        },
        set () {
        }
    })
    
  •  箭头函数
     没有this, 没有arguments
     
    
        let a = 1
        let obj = {
          a: 2,
          fn: function () { // this = obj
            setTimeout(() => {
              console.log(this.a) // 2
            })
          }
        }
        obj.fn()
        ////////////////////////////
        let a = 1
        let obj = {
          a: 2,
          fn: () => { // this = obj
            setTimeout(() => {
              console.log(this.a) // undefined
            })
          }
        }
        obj.fn()
    
  •    js 中有this的情况
       1、 { let ...} // 花括号配合着let
       2、全局作用域
       3、 函数作用域
       
    
  •    proxy 数据劫持
    
        // 希望数组变化时就能更新视图
        function update() {
            console.log('更新视图')
        }
        let arr = [1,2,3]
        // proxy 要与 Reflect配合使用
        let proxy = new Proxy(arr, {
            set (target, key, value) {
                // 不要手动操作原数组, 因为数组变化时可能会调用push、pop方法, 此时key就会出现问题
                if (key === 'length') return true
                return Reflect.set(target, key, value) // 成功返回true 失败返回false
            },
            get (target, key) {
                return Reflect.get(target,key)
            }
        }
    
  • 数组的方法 : 
     es5( forEach, reduce, map, filter, some, every)
     es6 (find, findIndex)
     es7(includes)
     reduce 收敛
     
    
    // reduce 收敛
    let r = [1,2,3,4,5].reduce((a, b) => {
        return a+b
    })
    console.log(r) // 15
    let keys = ['name', 'age']
    let values = ['yx', 18]
    let obj =  keys.reduce((a, b, index, current) =>{
        a[b] = values[index]
        return a
    },{})
    console.log(obj)
    ///////////
    let keys = ['name', 'age']
    let values = ['yx', 18]
    let obj =  keys.reduce((a, b, index, current) =>(a[b] = values[index], a),{}) // 逗号运算符:只返回最后一项
    console.log(obj)
    
  • compose方法(组合多个函数)

    function sum (a,b) {
        return a+b
    }
    function toUpper (str) {
        return str.toUpperCase()
    }
    function add (str) {
        return `***${str}***`
    }
    // 第一种写法
    function compose (...fns) {
        return function (...args) {
            // 获取最后一个函数
            let lastFn = fns.pop()
            // 倒着执行
            return fns.reduceRight((a, b) => { // fns中的函数从右向左执行
                return b(a)
            }, lastFn(...args))
            
        }
    }
    // 第二种写法
    function compose(...fns) {
        return fns.reduce((a, b) => {
            return (...args) => {
                return a(b(...args))
            }
        })
    }
  • es6中的类
    1. 了解构造函数的属性

      属性分为两种 实例上的属性 公有属性

        function Animal (name) {
            this.name = name
            this.arr = [1,2,3]
        }
        Animal.prototype.address = { location: 'ali'}
        let a1 = new Animal('猴子')
        let a2 = new Animal('小鸡')
        console.log(a1.arr === a2.arr) // false
        console.log(a1.address === a2.address) // true
        // 每个实例都有一个__proto__指向所属类的原型
        console.log(a1.__proto__ === Animal.prototype) // true
        console.log(a1.prototype === Animal) // true
        console.log(Animal.__proto__ === Function.prototype) // true
        console.log(a1_proto__.__proto__=== Object.prototype) // true
        console.log(Object.prototype=== null) // true
    
    1. 类的继承
       // es5的写法
      function Animal (name) {
        this.name = name
        this.eat = '吃肉'
      }
      Animal.prototype.address = { location: 'ali'}
      function Tiger (name) {
          this.name = name
          this.age = 10
          Animal.call(this) // Tiger继承Animal实例上的属性
      }
       // 继承父类的公共属性或方法
      // 思路:先找自己原型上的属性,没有再去找父类身上的属性
      // 方法一、
      Tiger.prototype.__proto__ = Animal.prototype
      // 方法二
      Tiger.prototype = Object.create(Animal.prototype)
      
      Tiger.prototype.say = function () {
          console.log('说话')
      }
      // 继承父类实例上的属性
      let tiger = new Tiger()
      console.log(tiger.eat)
      
// es6写法
class Animal {
    static flag = 123 // es6 不支持这种写法, es7支持
    // 可改造成. es6 不支持静态属性, 只支持静态方法
    static flag () {
        return 123
    }
    constructor (name) {
        this.name =name
        this.eat = '吃肉'
    }
    say () {
        console.log('say', this) // es6规范里: 如果单独调用原型上的方法 this是不存在的
    }
}
// 类不能当做函数调用
let animal = new Animal()
animal.say()
// 错误写法
// let say = animal.say
// say()

// 继承
class Tiger extends Animal { // 实例+原型

}
let tiger = new Tiger('王老虎')
console.log(Tiger.flag()) // 静态方法可以被继承
  • es6中的装饰器 npx是node 5.2以上版本提供的,帮助我们执行.bin目录下的文件

@babel/core babel的核心包 主要用于代码转化

@babel/preset-env es6转换器(只能转化es6已定案的标准)

@babel/plugin-proposal-class-properties 主要的作用是用来转化类的属性

装饰器可以修饰类,包括类的属性 类的原型上的方法。修饰的时候,就是 把这个类 属性... 传递给修饰的函数

装饰器的写法:@

@flag
class Animal {
    @readonly
    name = 'xxx'
    @before
    say (a, b, c) {
        console.log('说话', a, b, c)
    }
}
function flag (constructor) {
    constructor.type = 'aaa'
}
// 装饰属性
function readonly (target, property, descriptor) {
    descriptor.writable = false
}
// 装饰方法
function before (target, property, descriptor) {
    let oldSay = descriptor.value
    descriptor.value = function () {
        console.log('before')
        oldSay.call(target)
    }
}