• 前端基础(四十五):你不知道的JavaScript - 解构、函数默认传参、类super、模板字面量、生成器提前完成、集合、新增API


    ...

    function foo(...args){
        console.log(args);
    }
    foo(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
    
    • 1
    • 2
    • 3
    • 4

    默认参数值

    function foo(x = 1, y = 2){
        console.log(x, y);
    }
    foo(); // 1 2
    foo(undefined, null); // 1 null
    foo(3, 4); // 3 4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    // function bar(x = x + 1, y = x + 2) Error ---> ReferenceError: Cannot access 'x' before initialization
    // function bar(x = y + 1, y = x + 2) Error ---> ReferenceError: Cannot access 'y' before initialization
    function bar(x = 1, y = x + 2) {
        console.log(x, y);
    }
    bar(); // 1 3
    bar(undefined, null); // 1 null
    bar(3, 4); // 3 4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    function bar(x = 1, y = ((num) => num)(2)) {
        console.log(x, y);
    }
    bar(); // 1 2
    bar(undefined, null); // 1 null
    bar(3, 4); // 3 4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    解构

    let data = {
        code: 200,
        data: {
            name: 'Lee',
            age: 18,
            list: [1, 2, 3]
        },
        msg: 'ok'
    }
    
    let { code: c, msg: m, data: d, data: { name: n, age: a, list: [n1, n2, n3] } } = data;
    
    console.log(c, m, d, n, a, n1, n2, n3); // 200 'ok' {name: 'Lee', age: 18, list: Array(3)} 'Lee' 18 1 2 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    var o1 = { a: 1, b: 2, c: 3 },
        o2 = {};
    
    ({ a: o2.x, b: o2.y, c: o2.z } = o1);
    
    console.log(o2); // {x: 1, y: 2, z: 3}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    var o1 = { a: 1, b: 2, c: 3 },
        a2 = [];
    
    ({ a: a2[0], b: a2[1], c: a2[2] } = o1);
    
    console.log(a2); // [1, 2, 3]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    var a1 = [1, 2, 3],
        o2 = {};
    
    [o2.a, o2.b, o2.c] = a1;
    
    console.log(o2.a, o2.b, o2.c); // 1 2 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    var a1 = [1, 2, 3],
        a2 = [];
    
    [a2[2], a2[0], a2[1]] = a1;
    
    console.log(a2); // [2, 3, 1]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    var o = { a: 1, b: 2, c: 3 },
        a, b, c, p;
    
    p = { a, b, c } = o;
    
    console.log(a, b, c); // 1 2 3 
    
    p === o; // true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    var o = { a: 1, b: 2, c: 3 },
        p = [4, 5, 6],
        a, b, c, x, y, z;
    
    ({ a } = { b, c } = o);
    [x, y] = [z] = p;
    
    console.log(a, b, c); // 1 2 3 
    console.log(x, y, z); // 4 5 4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    let data = [1, undefined, 3];
    let [a = 10, b = 20, c = 30, d = 40] = data;
    console.log(a, b, c, d); // 1 20 3 40
    
    • 1
    • 2
    • 3

    super 对象

    var o1 = {
        foo() {
            console.log("o1:foo");
        }
    };
    var o2 = {
        foo() {
            super.foo(); // o1.foo
            console.log("o2:foo");
        }
    };
    Object.setPrototypeOf(o2, o1);
    o2.foo(); // o1:foo o2:foo
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    标签模板字面量

    /**
     * 标签模板字面量
     *      strings:    
     *          是一个由所有普通字符串(插入表达式之间的部分)组成的数组
     *          strings.raw:
     *              原始(raw)字符串,原始版本的值保留了原始的转义码 \n 序列(\ 和 n 是独立的字符),而处理过的版本把它当作是一个单独的换行符
     *      values:
     *          插入的值组成的数组
     */
    function foo(strings, ...values) {
        console.log(strings);
        console.log(strings.raw);
        console.log(values);
    }
    
    var name = "Lee";
    var age = 18;
    
    // strings      --->    ['Hello, 我叫', '\n今年', '岁!', raw: Array(3)]
    // strings.raw  --->    ['Hello, 我叫', '\\n今年', '岁!']
    // values       --->    ['Lee', 18]
    foo`Hello, 我叫${name}\n今年${age}岁!`;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • ES6 提供了一个内建函数可以用作字符串字面量标签:String.raw(…)。它就是传出 strings 的原始版本
      console.log(String.raw`Hello\nLee!!!`); // Hello\nLee!!!
      
      • 1

    生成器提前完成

    function* foo() {
        yield 1;
        yield 2;
        yield 3;
        return 4;
    }
    
    let it = foo();
    console.log(it.next()); // {value: 1, done: false}
    console.log(it.return()); // {value: undefined, done: true}
    console.log(it.return(5)); // {value: 5, done: true}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    集合

    类 - new.target

    class Foo {
    
        static msg = 'Hello Foo';
    
        constructor() {
            console.log(new.target.msg);
        }
    
    }
    
    class Bar extends Foo {
    
        static desc = 'Hello Bar';
    
        constructor() {
            super();
            console.log(new.target.desc, new.target.msg);
        }
    
        baz() {
            console.log(new.target);
        }
    
    }
    
    new Foo(); // Hello Foo
    var b = new Bar(); // Hello Foo --- Hello Bar, Hello Foo
    b.baz(); // undefined
    
    • 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
    • 28
    • new.target 作用:
      • new.target 可以访问 静态属性 / 方法
      • 类构造器中的 new.target 如果是 undefined,那么就可以知道这个函数不是通过 new 调用的,因此如果需要的话可以强制一个 new 调用

    映射 - Map

    var m = new Map();
    var x = { id: 1 },
        y = { id: 2 };
    
    // 设置值
    m.set(x, "foo");
    m.set(y, "bar");
    
    // 元素含量
    console.log(m.size); // 2
    
    // 查询值
    console.log(m.get(x)); // foo
    console.log(m.get(y)); // bar
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    console.log(m.values());
    console.log(m.values().next()); // {value: 'foo', done: false}
    
    • 1
    • 2

    在这里插入图片描述

    console.log(m.entries());        
    console.log(m.entries().next()); // {value: Array(2) [{id: 1}, 'foo'], done: false}
    
    • 1
    • 2

    在这里插入图片描述

    console.log(m.keys());
    console.log(m.keys().next()); // {value: {id: 1}, done: false}
    
    • 1
    • 2
    // 删除值
    m.delete(y);
    
    • 1
    • 2
    // 清空值
    m.clear();
    
    • 1
    • 2

    WeakMap

    WeakMap 是 map 的变体,二者的多数外部行为特性都是一样的,区别在于内部内存分配(特别是其 GC)的工作方式

    注意:WeakMap(只)接受对象作为键

    WeakMap 没有 size 属性或 clear() 方法,也不会暴露任何键、值或项目上的迭代器

    在这里插入图片描述

    var m = new WeakMap();
    var x = { id: 1 },
        y = { id: 2 };
    
    m.set(x, "foo");
    
    m.has(x); // true 
    m.has(y); // false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    var m = new WeakMap();
    var x = { id: 1 },
        y = { id: 2 },
        z = { id: 3 },
        w = { id: 4 };
    
    m.set(x, y);
    
    x = null; // { id: 1 } 可GC 
    y = null; // { id: 2 } 可GC 
    
    // 只因 { id: 1 } 可GC 
    m.set(z, w);
    w = null; // { id: 4 } 不可GC
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Set

    set 是一个值的集合,其中的值唯一(重复会被忽略)

    set 的 API 和 map 类似。只是 add(…) 方法代替了 set(…) 方法(某种程度上说有点讽刺),没有 get(…) 方法。

    在这里插入图片描述

    var s = new Set();
    var x = { id: 1 },
        y = { id: 2 };
    
    s.add(x);
    s.add(y);
    s.add(x);
    
    // s.size; // 2 
    
    // s.delete(y);
    
    // s.size; // 1 
    
    // s.clear();
    
    // s.size; // 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • Set 迭代器
      var s = new Set();
      var x = { id: 1 },
          y = { id: 2 };
      
      s.add(x).add(y);
      
      var keys = [...s.keys()],
          vals = [...s.values()],
          entries = [...s.entries()];
      
      s.keys().next();
      s.values().next();
      s.entries().next();
      
      keys[0] === x; // true
      keys[1] === y; // true
      
      vals[0] === x; // true
      vals[1] === y; // true
      
      entries[0][0] === x; // true
      entries[0][1] === x; // true
      entries[1][0] === y; // true
      entries[1][1] === y; // true
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24

    WeakSet

    就像 WeakMap 弱持有它的键(对其值是强持有的)一样,WeakSet 对其值也是弱持有的(这里并没有键):

    WeakSet 的值必须是对象,而并不像 set 一样可以是原生类型值。

    在这里插入图片描述

    var s = new WeakSet();
    var x = { id: 1 },
        y = { id: 2 };
    s.add(x);
    s.add(y);
    x = null; // x可GC 
    y = null; // y可GC
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    新增API

    静态函数 Array.of(..)

    var a = Array(3);
    console.log(a);         // (3) [空属性 × 3]
    console.log(a.length);  // 3
    console.log(a[0]);      // undefined
    
    var b = Array.of(3);
    console.log(b);         // [3]
    console.log(b.length);  // 1
    console.log(b[0]);      // 3
    
    var c = Array.of(1, 2, undefined);
    console.log(c);         // (3) [1, 2, undefined]
    console.log(c.length);  // 3
    console.log(c[2]);      // undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    静态函数 Array.from(..)

    注意 空值undefined

    // 类数组对象
    var arrLike = {
        length: 3,
        0: "foo",
        3: "bar"
    };
    Array.prototype.slice.call(arrLike); // (3) ['foo', 空属性 × 2]
    Array.from(arrLike); // (3) ['foo', undefined, undefined]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    var arrLike = {
        length: 4,
        2: "foo"
    };
    Array.from(arrLike); // [undefined, undefined, 'foo', undefined]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    var arrLike = {
        length: 4,
        2: "foo"
    };
    
    let arr = Array.from(arrLike, (value, index) => {
        console.log(value, index);
        return {key: index, value};
    });
    
    console.log(arr); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    原型方法 copyWithin(..)

    copyWithin(..) 从一个数组中复制一部分到同一个数组的另一个位置,覆盖这个位置所有原来的值

    copyWithin(..) 方法不会增加数组的长度。到达数组结尾复制就会停止

    [1, 2, 3, 4, 5].copyWithin(3, 0);       // [1,2,3,1,2] 
    [1, 2, 3, 4, 5].copyWithin(3, 0, 1);    // [1,2,3,1,5] 
    [1, 2, 3, 4, 5].copyWithin(0, -2);      // [4,5,3,4,5] 
    [1, 2, 3, 4, 5].copyWithin(0, -2, -1);  // [4,2,3,4,5]
    
    • 1
    • 2
    • 3
    • 4
    • copyWithin
      • 第1个参数: 表示目标覆盖的开始索引位置。
      • 第2个参数: 表示开始复制的开始元素索引位置。
      • 第3个参数: 表示结束复制的元素索引位置,注:不包含最后一个索引元素

    原型方法 fill(..)

    Array(4).fill(undefined); // [undefined, undefined, undefined, undefined]
    
    • 1

    原型方法 entries()values()keys()

    迭代器方法

    var a = [1,2,3];
    [...a.values()];            // [1,2,3] 
    [...a.keys()];              // [0,1,2] 
    [...a.entries()];           // [ [0,1], [1,2], [2,3] ] 
    [...a[Symbol.iterator]()];  // [1,2,3]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    var a = []; 
    a.length = 3; 
    a[1] = 2; 
    [...a.values()];    // [undefined,2,undefined] 
    [...a.keys()];      // [0,1,2] 
    [...a.entries()];   // [ [0,undefined], [1,2], [2,undefined] ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    静态函数 Object.is(..)

    如果需要严格识别 NaN 或者 -0 值,那么应该选择 Object.is(…)

    var x = NaN, y = 0, z = -0; 
    x === x;            // false 
    y === z;            // true 
    Object.is(x, x);    // true 
    Object.is(y, z);    // false
    
    • 1
    • 2
    • 3
    • 4
    • 5

    静态函数 Object.getOwnPropertySymbols(..)

    获取对象上所有的符号属性

    var o = { 
        foo: 42, 
        [Symbol("bar")]: "hello world", 
        baz: true 
    }; 
    Object.getOwnPropertySymbols(o); // [ Symbol(bar) ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    静态函数 Object.setPrototypeOf(..)

    行为委托

    var o1 = { 
        foo() { 
            console.log("foo"); 
        } 
    };
    var o2 = {};
    
    Object.setPrototypeOf(o2, o1); 
    
    // 委托给o1.foo() 
    o2.foo(); // foo
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    var o1 = { 
        foo() { 
            console.log("foo"); 
        } 
    }; 
    
    var o2 = Object.setPrototypeOf({}, o1 ); 
    
    // 委托给o1.foo() 
    o2.foo(); // foo
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Math

    • 三角函数:
      • cosh(..) 双曲余弦函数
      • acosh(..) 双曲反余弦函数
      • sinh(..) 双曲正弦函数
      • asinh(..) 双曲反正弦函数
      • tanh(..) 双曲正切函数
      • atanh(..) 双曲反正切函数
      • hypot(..) 平方和的平方根(也即:广义勾股定理)
    • 算术:
      • cbrt(..) 立方根
      • clz32(..) 计算 32 位二进制表示的前导 0 个数
      • expm1(..) 等价于 exp(x) - 1
      • log2(..) 二进制对数(以 2 为底的对数)
      • log10(..) 以 10 为底的对数
      • log1p(..) 等价于 log(x + 1)
      • imul(..) 两个数字的 32 位整数乘法
    • 元工具:
      • sign(..) 返回数字符号
      • trunc(..) 返回数字的整数部分
      • fround(..) 向最接近的 32 位(单精度)浮点值取整

    静态函数 Number.isFinite(..)Number.isNaN(..)

    isFinite 检查一个数值是否为有限的

    • Number.isFinite(..)Number.isNaN(..)与传统的全局方法isFinite()isNaN()的区别在于:
      • 传统方法先调用Number()非数值的值转为数值,再进行判断
      • 这两个新方法只对数值有效,Number.isFinite()对于非数值一律返回false,Number.isNaN()只有对于NaN才返回true,非NaN一律返回false
    var a = NaN, b = Infinity, c = 42; 
    Number.isFinite(a); // false 
    Number.isFinite(b); // false 
    Number.isFinite(c); // true
    
    • 1
    • 2
    • 3
    • 4
    var a = "42"; 
    isFinite(a);        // true 
    Number.isFinite(a); // false
    
    • 1
    • 2
    • 3

    Number.isInteger(..)

    判断整数

    Number.isInteger(4);        // true 
    Number.isInteger(4.2;       // false
    Number.isInteger(NaN);      // false 
    Number.isInteger(Infinity); // false
    
    • 1
    • 2
    • 3
    • 4
    • 自定义 isFloat
      function isFloat(x) { 
          return Number.isFinite(x) && !Number.isInteger(x); 
      } 
      isFloat(4.2);       // true 
      isFloat(4);         // false 
      isFloat(NaN);       // false 
      isFloat(Infinity);  // false
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    Number.isSafeInteger(..)

    具检查一个值以确保其为整数并且在 Number.MIN_SAFE_INTEGER-Number.MAX_SAFE_INTEGER 范围之内(全包含)

    var x = Math.pow(2, 53), 
        y = Math.pow(-2, 53); 
    Number.isSafeInteger(x - 1);    // true 
    Number.isSafeInteger(y + 1);    // true 
    Number.isSafeInteger(x);        // false 
    Number.isSafeInteger(y);        // false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Unicode 函数

    String.fromCodePoint(0x1d49e); // "𝒞" 
    "ab𝒞d".codePointAt(2).toString(16); // "1d49e"
    
    var s1 = "e\u0301"; 
    s1.length; // 2 
    
    var s2 = s1.normalize(); 
    s2.length; // 1 
    s2 === "\xE9"; // true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    静态函数 String.raw(..)

    var str = "bc"; 
    String.raw`\ta${str}d\xE9`; 
    // '\\tabcd\\xE9', 而不是" abcdé"
    
    • 1
    • 2
    • 3

    原型函数 repeat(..)

    "foo" * 3;          // "foofoofoo"
    "foo".repeat( 3 );  // "foofoofoo"
    
    • 1
    • 2

    字符串检查函数startsWith(..)endsWidth(..)includes(..)

    var palindrome = "step on no pets"; 
    
    palindrome.startsWith("step on");   // true 
    palindrome.startsWith("on", 5);     // true 
    
    palindrome.endsWith("no pets");     // true 
    palindrome.endsWith("no", 10);      // true 
    
    palindrome.includes("on");          // true 
    palindrome.includes("on", 6);       // false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    PID学习
    Linux进程间通信方式之socket使用实例
    LED显示屏出现马赛克有哪些原因
    纵横交织的功能的单元测试
    【云备份】
    又一个微信聊天机器人横空出世了,人人可用
    ant.design 的 Pro Component 的 ProTable 清除表单内容的方法
    CSS - 快速实现悬浮吸顶,当页面滑动一定距离时固定吸附在顶部(position: sticky)
    unity Socket 客户端向服务端发送消息并实现简单远程控制
    iTOP-3568开发板Android11 proc文件系统查询
  • 原文地址:https://blog.csdn.net/weixin_43526371/article/details/127127812