ECMAScript 6 常用特性整理

ECMAScript 6 常用特性整理

说明

看了 阮一峰 老师的 ECMAScript 6 入门,决定将之前一直使用到的 ES6 重新整理一遍。

1. let 和 const

  1. 用法类似 var 用来声明变量,但是声明的变量只在命令所在的代码块中有效

  2. 不存在变量提升

  3. 暂时性死区, 在变量用 let 声明前的代码中 只要使用到变量,就会报错

  4. 不允许重复声明变量

  5. const 声明的是一个只读的常量,声明后值不可以改变

  6. 对于对象和数组来说,变量指向内存地址,保存的只是一个指针,const 声明的变量可以保证指针不变,但是指向的数据结构发生变化就是不可控的

2. 块级作用域

  1. let 和 const 声明的变量存在块级作用于, ES6 允许块级作用域的任意嵌套,外层的作用域无法读取内层作用域的变量

  2. 应该避免在块级作用域内声明函数,如果需要声明函数,要使用函数表达式

3. 变量的解构赋值

解构赋值等号的右边需要时可遍历结构

1. 数组的解构赋值
    let [a, [b], d] = [1, [2, 3], 4];
    console.log(a, b, d); // 1, 2, 4
    // 等号右边需要时可遍历结构
    let [f] = 121212;
    console.log(f); // 报错

    // 指定默认值
    let [foo = true] = [];
    console.log(foo); // true
    // ES6 内部使用严格相等 === 判断一个位置是否有值,=== undefined 才会使用默认值
    let [x = 1] = [undefined];
    let [y = 1] = [null];
    console.log(x, y); // 1 null

    // 惰性求值
    function f () { // 未执行,只有 x 取不到值的时候才会执行
        console.log('aaa'); 
    }
    let [x = f()] = [1];
    console.log(x); // 1

    // 默认值引用解构赋值的其他变量
    let [x = 1, y = x] = [];
    console.log(x, y); // 1 1

    let [x, y = x] = [1];
    console.log(x, y); // 1 1

    let [x = y, y = 1] = [];
    console.log(x, y); // 报错
2. 对象的解构赋值
    let {a: aa} = {a: 1, b: 2}; // 想找到同名的属性 'a' 然后复制给变量 'aa'
    console.log(aa); // 1
    // 变量的解构赋值是变量声明和赋值一体的,所以要赋值的变量不能提前声明
    let a = 12;
    let [a] = [1, 2, 3];
    console.log(a); // 报错

    let a = 12;
    let b;
    [a] = [1, 2, 3];
    ({b} = {b: 1}); // 需要放在'()'里 否则会把 {b} 解析为代码块
    console.log(a, b); // 成功 1 1
    // 数组是特殊的对象
    let {0: fir, 1: sec} = [1, 2, 3];
    console.log(fir, sec); // 1 2 
3. 字符串的解构赋值
    // 字符串会被转换成类数组对象,含有 length 属性
    let [a, b] = 'hello';
    console.log(a, b); // h e
    let {length: len} = 'hello';
    console.log(len); // 5
4. 函数参数的解构赋值
    function f([a,b]) {
        return a + b;
    }
    console.log(f([1, 2])); // 3 
    // 使用默认值
    function f ({x = 'x', y = 'y'} = {}) {
        console.log([x, y]);
    }
    f(); // ["x", "y"] 不传入参数 参数按照默认值解构 {x = 'x', y = 'y'} = {} ({},是参数中的)
    f({}); // ["x", "y"] 传入参数 参数按照传入的值解构 {x = 'x', y = 'y'} = {} ({}, 是传入的 {})
    f({x: 1}); // [1, "y"] 传入参数 参数按照传入的值解构 {x = 'x', y = 'y'} = {x: 1}
    // 另外一种默认值的写法
    function f ({x, y} = {x: 'x', y: 'y'}) {
        console.log([x, y]);
    }
    f(); // ["x", "y"] 不传入参数 参数按照默认值解构 {x, y} = {x: 'x', y: 'y'}
    f({}); // [undefined, undefined] 传入参数 参数按照传入的值解构 {x, y} = {}
    f({x: 1}); // [1, undefined] 传入参数 参数按照传入的值解构 {x, y} = {x: 1}

