ES6 +

146 阅读2分钟

ECMAScript 新特性

ES2015

  • let 和 作用域

    • 块级作用域
    • 没有变量提升
  • const 常量

  • 数组的解构

// 数组解构
const arr = ['1','2','3']
const [a,,c,d = '4'] = arr
const [A,...result] = arr
console.log(a) // ‘1’
console.log(c) // ‘3’
console.log(d) // ‘4’
console.log(A) // ‘A’
console.log(result) // ['2', '3']
  • 对象的解构
// 对象解构
const obj = {name:'x', age:18, gander: 'm'}
const {name:firstName , age, gander = 'f', weight = '80'} = obj
console.log(firstName) // x
console.log(age) // 18
console.log(gander)  // 'm'
console.log(weight)  // '80'
  • 模板字符串

  • 字符串的扩展方法

    • includes()
    • startsWith()
    • endsWith()
  • 参数默认值

// 多个参数, 带默认值的形参要放在最后
    function foo1 (enable == true) {
        console.log('foo invoked - enable: ');
        console.log(enable)
    }
    foo1(false);
    foo1();
    foo1(true)
  • 剩余参数
function test(...args){
    console.log(args)
}
test(1,2,3) // [1,2,3]
  • 展开数组
 const arr = [1,2,3,4];
 console.log(...arr);
  • 箭头函数

    箭头函数不会改变this指向

        function foo3(i) {
            return i + 1;
        }
        const inc = n => n + 1; 
        console.log(foo3(100)); // 101
        console.log(inc(100)); // 101
    
        const array = [1,3,2,4,5,6,9,7];
        array.filter(i => i % 2); // 获取偶数
    
        // 箭头函数不会改变this指向
        // 1.普通函数的this:指向它的调用者,如果没有调用者则默认指向window.
        // 2.箭头函数的this: 指向箭头函数定义时所处的对象,而不是箭头函数使用时所在的对象,默认使用父级的this.
        const name2 = 'lee';
        const person = {
            name2: 'tom',
            sayHi1: function(){
                console.log('my name is ', this.name2);
            },
            sayHi2: () => {
                console.log('my name is ', this.name2);
            },
            sayHiAsync: function() {
                // 1.
                // setTimeout(function(){
                //     console.log(this.name);
                // }, 1000); // undefined 因为异步调用, 无法访问person的那么属性
                // 2.
                // const _this = this;
                // setTimeout(function(){
                //     console.log(_this.name2);
                // },1000) // tome 定义一个_this指向this, 利用闭包的特性, 调用到person
                // 3.
                setTimeout(() => {
                    console.log(this.name2);
                }, 1000); // 箭头函数 this 指向 sayHiAsync 被定义的地方, 即person
            }
        }
        person.sayHi1();
        person.sayHi2();
        person.sayHiAsync();
    
  • 对象字面量增强

  • Object.assign()

const source1 = {
        a: 123,
        b: 234,
    }
    const source2 = {
        b: 789,
        d: 12345,
    }
    const target = {
        b: 456,
        c: 345,
    }
    const afterTarget = Object.assign(target, source1);
    console.log(target);
    console.log(afterTarget === target);
    // 多个源对象
    const afterTarget2 = Object.assign(target,source1, source2);
    console.log(target);
  • Object.is() 判断相等
 console.log(
        // 0 == false // true
        // 0 === false // false
        // +0 === -0 // true
        // NaN === NaN // false
        // Object.is(+0, -0) // false
        Object.is(NaN, NaN) // true
    )
  • Proxy vs Object.defineProperty

    • 监听对象属性的删除
    • 对数组对象的监视(重写数组的操作方法)
    • 非侵入式
    const person2 = {
        name: 'zoe',
        age: 20
    }
    const person2Proxy = new Proxy(person2, {
        // get(target, property) {
        //     console.log(target, property)
        //     return 100;
        // },
        get(target, property){
            return property in target?target[property] : 'default'
        },
        set(target, property, value) {
            if (property == 'age') {
                if (!Number.isInteger(value)) {
                    throw new TypeError(`${value} is not an int`);
                }
            }
            target[property] = value;
        },
        deleteProperty(target, property) {
            console.log('delete', property);
            delete target[property];
        }
    });
    console.log(person2Proxy.name);
    console.log(person2Proxy.xxx);
    person2Proxy.age = 100;
    console.log(person2Proxy.age);
    // person2Proxy.age = '101';
    // console.log(person2Proxy.age);
    delete person2Proxy.age;
    console.log(person2);

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

    // proxy 相对 object.defineProperty 

    // object.defineProperty 只能监听对象属性的读写
    // proxy 能监视更多对象操作, 例如delete 和 对方法的调用

    // proxy 更好的实现了对数组对象的监视
    // defineProperty 通过重写数组方法来实现对数组的监视

    // proxy 以非侵入的方式监管了对象的读写
  • Reflect 静态类(不能new, 与Math相似)
