ECMAScript 6 常用特性整理

来源:互联网 发布:pycharm和python 编辑:程序博客网 时间:2024/06/05 18:05

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

更多文章

  • ECMAScript 6 常用特性整理
  • Promise-使用整理
  • Decorator装饰器
  • Iterator、Generator、async、await 异步编程
原创粉丝点击