4. 字符串扩展

模板字符串

    // 一般写法
    `hello hello`
    // 多行
    `
    hello hello
    hello
    `
    // 变量
    `hello ${name} hello`

更多字符串方法 javascript字符串方法汇总

5. 数值的扩展

1. Number.isFinite() 是否为有限的
    Number.isFinite(1); // true
    Number.isFinite(NaN); // false
    Number.isFinite(Infinity); // false
    Number.isFinite(true); // false
2. Number.isNaN() 是否为 NaN
    Number.isNaN(NaN); // true
    Number.isNaN(15); // false
3. Number.parseInt(), Number.parseFloat() 移植到 Number 上了
4. Number.isInteger() 判断值是否为整数
    Number.isInteger(3.3); // false
    Number.isInteger(3.0); // true
5. Math.trunc() 除去数字的小数部分,返回整数部分 (内部使用 Number 方法装换为数值)
    Math.trunc(123.22); // 123 
    Math.trunc('123.22'); // 123 
    Math.trunc(true); // 1
    Math.trunc(null); 0
    Math.trunc(undefined); // NaN
    Math.trunc({}); // NaN
    Math.trunc([]); // 0
    Math.trunc('a123'); // NaN

6. 数组的扩展

1. Array.from() 将类数组对象转换为真正的数组
    let obj = {
        '0': 'a',
        '1': 'b',
        '2': 'c',
        length: 3
    }
    const arr = Array.from(obj);
    console.log(arr); //  ["a", "b", "c"]

    function f () {
        const args = Array.from(arguments, (x) => x + '--add');
        console.log(args);
    }
    f('a', 'c'); //["a--add", "c--add"]
2. Array.of() 将一组数值转化为数组
    const arr = Array.of(12,12,12);
    console.log(arr); // [12, 12, 12]
3. find() findIndex() 找到第一个符合条件的数组成员,参数是一个回调函数,数组成员依次执行回调,直到第一个返回值为true的成员,然后返回此成员或者所在index,没有则返回undefined
    const member = [22, 323, 424, -12, 0].find((value, index) => {
        return value < 0;
    })
    console.log(member); // -12

    const member = [22, 323, 424, -12, 0].findIndex((value, index) => {
        return value < 0;
    })
    console.log(member); // 3
更多数组方法,在 Javascript 数组方法汇总

7. 函数的扩展

ES6 中的函数参数可以设置默认值,函数进行声明初始化的时候,参数会形成一个单独的作用域,初始化结束后这个作用域就会消失,这种行为在不设置参数默认值时是不存在的

    // 参数中 y 默认等于 x 变量,调用函数是,参数新城单独作用域,y 指向参数 x 而不是全局的 x
    var x = 1;
    function f(x, y = x) {
      console.log(y);
    }
    f(2) // 2
    // foo 在 bar 函数的参数作用域中没有定义,所以指向全局的 foo 
    let foo = 'outer';
    function bar(func = x => foo) {
      let foo = 'inner';
      console.log(func()); 
    }
    bar(); // outer
1. rest 参数, 有点类似逆向的扩展运算符
    function f (...args) {
        console.log(args); // [1, 2, Array(2), function]
    }

    f(1, 2, [11, 22], function () {
        console.log('in');
    });