Reflect 属于一个静态类,只能执行静态类的静态方法

    // Reflect 内部分装了一系列对对象的底层操作

    // Reflect 成员方法就是 Proxy 处理对象的默认实现

    // 提供了一套统一的用于操作对象的API

    const testObj2 = {
        foo: '123',
        baz: '234',
    }
    const proxy2 = new Proxy(testObj2, {
        get(target, property) {
            // 先实现属性监视逻辑, 
            // 再实现默认实现方法
            // Reflect 类似于 oc 中的 super
            console.log('watch, logic'); 
            return Reflect.get(target, property);
        }
    })
    console.log(proxy2.foo);

    // Reflect 统一 api
    // 原先 多种方法类型
    // console.log('foo' in testObj2);
    // console.log(delete testObj2['baz'])
    // console.log(Object.keys(testObj2));
    // 统一方式
    console.log(Reflect.has(testObj2, 'foo'));
    console.log(Reflect.deleteProperty(testObj2,'baz'));
    console.log(Reflect.ownKeys(testObj2));
  • Promise

  • class

    • extends
  • Set(数据结构) 唯一 内部成员不允许重复

  • Map(数据结构) 任意数据类型作为键

    • .set() 设置值
    const m = new Map();
    const tom = {name:'tom'};
    m.set(tom, 90);
    m.set('a','1')
    console.log(m); //Map { { name: 'tom' } => 90, 'a' => '1' }
    
    • .get() 取值
    • .has() 判断某个键是否存在
    • .delete() 删除某个键
    • .clear() 清空所有键值
  • Symbol(全新的原始数据类型)

    • 为对象添加独一无二的属性名
    • 无法通过 for in 或者 Object.keys 拿到Symbol类型的属性名
    • JSON.stringfly(obj)也会忽略掉Symbol属性
    • 适合作为对象的私有属性
    • 可通过 Object.getOwnPropretySymbol(obj) 获取到Symbol类型属性名
    const s = Symbol();
    console.log(typeof s) // symbol
    console.log(
        Symbol() === Symbol() // false
        // Symbol('foo') === Symbol('foo') // false
    )
    
    const s1 = Symbol.for('foo');
    const s2 = Symbol.for('foo');
    console.log(s1, s2); // Symbol(foo) Symbol(foo)
    console.log(s1 === s2); // true
    
  • BigInt(全新的原始数据类型)

  • for 适合遍历普通数组

  • for ... in 适合遍历键值对

  • for ... of 遍历所有数据结构的统一方式

    • 实现Iterable接口是 for...of 的前提
 // iterable // 可迭代接口|协议|标准
    // 是 for...of 的前提
    // 对象内部挂载 iterator 方法
    // 返回一个带有next()方法的对象
    // 调用next()方法就可以实现对内部所有数据的遍历

    const set= new Set(['foo', 'bar', 'baz']);
    const iterator = set[Symbol.iterator]();
    console.log(iterator.next()); // {value: 'foo', done: false}
    console.log(iterator.next()); // {value: 'bar', done: false}
    console.log(iterator.next()); // {value: 'baz', done: false}
    console.log(iterator.next()); // {value: undefined, done: true}

    // iterable // 迭代器接口实现
    const obj = {
        store: ['foo', 'bar', 'baz'], // 一个数组用于保存要迭代的数据
        [Symbol.iterator]: function(){
            let index = 0;
            const self = this;
            return {
                next: function() {
                    const result = {
                        value: self.store[index],
                        done: index >= self.store.length ,
                    } // 实现迭代结果接口, iterationResult, 约定 有一个value属性, 标识当前被迭代到的数据, 任意类型. 一个 done 属性 , 标识是否迭代完成
                    index ++;
                    return result;
                }
            } // 实现迭代器接口, iterator , 约定内部必须实现一个用于迭代的 next() 方法
        },
    } // 自定义对象, 实现可迭代接口 iterable , 约定内部必须有一个可以返回迭代器的 iterator 方法
    for (const item of obj) {
        console.log(item);
    }

    // 迭代器 模式  iterator  (用来干什么)
    // 场景 任务清单
    const todos = {
        life: ['吃饭', '睡觉', '打豆豆'],
        learn: ['语文','数学','英语'],
        work: ['项目A', '项目B'],
        
        each: function (callback) {
            const all = [].concat(this.life, this.learn, this.work)
            for (const item of all) {
                callback(item);
            }
        }
        // 提供一个统一遍历结构, 处理方法可以不用管todos内部的数据结构是什么, 除了life, learn, work 还会有什么别的任务列表
        [Symbol.iterator]: function() {
            const all = [...this.life, ...this.learn, ...this.work];
            let index = 0;
            return {
                next: function() {
                    return {
                        value: all[index],
                        done: index++ => all.length
                    }
                }
            }
        }
    }
    todo.each(function (item) {
        console.log(item);
    })
    for(const item of todos) {
        console.log(item);
    }
  • generator
  • ES Module 语言层面的模块化标准

ES2016

  • Arrary.prototype.includes 是否存在某一指定元素
  • 指数运算符
console.log(2 ** 10) // 1024

ES2017

  • Object.values 返回对象所有值组成的一个数组
  • Object.entries 以数组形式返回所有键
  • Object.getOwnPropertyDescriptors 获取对象属性的详细描述信息
  • String.prototype.padStart
  • String.proto.padEnd
// 字符串填充方法
    // String.prototype.padStart / String.prototype.padEnd
    // 可以为数字前面添加0, 也可以用以对齐输出的字符串长度
    const obj = {
        a: 12,
        css: 3421,
        javaScript: 129213,
    }
    for (const [name, count] of Object.entries(obj)) {
        console.log(`${name.padEnd(16, '-')}` | `${count.toString.padStart(3, '0')}`);
    }
  • 在函数中添加尾逗号
  • async/await