• ③ ES6 新特性


    1 面向过程与面向对象

    1.1 冰箱装大象

    • js是一种基于对象(object-based)的语言

    1.2 类与对象

    • 类是对象的模板,定义了同一组对象共有的属性和方法

    2 ES5中的类与继承

    2.1 类

    1. 如何定义类

    • 属性定义在类上

    • 方法定义在原型上

    function People(name, age) {
      this.name = name
      this.age = age
    }
    
    People.prototype.showName = function() {
      console.log('我的名字是' + this.name);
    }
    
    let p1 = new People('zhouzhou', 12)
    console.log(p1);
    p1.showName()
    
    let p2 = new People('zhangsan', 18)
    console.log(p2);
    p2.showName()
    

    2. 如何定义实例属性 实例方法 静态属性 静态方法

    • 静态属性 静态方法:定义在类上

    • 实例属性:定义在构造函数上

    • 实例方法:定义在类的原型对象上

    function People(name, age) {
      console.log('this', this); // 指向实例对象
      // 实例属性:定义在构造函数上
      this.name = name
      this.age = age
      People.count++
    }
    // 静态属性:定义在类上
    People.count = 0
    // 静态方法
    People.getCount = function() {
      console.log('People.count--this', this); // 指向当前构造函数
      console.log('当前共有' + People.count + '个人');
    }
    
    // 实例方法
    People.prototype.showName = function() {
      console.log('我的名字是' + this.name);
    }
    
    let p1 = new People('zhouzhou', 12)
    console.log(p1);
    p1.showName()
    
    let p2 = new People('zhangsan', 18)
    console.log(p2);
    p2.showName()
    
    console.log(People.count);
    People.getCount()
    
    // 静态方法
    Math.max(4, 5)
    Math.random()
    

    2.2 继承

    // 父类
    function Animal(name) {
      this.name = name
    }
    Animal.prototype.showName = function() {
      console.log('名字是:' + this.name);
    }
    

    1. 构造函数继承

    继承属性

    // 子类
    function Dog(name, color) {
      Animal.call(this, name) // 继承属性
      this.color = color
    }
    
    let d1 = new Dog('fulai', 'white')
    console.log(d1);
    d1.showName()
    

    2. 原型继承

    继承方法

    // 子类
    function Dog(name, color) {
      this.color = color
    }
    // 继承方法
    Dog.prototype = new Animal()
    Dog.prototype.constructor = Dog
    
    let d1 = new Dog('fulai', 'white')
    console.log(d1);
    d1.showName()
    

    3. 组合继承

    • 继承属性 -- 构造函数继承

    • 继承方法 -- 原型继承

    // 子类
    function Dog(name, color) {
      Animal.call(this, name) // 继承属性 -- 构造函数继承
      this.color = color
    }
    // 继承方法 -- 原型继承
    Dog.prototype = new Animal()
    Dog.prototype.constructor = Dog
    
    let d1 = new Dog('fulai', 'white')
    console.log(d1);
    d1.showName()
    

    3 ES6中的类与继承

    3.1 定义类

    1. class -- 语法糖

    class People {
      constructor(name, age) {
        this.name = name
        this.age = age
      }
      showName() {
        console.log(this.name);
      }
    }
    let p1 = new People('zhouzhou', 12)
    console.log(p1);
    

    2. 定义最顶层属性

    • 通过 get set 定义最顶层属性
    class People {
      constructor(name, age) {
        this.name = name
        this.age = age
        this._sex = -1
      }
    
      get sex() {
        return this._sex
      }
      set sex(val) {
        // this.sex = val // 死循环
        this._sex = val
      }
      showName() {
        console.log(this.name);
      }
    }
    let p1 = new People('zhouzhou', 12)
    
    p1.sex = 1
    console.log(p1.sex);
    
    为什么定义顶层属性:解决业务需求操作(可以对属性的读写做拦截操作)
    class People {
      constructor(name, age) {
        this.name = name
        this.age = age
        this._sex = -1
      }
    
      get sex() {
        if(this._sex === 1) {
          return 'male'
        } else if(this._sex === 0) {
          return 'female'
        } else {
          return 'error'
        }
      }
      set sex(val) { // 1 male 0 female
        if(val === 0 || val === 1) {
          this._sex = val
        }
      }
      showName() {
        console.log(this.name);
      }
    }
    let p1 = new People('zhouzhou', 12)
    
    // p1.sex = 1
    // p1.sex = 0
    
    console.log(p1.sex);
    

    3. 定义静态方法

    es6明确规定,class 中没有静态属性

    因为 typeof 类function, 所以可以像 es5 一样定义静态属性

    • static 定义静态方法

    • 静态方法能被子类继承,但不能在实例上调用

    class People {
      constructor(name, age) {
        this.name = name
        this.age = age
        this._sex = -1
      }
      // 静态方法
      static getCount() {
        return 5
      }
    }
    // 静态属性
    People.count = 9
    console.log(People.count); // 9
    console.log(typeof People); // function
    console.log(People.getCount()); // 5
    
    class Coder extends People {
      constructor(name, age, company) {
        super(name, age) // 继承父类属性
        this.company = company
      }
    }
    console.log(Coder.getCount());
    

    3.2 继承

    • extends 实现继承

    • super 继承超类属性

    class People {
      constructor(name, age) {
        this.name = name
        this.age = age
      }
      showName() {
        console.log(this.name);
      }
    }
    let p1 = new People('zhouzhou', 12)
    console.log(p1);
    
    class Coder extends People {
      constructor(name, age, company) {
        super(name, age) // 继承父类属性
        this.company = company
      }
      showCompany() {
        console.log(this.company);
      }
    }
    let c1 = new Coder('zhangsan', 12, 'imooc')
    console.log(c1);
    c1.showName()
    

    4 新的原始数据类型 Symbol

    • 一种新的原始数据类型

    4.1 声明方式

    1. 直接声明

    let s1 = Symbol()
    let s2 = Symbol()
    console.log(s1);
    console.log(s2);
    console.log(s1 === s2); // false
    

    2. 字符串作为参数 -- 作为描述 description

    let s1 = Symbol('foo')
    let s2 = Symbol('foo')
    console.log(s1);
    console.log(s2);
    console.log(s1 === s2); // false
    

    3. 对象作为参数 -- 作为描述 description

    const obj = {
      name: 'imooc',
      toString() {
        return this.name
      }
    }
    let s = Symbol(obj)
    console.log(s);
    

    4. 通过 for() 声明

    let s1 = Symbol.for('foo')
    let s2 = Symbol.for('foo')
    console.log(s1 === s2); // true
    
    • 通过 for() 声明的变量是全局环境下的
    function foo() {
      return Symbol.for('foo')
    }
    const x = foo()
    const y = Symbol.for('foo')
    console.log(x === y);
    
    • Symbol.keyFor() 检测当前变量是否全局登记过
    const s1 = Symbol('foo')
    console.log(Symbol.keyFor(s1)); // undefined
    
    const s2 = Symbol.for('foo')
    console.log(Symbol.keyFor(s2)); // foo
    

    4.2 应用场景

    1. 避免属性名覆盖

    const stu1 = '李四'
    const stu2 = '李四'
    const grade = {
      [stu1]: { address: 'yyy', tel: '222' },
      [stu2]: { address: 'zzz', tel: '333' },
    }
    console.log(grade); // grade = { '李四': { address: 'zzz', tel: '333' } }
    
    const stu1 = Symbol('李四')
    const stu2 = Symbol('李四')
    const grade = {
      [stu1]: { address: 'yyy', tel: '222' },
      [stu2]: { address: 'zzz', tel: '333' },
    }
    console.log(grade);
    

    2. 消除魔术字符串

    const shapeType = {
      triangle: Symbol(),
      circle: Symbol()
    }
    function getArea(shape) {
      let area = 0
      switch(shape) {
        case shapeType.triangle:
          area = 1
          break
        case shapeType.circle:
          area = 2
          break
      }
      return area
    }
    console.log(getArea(shapeType.triangle));
    console.log(getArea(shapeType.circle));
    

    4.3 遍历对象

    1. for..in 无法遍历到 Symbol 属性
    for(let key in user) {
      console.log(key);
    }
    
    1. for..of + Object.keys() 无法遍历到 Symbol 属性
    for(let key of Object.keys(user)) {
      console.log(key);
    }
    
    1. for..of + Object.getOwnPropertySymbols() 只能遍历到 Symbol 属性
    for(let key of Object.getOwnPropertySymbols(user)) {
      console.log(key);
    }
    
    1. for..of + Reflect.ownKeys() 能遍历到普通属性 + Symbol 属性
    for(let key of Reflect.ownKeys(user)) {
      console.log(key);
    }
    

    5 新的数据结构 Set

    5.1 定义及操作方法

    • set 成员值唯一
    let s = new Set([1, 2, 3, 2])
    console.log(s); // { 1, 2, 3}
    s.add('imooc').add('es')
    s.delete(2)
    // s.clear()
    console.log(s.has('imooc')); // true
    console.log(s.has('imooc1')); // false
    console.log(s.size); // 4
    

    5.2 遍历

    s.forEach(item => console.log(item))
    
    for(let item of s) {
      console.log(item);
    }
    
    for(let item of s.keys()) {
      console.log(item);
    }
    
    for(let item of s.values()) {
      console.log(item);
    }
    
    // key跟value同名
    for(let item of s.entries()) {
      console.log(item, item[0], item[1]);
    }
    

    5.3 应用场景

    1. 数组去重

    let arr = [1, 2, 3, 4, 2, 3]
    let s = [...new Set(arr)]
    

    2. 合并去重

    let arr1 = [1, 2, 3, 4]
    let arr2 = [2, 3, 4, 5, 6]
    // let s = [...new Set([...arr1, ...arr2])]
    let s = Array.from(new Set([...arr1, ...arr2]))
    

    3. 交集

    let arr1 = [1, 2, 3, 4]
    let arr2 = [2, 3, 4, 5, 6]
    let s1 = new Set(arr1)
    let s2 = new Set(arr2)
    let res = [...new Set(arr1.filter(item => s2.has(item)))]
    

    4. 差集

    let arr1 = [1, 2, 3, 4]
    let arr2 = [2, 3, 4, 5, 6]
    let s1 = new Set(arr1)
    let s2 = new Set(arr2)
    let arr3 = new Set(arr1.filter(item => !s2.has(item)))
    let arr4 = new Set(arr2.filter(item => !s1.has(item)))
    

    5.4 WeakSet

    • WeakSet 只能添加对象

    1. 定义及操作方法

    let ws = new WeakSet()
    const obj1 = { name: 'imooc' }
    const obj2 = { age: 5 }
    ws.add(obj1)
    ws.add(obj2)
    ws.delete(obj1)
    console.log(ws); // WeakSet {{age: 5}}
    console.log(ws.has(obj2)); // true
    

    2. 不能遍历

    3. 垃圾回收机制(GC)

    垃圾回收机制 GC +1 +1

    • WeakSet 弱引用,对 WeakSet 的引用不会被记录到垃圾回收机制

    6 新的数据结构 Map

    6.1 定义及操作

    let m = new Map()
    let obj = {
      name: 'imooc'
    }
    m.set(obj, 'es')
    console.log(m); // Map {Object => "es"}
    console.log(m.get(obj)); // true
    m.delete(obj)
    console.log(m); // Map size: 0
    
    let map = new Map([
      ['name', 'imooc'],
      ['age', 5]
    ])
    console.log(map); // Map(2) {'name' => 'imooc', 'age' => 5}
    map.set('name', 'zhangsan')
    console.log(map); // Map(2) {'name' => 'zhangsan', 'age' => 5}
    

    6.2 遍历

    map.forEach((value, key) => console.log(value, key))
    for(let [key, value] of map) {
      console.log(key, value);
    }
    for(let key of map.keys()) {
      console.log(key);
    }
    for(let value of map.values()) {
      console.log(value);
    }
    for(let [key, value] of map.entries()) {
      console.log(key, value);
    }
    

    6.3 WeakMap

    • WeakMap 键名只能是引用数据类型

    1. 定义及操作方法

    let wm = new WeakMap()
    wm.set([1], 2)
    wm.set({ name: 'imooc' }, 'es')
    console.log(wm);
    

    2. 不支持 delete 和遍历

    3. 垃圾回收机制(GC)

    垃圾回收机制 GC +1 +1

    • WeakMap 弱引用,对 WeakMap 的引用不会被记录到垃圾回收机制

    7 字符串的扩展

    7.1 unicode

    // unicode
    // es6 \uxxxx 码点 0000~ffff
    // \u20bb7 -> \u20bb+7
    // \u{20bb7}
    // \u{41} -> A
    
    console.log('\z' === 'z'); // true
    console.log('\172' === 'z'); // true
    // \HHH (8进制数)
    console.log('\172'.toString() === 'z'); // true
    // \xHH (16进制数)
    console.log('\x7A' === 'z'); // true
    console.log('\u007A' === 'z'); // true
    console.log('\u{7A}' === 'z'); // true
    

    7.2 模板字符串

    1. es5

    const isLargeScreen = () => {
      return true
    }
    let class1 = 'icon'
    class1 += isLargeScreen() ? ' icon-big' : ' icon-small'
    

    2. es6

    const isLargeScreen = () => {
      return true
    }
    const class2 = `icon icon-${isLargeScreen() ? 'big' : 'small'}`
    

    7.3 带标签的模板字符串

    const foo = (a,b,c,d) => {
      // raw:原始字符串
      console.log(a); // ['这是', ',他的年龄是', '岁', raw: Array(3)]
      console.log(b); // zhouzou
      console.log(c); // 12
      console.log(d); // undefined
    }
    const name = 'zhouzou'
    const age = 12
    foo`这是${name},他的年龄是${age}岁`
    

    7.4 String.fromCodePoint(unicode)

    • 增加码点范围
    String.fromCharCode(0x20bb7) // es5 ஷ fromCharCode只能识别6位数
    String.fromCodePoint(0x20bb7) // es6 
    

    7.5 常见方法

    const str = 'imooc'
    str.indexOf('mo'); // 1
    str.includes('mo'); // true
    str.startsWith('im'); // true
    str.endsWith('mooc'); // true
    const newStr = str.repeat(10)
    

    8 正则表达式的扩展

    • es5:i(忽略大小写) m(多行匹配) g(全局匹配)

    8.1 y 修饰符 -- 粘连修饰符

    const str = 'aaa_aa_a'
    const reg1 = /a+/g // 每次匹配剩余的
    const reg2 = /a+/y // 剩余的第一个开始匹配
    
    console.log(reg1.exec(str)); // ["aaa", ...]
    console.log(reg2.exec(str)); // ["aaa", ...]
    
    // 剩余的'_aa_a'匹配
    console.log(reg1.exec(str)); // ["aa", ...]
    console.log(reg2.exec(str)); // null
    
    console.log(reg1.exec(str)); // ["a", ...]
    console.log(reg2.exec(str)); // ["aaa", ...]
    

    8.2 u 修饰符 -- unicode

    • \u0000~\uffff
    const str = '\uD842\uDFB7' // 表示一个字符
    console.log(/^\uD842/.test(str)); // true es5
    console.log(/^\uD842/u.test(str)); // false es6
    
    // . 除换行符外的任意单个字符
    console.log(/^.$/.test(str)); // false
    console.log(/^.$/u.test(str)); // true
    
    console.log(/\u{61}/.test('a')); // false
    console.log(/\u{61}/u.test('a')); // true
    
    console.log(/{2}/.test('')); // false
    console.log(/{2}/u.test('')); // true
    

    9 数值的扩展

    9.1 进制数转换

    1. 十进制 -> 二进制

    • toString(2)
    const a = 5
    console.log(a.toString(2)); // 101
    

    2. 二进制 -> 十进制

    • parseInt(num, 2)
    const b = 101
    console.log(parseInt(b, 2)); // 5
    

    9.2 进制数前缀

    • 0B 二进制 0O 八进制
    const a = 0B0101
    console.log(a); // 5
    
    const b = 0O777
    console.log(b); // 511
    

    9.3 Number.isFinite()

    • 只对数字进行判断,非数字的字符类型都是 false
    console.log(Number.isFinite(5)); // true
    console.log(Number.isFinite(0.5)); // true
    console.log(Number.isFinite(Infinity)); // false
    console.log(Number.isFinite('imooc')); // false
    console.log(Number.isFinite(true)); // false
    

    9.4 Number.isNaN()

    // NaN: Not a Number
    console.log(Number.isNaN(NaN)); // true
    console.log(Number.isNaN(15)); // false
    

    9.5 Number.parseInt() Number.parseFloat()

    console.log(Number.parseInt(5.5)); // 5
    console.log(window.parseInt(5.5)); // 5
    console.log(Number.parseFloat(5.5)); // 5.5
    console.log(window.parseFloat(5.5)); // 5.5
    

    9.6 Number.isInteger()

    console.log(Number.isInteger(5)); // true
    console.log(Number.isInteger(5.5)); // false
    

    9.7 0.1 + 0.2 !== 0.3

    • 当前 0.1 转为二进制数被存储在电脑时,会有精度缺失(实际上存储的是近似值)

    IEEE754 双精度标准 -- 存储数字的方法

    • 35 -> 00100011
    • 0.375 -> 0.011
    • 0.1 -> 0.000110011....
    console.log(0.1000000000000001);
    console.log(0.10000000000000001);
    console.log(0.10000000000000001 === 0.1); // true
    

    9.8 Math 新增方法

    1. 数值的最大值 Number.MAX_SAFE_INTEGER 最小值 MIN_SAFE_INTEGER

    • Math.pow(2, 53)
    • Math.pow(-2, 53)
    const max = Math.pow(2, 53)
    console.log(max); // 9007199254740992
    console.log(max+1); // 9007199254740992
    console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
    console.log(Number.MAX_SAFE_INTEGER === max-1);
    console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991
    console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER+1)); // false
    

    2. Math.trunc()

    • 去除小数部分保留整数
    console.log(Math.trunc(5.5)); // 5 
    console.log(Math.trunc(-5.5)); // -5 
    console.log(Math.trunc(true)); // 1 
    console.log(Math.trunc(false)); // 0 
    console.log(Math.trunc(NaN)); // NaN
    console.log(Math.trunc(undefined)); // NaN
    
    console.log(Number.parseInt(5.5)); // 5
    console.log(Number.parseInt(-5.5)); // -5
    console.log(Number.parseInt(true)); // NaN
    

    3. Math.sign()

    • 判断当前数值是正数 负数 还是0
    console.log(Math.sign(5)); // 1
    console.log(Math.sign(-5)); // -1
    console.log(Math.sign(0)); // 0
    console.log(Math.sign(NaN)); // NaN
    console.log(Math.sign(true)); // 1
    console.log(Math.sign(false)); // 0
    

    4. Math.cbrt()

    • 计算一个数值的立方根
    console.log(Math.cbrt(8)); // 2
    console.log(Math.cbrt('imooc')); // NaN
    

    10 代理 Proxy

    10.1 实现代理

    1. ES5

    let obj = {}
    let newVal = ''
    Object.defineProperty(obj, 'name', {
      get() {
        return newVal
      },
      set(val) {
        newVal = val
      }
    })
    obj.name = 'es'
    console.log(obj);
    

    2. ES6

    // ES6 Proxy
    let obj = {}
    let p = new Proxy(obj, {})
    p.name = 'imooc'
    console.log(p.name); // imooc
    for(let key in obj) {
      console.log(key);
    }
    

    10.2 使用 Proxy 实现操作拦截

    // _password 是私有属性 不允许访问和修改
    let user = {
      name: 'zouzou',
      age: 12,
      _password: '***'
    }
    

    1. get 拦截对象属性的读取

    user = new Proxy(user, {
      get(target, prop) {
        if(prop.startsWith('_')) {
          throw new Error('不可访问')
        } else {
          return target[prop]
        }
      }
    })
    console.log(user.age);
    try {
      console.log(user._password);
    } catch(e) {
      console.log(e.message);
    }
    

    2. set 拦截对象属性的设置

    • 返回一个布尔值
    user = new Proxy(user, {
      get(target, prop) {
        if(prop.startsWith('_')) {
          throw new Error('不可访问')
        } else {
          return target[prop]
        }
      },
      set(target, prop, val) {
        if(prop.startsWith('_')) {
          throw new Error('不可访问')
        } else {
          target[prop] = val
          return true
        }
      }
    })
    user.age = 18
    console.log(user.age);
    try {
      user._password = 'xxx'
    } catch(e) {
      console.log(e.message);
    }
    

    3. has 拦截 propKey in proxy 的操作

    • 返回一个布尔值
    let range = {
      start: 1,
      end: 5
    }
    range = new Proxy(range, {
      has(target, prop) {
        return prop >= target.start && prop <= target.end
      }
    })
    console.log(2 in range);
    

    4. deleteProperty 拦截对象属性的删除

    • 返回一个布尔值
    user = new Proxy(user, {
      get(target, prop) {
        if(prop.startsWith('_')) {
          throw new Error('不可访问')
        } else {
          return target[prop]
        }
      },
      deleteProperty(target, prop) {
        // 拦截删除
        if(prop.startsWith('_')) {
          throw new Error('不可删除')
        } else {
          delete target[prop]
          return true
        }
      }
    })
    try {
      // delete user.age
      delete user._password
    } catch(e) {
      console.log(e.message); 
    }
    console.log(user.age);
    

    5. ownKeys 遍历拦截

    • 对当前对象的遍历方法进行拦截操作
    1. Object.getOwnPropertyNames()
    2. Object.getOwnPropertySymbols()
    3. Object.keys()
    4. for..in..
    user = new Proxy(user, {
      ownKeys(target) {
        return Object.keys(target).filter(key => !key.startsWith('_'))
      }
    })
    
    for(let key in user) {
      console.log(key);
    }
    

    6. apply 函数调用 + call + apply 操作拦截

    • 拦截之后,修改函数的返回值
    let sum = (...args) => {
      let num = 0
      args.forEach(item => {
        num += item
      })
      return num
    }
    sum = new Proxy(sum, {
      apply(target, ctx, args) {
        return target(...args) * 2
      }
    })
    console.log(sum(1, 2)); // 6
    console.log(sum.call(null, 1, 2, 3)); // 12
    console.log(sum.apply(null, [1, 2, 3])); // 12
    

    7. construct 拦截 new 操作

    • 返回一个对象
    let User = class {
      constructor(name) {
        this.name = name
      }
    }
    User = new Proxy(User, {
      construct(target, args, newTarget) {
        console.log('construct');
        return new target(...args)
      }
    })
    console.log(new User('imooc'))
    

    11 反射 Reflect

    • Reflect 的目的

    1. 将 Object 的属性转移到 Reflect 上

    • ES6 使得语法更加规范
    let obj = {}
    let newVal = ''
    Reflect.defineProperty(obj, 'name', {
      get() {
        return newVal
      },
      set(val) {
        console.log('set');
        newVal = val
      }
    })
    obj.name = 'es'
    console.log(obj.name);
    

    2. 修改某些 Object 方法的返回结果,使其变得更合理

    try {
      Object.defineProperty() // 无返回值
    } catch(e) {
    
    }
    if(Reflect.defineProperty()) { // 返回值 boolean
    
    } else {}
    

    3. 让 Object 操作变成函数行为

    • 命令式操作 -> 函数式操作(更加友好)
    console.log('assign' in Object); // true
    console.log(Reflect.has(Object, 'assign')); // true
    

    4. Reflect 对象的方法与 Proxy 对象的方法一一对应

    let user = {
      name: 'zouzou',
      age: 12,
      _password: '***'
    }
    user = new Proxy(user, {
      get(target, prop) {
        if(prop.startsWith('_')) {
          throw new Error('不可访问')
        } else {
          // return target[prop]
          return Reflect.get(target, prop)
        }
      },
      set(target, prop, val) {
        if(prop.startsWith('_')) {
          throw new Error('不可访问')
        } else {
          // target[prop] = val
          Reflect.set(target, prop, val)
          return true
        }
      },
      deleteProperty(target, prop) {
        // 拦截删除
        if(prop.startsWith('_')) {
          throw new Error('不可删除')
        } else {
          // delete target[prop]
          Reflect.deleteProperty(target, prop)
          return true
        }
      },
      ownKeys(target) {
        // return Object.keys(target).filter(key => !key.startsWith('_'))
        return Reflect.ownKeys(target).filter(key => !key.startsWith('_'))
      }
    })
    console.log(user.age);
    try {
      console.log(user._password);
    } catch(e) {
      console.log(e.message);
    }
    
    user.age = 13
    console.log(user.age);
    try {
      user._password = 'xxx'
    } catch(e) {
      console.log(e.message);
    }
    
    delete user.age
    console.log(user.age);
    
    for(let key in user) {
      console.log(key);
    }
    
    let sum = (...args) => {
      let num = 0
      args.forEach(item => {
        num += item
      })
      return num
    }
    sum = new Proxy(sum, {
      apply(target, ctx, args) {
        // return target(...args) * 2
        return Reflect.apply(target, target, [...args]) * 2
      }
    })
    console.log(sum(1, 2)); // 6
    console.log(sum.call(null, 1, 2, 3)); // 12
    console.log(sum.apply(null, [1, 2, 3])); // 12
    
  • 相关阅读:
    webMagic学习笔记 主页
    maven 听视频笔记
    idea如何做到多模块开发项目 收藏整理
    JAVA 增删改查接口命名规范(dao层与 service 层
    mybatis 自学笔记
    nginx学习主页导航
    用 async/await 来处理异步
    若依:SysUserMapper.xml 分析
    idea 创建多模块项目子模块为灰色
    Maven多模块开发遇到的错误 -- Maven的子模块变成灰色
  • 原文地址:https://www.cnblogs.com/pleaseAnswer/p/16285409.html
Copyright © 2020-2023  润新知