2. 扩展运算符, 将一个数组转为用逗号分隔的参数序列。
    // 函数使用
    function f (a, b) {
        console.log(a, b);
    }

    const arr = [123, 456];
    f(...arr); // 123 456

    // 合并数组
    const arr1 = ['a', 'b', 'c'];
    const arr2 = [1, 2, 3];
    const arr = [...arr1, ...arr2];
    console.log(arr); // ["a", "b", "c", 1, 2, 3]

    // 结合解构赋值
    const arr1 = ['a', 'b', 'c'];
    const [fir, ...sec] = arr1;
    console.log(fir, sec); // a ["b", "c"]
    // 结构赋值时,要放在最后,否则报错

    const arr1 = ['a', 'b', 'c'];
    const [...fir, sec] = arr1;
    console.log(fir, sec); // 报错

    // 可以用来将字符串转换成数组
    const arr = [...'hello'];
    console.log(arr); // ["h", "e", "l", "l", "o"]
3. 严格模式

ES6 中的 严格模式可以设置成全局的,但是在函数中的严格模式需要函数参数不包含 默认值、解构赋值、扩展运算符,否则会报错

4. 箭头函数, 简化回调函数
  1. 函数体内的 this 对象 就是定义时所在的对象,不是使用时的对象
  2. 不可以当做构造函数,也就是不也已使用 new 命令
  3. 不可以使用 arguments 对象,不存在,可以用 rest 参数 代替
  4. 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数
    // 定义函数, 一个参数
    let f = x => x;
    // 没有参数 用 ()
    let f = () => 'test';
    // 多个参数 (x, y)
    let f = (a, b) => a + b;
    // 代码块多于一行
    let f = (a, b) => {
        let num = a + b;
        return num;
    }

8. 对象的扩展

    // 对象的一般写法
    let foo = 'foo';
    let obj = {foo: foo};
    // 简洁的写法
    let obj = {foo}; // 属性名 = 变量名
    // 方法的简写
    const obj = {
        method(){
            console.log('method');
        }
    }
1. ES6 允许表达式作为对象的属性名或者方法名
    // 属性名
    let prop = 'foo';
    let obj = {
        [prop]: true,
        ['a' + 'b']: 123
    };
    console.log(obj); // {foo: true, ab: 123}
    // 方法名
    let prop = 'foo';
    let obj = {
        [prop]() {
            console.log('obj.foo function');
        }
    }
    obj.foo(); // obj.foo function
    // 属性名表达式与简洁表示法不能同时用,会报错
    let foo = 'bar';
    let bar = 'abc';
    let obj = {
        [foo]   // 报错
    }
2. Object.is() 比较两个值是否相等,基本与 === 差不多
    // 与 === 不一样的地方
    NaN === NaN // false
    -0 === +0 // true

    Object.is(-0, +0) // false
    Object.is(NaN, NaN) // true
3. Object.assign() 实现浅拷贝,用于合并对象,将源对象的所有可枚举属性,复制到目标对象
    // 第一个参数是目标对象,后面的参数是源对象,有同名的属性,后边的会覆盖前边的
    let target = {a: 1, b: 2};
    let source1 = {b: 4, c: 8};
    let source2 = {c: 6};
    const a = Object.assign(target, source1, source2);
    console.log(a); // {a: 1, b: 4, c: 6}
    console.log(target); // {a: 1, b: 4, c: 6}
    // 指定默认值
    const defaultVal = {
        level: 1,
        type: 'html'
    }
    function f (options) {
        options = Object.assign({}, defaultVal, options);
        return options;
    }
    console .log(f({level: 2})); // {level: 2, type: "html"}
4. 对象的扩展运算符
    // 解构赋值, ... 必须在最后,并且 = 右边需要是一个对象
    let {x, y, ...d} = {x: 'x', p: 'p', y: 'y', c: 'c'};
    console.log(d); // {p: "p", c: "c"}
    // 作为扩展,可以有多个 ... 
    let a = {x: '1212', y: '1222'};
    let b = {z: 'zzz', y: '12ed'};
    let ab = {...a, ...b};
    console.log(ab); // {x: "1212", y: "12ed", z: "zzz"}

