es6 学习笔记(二)

解构赋值

从数组或者对象中提取值去对变量/数组赋值被称为解构。

一、数组解构赋值

类似于

1
2
3
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

注意点:
右边必须为可遍历的结构。

  • 左>右
    对于没有办法匹配的变量,会被赋值为undefined,数组会被赋为空
    1
    2
    3
    4
    let [x, y, ...z] = ['a'];
    x // "a"
    y // undefined
    z // []

为了避免这样,可以考虑给默认值。且一旦右边的值非严格等于undefined,就会覆盖左边的默认值

1
[x, y = 'b'] = ['a']; // x='a', y='b'

  • 左<右
    不完全解构,只取部分值
    1
    2
    3
    4
    let [a, [b], d] = [1, [2, 3], 4];
    a // 1
    b // 2
    d // 4

二、对象的解构赋值

变量必须与属性同名,才能取到正确的值。本质上类似于

1
2
3
4
var { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };
//eg
var {key1,key2} = {key1:value1,key2:value2}
key1 //value1
  • 区分模式和变量
  • 也可以设置默认值

    1
    2
    3
    4
    5
    6
    var {x,y=5} = {x:1}
    x //1
    y //5
    var {x:y = 3} = {x: 5};
    y // 5
  • 不要将花括号写在行首,避免被解释为代码块,用括号包裹即可。

    1
    2
    3
    4
    5
    6
    var x;
    {x} = {x: 1};
    // SyntaxError: syntax error
    // 正确的写法
    ({x} = {x: 1});

三、字符串的解构赋值

1
2
3
4
5
6
const [a, b, c, d, e] = 'hello';
//也可以
for (let codePoint of 'foo') {
console.log(codePoint)
}

数值和布尔值也可以解构

四、用途

  • 交换变量

    1
    [x, y] = [y, x+y];
  • 从函数返回多个值

    1
    2
    3
    4
    function example() {
    return [1, 2, 3];
    }
    var [a, b, c] = example();
  • 函数参数的默认值

  • 与for of 配合遍历

    1
    2
    3
    for (let [key, value] of map) {
    console.log(key + " is " + value);
    }
  • 模块


字符串扩展

  1. includes/startsWith/endsWith(str,index)
    index为开始搜索的位置
  2. repeat()

    1
    2
    "he".repeat(3) //hehehe
    "he".repeat(0) //""
  3. 模板字符串
    见另一个笔记es6笔记(一)
    模板编译部分见阮一峰笔记

  • 标签模板
    跟在函数名后面的模板字符串会被识别为多个参数。
    - 用途1
    
    可以用来对用户传入的数据进行预处理,比如过滤HTML字符串,防止用户输入恶意内容
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    var message =
    SaferHTML`<p>${sender} has sent you a message.</p>`;
    function SaferHTML(templateData) {
    var s = templateData[0]; //<p>
    for (var i = 1; i < arguments.length; i++) {
    var arg = String(arguments[i]); //sender
    // Escape special characters in the substitution.
    s += arg.replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;");
    // Don't escape special characters in the template.
    s += templateData[i];
    //templateData[i]这边指has sent you a message.</p>
    }
    return s;
    }
    //类似于functionName(strArr,..valuesArr),这边的strArr即为模板字符串中分解出来的所有非变量的字符串所组成的数组。
    //"templateData" ["<p>", " has sent you a message.</p>"]
    //"arguments" [object Arguments] {
    0: ["<p>", " has sent you a message.</p>"],
    1: "luchen"
    }
    arguments = strArr + valuesArr

除此之外,还有一个很神奇的用法,就是可以将普通的javascript转换为其他语言,比如说jsx..,找到jsx函数的实现,然后就可以将一个DOM字符串转为React对象..四国以..

1
2
3
4
5
6
7
8
9
jsx`
<div>
<input
ref='input'
onChange='${this.handleChange}'
defaultValue='${this.state.value}' />
${this.state.value}
</div>
`


数值的扩展

  1. 0b,0o 二进制八进制写法

    1
    2
    3
    4
    5
    6
    7
    8
    0b111110111 === 503
    0o767 === 503
    //es5
    parseInt("111110111", 2) === 503
    parseInt("767", 8) === 503
    //转为十进制用Number(str)
    Number('0b111')
  2. 原有方法加了Number限定,取消全局函数
    传统方法先用Number转换,然后判断,而现在不会转换,如果非数值,直接false

    1
    2
    3
    4
    5
    Number.isFinite() Number.isNaN()
    Number.parseInt() Number.parseFloat()
    Number.isInteger()
    //Number.isInteger(25) // true 25与25.0被认为是同一个数
    //Number.isInteger(25.0) // true
  3. 增加极小值,用于浮点数误差判断
    Number.EPSILON

  4. 整数范围
    JavaScript能够准确表示的整数范围在-2^53到2^53之间(开区间)
    现在用Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。

    1
    2
    Number.MAX_SAFE_INTEGER === 2**53-1
    Number.MAX_SAFE_INTEGER === -(2**53-1)
  5. Math对象的扩展

  • Math.trunc()
    取数的整数部分,截断,非四舍五入。非数值先Number(),不能转则NaN

    1
    2
    3
    4
    //等于
    function mathTrunc (x) {
    return (x < 0 ? Math.ceil(x) : Math.floor(x))
    }
  • Math.sign()判断符号

  • 三角函数运算
  • 对数运算
  • 指数运算
    1
    2**3 ===8

数组扩展