9. Set

  1. Set 数据结构类似数组,但是成员的值都是唯一的,没有重复的值,可以用来数组去重
    // 初始化
    const set = new Set([1, 2, 1, 3 ,2 , 5]);
    console.log([...set]); // [1, 2, 3, 5]
    // 添加
    set.add(123);
    set.add(2);
    console.log([...set]); // [1, 2, 3, 5]
    // 数组去重, 向Set 中加入值的时候不会发生类型转换
    let arr = [1, 2, 1, 3 ,2 , 5, '5'];
    const output = [...new Set(arr)];
    console.log(output); // [1, 2, 3, 5, "5"]
    // NaN 与 NaN 比较算是重复的 
    let arr = [1, NaN];
    let set = new Set(arr);
    console.log(set.size); // 2
    set.add(NaN);
    const output = [...set];
    console.log(output); // [1, NaN]
  1. set 实例的方法
    let set = new Set([1, 2, 3, 2, 5]);
    console.log(set.size); // 4 返回 Set 实例的成员总数
    set.add(8); // SetIterator {1, 2, 3, 5, 8} 添加值
    set.delete(5); // SetIterator {1, 2, 3, 8} 删除值
    set.has(8); // true 是否含有某个值
    set.clear(); // [] 清除所有值,没有返回值
    for (let item of set.keys()) {
        console.log(item);  // 1 2 3 5 返回键名,Set 没有键名就返回键值,跟 set.values一样 
    }
    for (let item of set.values()) {
        console.log(item);  // 1 2 3 5 返回键值
    }
    for (let item of set.entries()) {
        console.log(item);  // [1, 1] [2, 2] [3, 3] [5, 5] 返回键值对
    }
    set.forEach((item, i) => {
        console.log(item, i); // 遍历
    });
  1. set 实现并集、交集、差集
    let a = new Set([1, 2, 3]);
    let b = new Set([4, 2, 3]);

    // 并集
    const union = new Set([...a, ...b]);
    console.log(union); // Set(4) {1, 2, 3, 4}
    // 交集
    const intersect = new Set([...a].filter(x => b.has(x)));
    console.log(intersect); // Set(2) {2, 3}
    // 差集
    const diff = new Set([...a].filter(x => !b.has(x)));
    console.log(diff); // Set(1) {1}

10. Map

Object 对象是键值对的集合,但是传统上只能用 字符串做键,而 Map 结构上类似 Object 也是键值对的集合,但是键的范围不限制于字符串,各种类型的值都可以作为键,如果键的值是引用类型则,键实际上是指针指向的地址

    const a = new Map();
    const o1 = {name: 'xiaoming'};
    const o2 = {name: 'xiaoming'};

    // set 方法用于设置键值对
    a.set(o1, 'this is xiaoming');

    // has 方法用于判断是否含有值
    console.log(a.has(o1)); // true

    // o1 和 o2 是值相同但是指向不同内存地址的对象
    console.log(a.get(o1)); // this is xiaoming
    console.log(a.get(o2)); // undefined

    // o1 作为键内存地址不改变但是值变了,Map 依然可以通过 get 方法取到值,证明 键实际上是指针的指向地址
    o1.age = 23;

    // get 方法用于获取值
    console.log(a.get(o1)); // this is xiaoming 不变

    // delete 方法用作删除
    a.delete(o1);
    console.log(a.has(o1)); // false

    // 设置多个键值对
    const b = new Map([
        ['name', 'xiaoming'],
        ['age', 90]
    ])

    console.log(b.has('name')); // true
    console.log(b.has('age')); // true

    // size 属性 返回 map 成员总数
    console.log(b.size); // 2

    // clear 方法清除所有成员
    b.clear();
    console.log(b.has('name')); // false

    const b = new Map([
        [{name: 'firstName'}, 'xiaoming'],
        ['age', 90]
    ])

    // 返回键名
    for (let key of b.keys()) {
        console.log(key); // {name: "firstName"} age
    }

    // 返回键值
    for (let value of b.values()) {
        console.log(value); // xiaoming 90
    }

    // 返回所有成员
    for (let item of b.entries()) {
        console.log(item); // [{name: "firstName"}, "xiaoming"] ["age", 90]
    }

    // 遍历所有成员
    b.forEach(function (value, key, map) {
        console.log(value, key); 
        // xiaoming  {name: "firstName"} 
        // 90 "age"
    })

11. Class

javascript 中,生成实例对象的传统方法是通过构造函数,es6 引入 Class 作为对象的模板,通过 Class 定义类,但是 es6 的 Class 只是一个语法糖,他只是在写法上更像面向对象编程的语法而已,es6 的类可以看做是构造函数的另外一种写法

    class Parent {
        /*
            通过 new 生成实例对象时,自动调用该方法,
            一个类必须有此方法,如果没有显示定义,空的constructor会被自动添加
            constructor 方法默认返回实例对象 即 this 
        */ 
        constructor(x, y) {
            /*
                这里的 this 指向实例化后的对象,
            */ 
            this.attrs = {
                a: 'a'
            };
        }
        // 定义实例属性 constructor 中也可以通过 this 定义
        state = {
            name: 'state name'
        };
        /*
            方法之间不能有逗号,
            定义的方法都挂载在 Parent.prototype 上了
            类的方法中如果有 this 默认指向类的实例,但是如果将方法提取出来单独使用,this 会指向该方法所在的运行环境,
            这个时候如果想通过 this 调用 类中定义的方法或属性就会找不到,解决办法是手动绑定 `.bind(this)`
        */ 
        show() {

        }
        // 静态属性 由类直接调用
        static classAttr = 'class attr';

        // 静态方法 由类直接调用
        static classMethod() {
            console.log('static');
        }
    }

    /*
        类 必须要通过 new 调用否则会报错(普通构造函数可以直接使用)
        不存在变量提升,子类一定要在父类后定义
    */ 
    Parent.classMethod(); // static
    console.log(Parent.classAttr); // class attr

    const parent = new Parent();
    console.log(Parent.name); // Parent
    console.log(parent.state); // {name: "state name"}
    console.log(parent.attrs); // {a: "a"}

    console.log(parent.__proto__ === Parent.prototype); // true
    console.log(parent.__proto__.constructor === Parent); // true
    console.log(Parent.prototype); // {constructor: function, show: function}

    /*
        Class 表达式方式定义
        me 只用作函数内使用, 不使用的话可以省略 函数外类叫做 MyClass
    */ 
    const MyClass = class me {
        getClassName() {
            return me.name
        }
    }
    const a = new MyClass();
    console.log(a.getClassName()); // me

类的继承,(extends)

  • es5 的继承,实质上是先创建子类的实例对象 this ,然后将父类的方法添加到 this 上
  • es6 的继承机制完全不同,实质上是先创建父类的实例对象 this (所以必须先调用super方法),然后再用子类的构造函数修改 this,子类中只有调用了 super 方法之后 才可以使用 this 关键字
    class Parent {
        constructor(name) {
            this.name = name;
        }

        logName(newName) {
            console.log(newName);
        }
    }

    // 子类 通过 extends 关键字继承父类
    class Child extends Parent {
        constructor(age, name) {
            /*
                super 表示父类的构造函数(constructor(name))
                子类必须在 constructor 方法中调用 super 否则会因为子类没有自己的 this 对象 又没有通过 super 继承父类的 this 而报错
            */ 
            super(name);
            this.age = age;
        }

        logAge() {
            console.log(this.age)
        }
        logName() {
            console.log('this is in Child');
        }

        logInfo() {
            // 调用 logName 方法,子类覆盖了父类
            this.logName(this.name);
            // 直接调用父类 的 logName 方法
            super.logName(this.name);
            this.logAge();
        }
    }

    console.log(Child.prototype.constructor === Child); // true

    const child = new Child(20, 'xiaobai');

    child.logInfo(); // this is in Child | xiaobai | 20

更多文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值