对象=》数组

  1. Array.from()
    将以下两种对象转变为数组
  • 类似数组的对象(array-like object),如arguments,getElementsByTag得到的集合
  • 可遍历(iterable)的对象,如Set Map

    任何有length属性的对象,都可以通过Array.from方法转为数组

    (1)用法:

    1
    Array.from(arrayLike, x => x * x);
**补充**:
扩展运算符(...)也可以做到。主要是以下场景:

1
2
3
4
5
function f1(param1,...arr){//确切的说是rest参数
//arr == [v2,v3]
}
f1(v1,v2,v3)
  1. Array.of()
    将一组数值转为数组

    1
    2
    3
    Array.of() // []
    Array.of(undefined) // [undefined]
    Array.of(1) // [1]
  2. arr.copyWithin(destIndex,srcStart,srcEnd)

    1
    2
    // 将3号位复制到0号位
    [1, 2, 3, 4, 5].copyWithin(0, 3, 4)
  3. arr.find() arr.findIndex
    主要是由于arr.indexOf比较是基于===全等操作符,那么NaN就不能被找到,因为跟NaN有关的表达式都会返回false.
    参数为回调函数

    1
    2
    3
    [1, 5, 10, 15].findIndex(function(value, index, arr) {
    return value > 9;
    }) // 2

    补充:

    1
    arr.includes(param1,startIndex) //es7
  4. arr.fill()
    常用语初始化

    1
    new Array(3).fill(7) //[7,7,7]
  5. arr.entries(),keys(),values()
    常与for..of一起使用进行对象遍历

    1
    2
    3
    for (let index of ['a', 'b'].keys()) {
    console.log(index);
    }

函数的扩展

  1. 函数参数默认值
    只能作为尾参数

  2. rest参数 值-》数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function add(...values) {
    let sum = 0;
    for (var val of values) {
    sum += val;
    }
    return sum;
    }
    add(2, 5, 3) // 10
  3. 扩展运算符
    将数组-》逗号分隔的序列
    不同于rest参数是在形参中,扩展运算符用于函数调用里

    1
    2
    3
    4
    5
    6
    function add(x, y) {
    return x + y;
    }
    var numbers = [4, 38];
    add(...numbers) // 42

常用

1
2
3
4
Math.max(...[14, 3, 77])
arr1.push(...[13,3,2]) //concat
[...arr1, ...arr2, ...arr3]
[a, ...rest] = list

  1. 箭头函数
  2. 尾递归
    -》递归改写,以解决多余的参数的问题(套一层函数/curry/es6默认值)
    -》优化:循环替代递归
    (1)返回函数而不是返回函数调用,用链式调用来替代嵌套调用
    阮一峰es6
    (2)memonization存储中间值
    具体见高性能javascript(p76)

对象扩展

  1. 属性、方法的简写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var birth = '2000/01/01';
    var Person = {
    name: '张三',
    //等同于birth: birth
    birth,
    // 等同于hello: function ()...
    hello() { console.log('我的名字是', this.name); }
    };
  2. 属性名表达式,
    也可以用来定义方法名

    1
    2
    3
    4
    5
    let propKey = 'foo';
    let obj = {
    [propKey]: true,
    };
  3. 方法的name属性
    get/set函数 -》person.firstName.name // “get firstName”
    匿名函数 (new Function()).name // “anonymous”
    symbol const key1 = Symbol(‘description’);

  4. Object.is
    在===的基础上补充两点:

  • NaN

    1
    Object.is(NaN, NaN) // true
  • +0 -0不相等

    1
    Object.is(+0, -0) // false
  1. Object.assign
  • 浅拷贝,如果源对象的某个key的value是对象,那么复制的是这个对象的引用。

    1
    2
    3
    4
    5
    6
    var obj1 = {a: {b: 1}};
    var obj2 = Object.assign({}, obj1);
    obj1.a.b = 2;
    obj2.a.b // 2
    tong
  • 同名属性,只会替换,不会添加

  • 只能拷贝自身属性,不能拷贝继承的属性以及不可枚举的属性。

    • 用途:

      • 给对象添加属性

        1
        2
        3
        4
        5
        class Point{
        constructor(x,y){
        Object.assign(this,{x,y})
        }
        }
      • 给对象添加方法

        1
        2
        3
        4
        5
        Object.assign(someClass.prototype,{
        someMethod(arg1, arg2) {
        ···
        },
        })
      • 克隆对象
        1
        2
        3
        4
        function clone(origin) {
        let originProto = Object.getPrototypeOf(origin);
        return Object.assign(Object.create(originProto), origin);
        }
  1. 属性的遍历
    for..in,Object.keys(),Object.getOwnPropertyNames(obj),Object.getOwnPropertySymbols(obj),Reflect.ownKeys(obj)

遍历顺序: 数字(按大小)-》字符串(按生成时间)-》Symbol(按生成时间)

1
2
Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 })
// ['2', '10', 'b', 'a', Symbol()]

  1. es7中的
    Object.getOwnPropertyDescriptors
    rest用于对象解构

补充知识

ES5有三个操作会忽略enumerable为false的属性。

  • for…in循环:只遍历对象自身的和继承的可枚举的属性
  • Object.keys():返回对象自身的所有可枚举的属性的键名
  • JSON.stringify():只串行化对象自身的可枚举的属性
  • es6中Object.assign():跟Object.keys一样,只拷贝自身的可枚举属性

es6中所有class的原型的方法都是不可枚举的。