跟着coderwhy学习JavaScript高级(十七)

399 阅读5分钟

ES7

includes

    const names = ["abc", "cba", "nba", "mba", NaN];
        
    if (names.indexOf("abc") !== -1) {
      console.log("包含abc")
    }

    if (names.indexOf(NaN) !== -1) {
      console.log("包含NaN"); //不会打印
    }

    if (names.includes(NaN)) {
      console.log("包含NaN"); //会打印
    }

    if (names.includes("abc")) {
      console.log("包含abc")
    }

指数运算

    const result1 = Math.pow(3,3);
    // ES7
    const result2 = 3 ** 3;

ES8

Object.values

之前可以通过Object.keys获取对象(不包括原型)中所有的key,在ES8中提供了Object.values()来获取所有的values。

    const obj = {
      name: "zhangsan",
      age: 18,
      address: [1, 2, 3, 4, 5],
      friends: {
        a: 1,
        b: 2,
        c: 3
      }
    }

    console.log(Object.keys(obj));
    console.log(Object.values(obj));

entries

通过Object.entries 可以获取到一个数组,数组中会存放可枚举属性的键值对数组

        const obj = {
      name: "zhangsan",
      age: 18,
      address: [1, 2, 3, 4, 5],
      friends: {
        a: 1,
        b: 2,
        c: 3
      }
    }
    
    Object.defineProperty(obj, "name", {
      configurable: true,
      enumerable: false,
      writable: true,
      value: "999"
    })
    // [["age","18"],["address",[1,2,3,4,5]],["friends",{a:1,b:2,c:3}]]
    console.log(Object.entries(obj))
    

String Padding

某些字符串我们需要对其进行前后的填充,来实现某种格式化效果,ES8中增加了 padStart 和 padEnd方法,分别是对字符串的首尾进行填充的。

我们简单举一个应用场景:比如需要对身份证、银行卡的前面位数进行隐藏:

    // 银行卡号
    var cardNumber = "23237532458972345234";
    // 保留后4位
    var lastFourNumber = cardNumber.slice(-4);
    // 显示最后4位,前面显示*
    var finalCard = lastFourNumber.padStart(17, "*")

    console.log(finalCard)

日期填充案例

    var date = new Date();
    var year = date.getFullYear();
    // 不满2位补充0
    var month = (date.getMonth() + 1).toString().padStart(2, '0');
     // 不满2位补充0
    var day = (date.getDate()).toString().padStart(2, '0')
    console.log(year, month, day)

Object Descriptors

Object.getOwnPropertyDescriptors()用来获取一个对象的所有自身属性的描述符。

    const obj = {
        name: "zhangsan",
        age: 18
    }
    
    Object.defineDescriptors(obj)
    

ES10

flat

方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回

    const nums = [10, 20, [2, 9], [[30, 40], [10, 45]], 78, [55, 88]]

    const flatArr = (arr) => {
      return arr.reduce((prev, cur) => {
        return prev.concat(Array.isArray(cur) ? flatArr(cur) : cur)
      }, [])
    }
    // ES10之前
    console.log(flatArr(nums))
    // flat
    console.log(nums.flat(Infinity)) 

flatMap

首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。

  • flatMap是先进行map操作,再做flat的操作;
  • flatMap中的flat相当于深度为1;
    const message = ["Hello World", "你好啊 李银河", "my name is why"];

    const msg1 = message.map(item => {
      return item.split(' ')
    })

    // [["Hello", "world"], ["你好啊", "李银河"], ["my", "name", "is", "why"]]
    const msg2 = message.flatMap(item => {
      //先map 然后flat 深度为1
      return item.split(' ')
    })

    console.log(msg1, msg2)

image.png

fromEntries

 const obj = {
      a: 1,
      b: 2,
      c: 3
    }
    // 对象转成entries ---> 遍历
    const entries = Object.entries(obj)
    entries.forEach(entry => {
      console.log(entry[0], entry[1])
    })
    // 对象转成entries ---> 遍历
    for (const [key, value] of entries) {
      console.log(key, value)
    }


    // entries转换成对象 ES10新增
    // Object.fromEntries的应用场景
    const str = "name=why&age=18&height=1.88"
    const params = new URLSearchParams(str)
    // 将entries转换为 对象
    const paramObj = Object.fromEntries(params)
    console.log(paramObj)

trimStart tirmEnd

    const message = "   Hello   World   ";
    console.log(message.trim());
    console.log(message.trimStart());
    console.log(message.trimEnd());

ES11

BigInt

在ES11之前大于MAX_SAFE_INTEGER的数值,表示的可能是不正确的。

    const maxInt = Number.MAX_SAFE_INTEGER
    console.log(maxInt + 1) // 可能表示出来不正确

    // ES11之后
    const bigInt = 99999999999999999999n;
    console.log(bigInt + 10n); //可以正确表示
    console.log(typeof bigInt); //bigInt

    const num = 10;
    // int 和 bigInt运算需要转换
    console.log(bigInt + BigInt(num));
    // bigInt 和 int运算需要转换
    console.log(num / Number(10n));

??空值合并运算符

空值合并操作符,可以在使用可选链时设置一个默认值

    const obj = {
      friend: {
        girlFriend: {
          // name: "luck"
        }
      }
    }
    // 没有可选链操作符之前
    if (obj.friend && obj.friend.girlFriend && obj.friend.girlFriend.name) {
      console.log(obj.friend.girlFriend.name)
    } else {
      console.log(undefined)
    }

    // 可选链操作符 空值合并运算符
    console.log(obj?.friend?.girlFriend?.name ?? "默认值")
    
    // 或者
    const foo = undefined; //当值是0 或者 是"" bar1有bug 
    const bar1 = foo || "default value"; 
    const bar2 = foo ?? "defualt value"; 

?.可选链操作符

允许读取位于连接对象链深处的属性值,而不必明确验证链中的每个引用是否有效。


    const obj = {
        friend: {
            girlFriend: {
                name: "luck"
            }
        }
    }
    // 没有可选链操作符之前
    if( obj.friend && obj.friend.girlFriend && obj.friend.girlFriend.name ) {
        console.log(obj.friend.girlFriend.name)
    } else {
        console.log(undefined);
    }
    
    // 可选链操作符
    console.log(obj?.friend?.girlFriend?.name);

Global This

JavaScript环境的全局对象,不同的环境获取的方式是不一样的。

  • 比如在浏览器中可以通过this、window来获取
  • 比如在Node中我们需要通过global来获取
  • ES11中对获取全局对象进行了统一的规范:globalThis
    console.log(globalThis);
    console.log(this); //浏览器上
    console.log(global); //node中

for..in标准化

  • 在ES11之前,虽然很多浏览器支持for...in来遍历对象类型,但是并没有被ECMA标准化。
  • 在ES11中,对其进行了标准化,for...in是用于遍历对象的key的:
    // for...in 标准化: ECMA
    const obj = {
      name: "why",
      age: 18
    }

    for (const item in obj) {
      console.log(item)
    }

ES12

FinalizationRegistry

  • FinalizationRegistry 提供了这样的一种方法:当一个在注册表中注册的对象被回收时,请求在某个时间点上调 用一个清理回调。(清理回调有时被称为 finalizer );
  • 可以通过调用register方法,注册任何你想要清理回调的对象,传入该对象和所含的值;
    // ES12: FinalizationRegistry类
    const finalRegistry = new FinalizationRegistry((value) => {
      console.log("注册在finalRegistry的对象, 某一个被销毁", value)
    })

    function newArr() {
      return new Array(1024 * 1024).fill(1)
    }

    //分配20个引用 让其引用保存在数组 不被释放
    var arrList = [];
    for (var i = 0; i < 20; i++) {
      setTimeout(function () {
        arrList.push(newArr())
      }, i * 100)
    }

    setTimeout(() => {
      for (var i = 0; i < 10; i++) {
        //以通过调用register方法,注册任何你想要清理回调的对象,传入该对象和所含的值
        finalRegistry.register(arrList[i], i)
      }
    }, 4000)


    // 释放10个引用  然后等待GC回收10个引用
    // 这里要注意, 释放10个 
    setTimeout(function () {
      for (var i = 0; i < 10; i++) {
        arrList.shift()
      }
    }, 5000)

image.png

WeakRefs

  • 如果我们默认将一个对象赋值给另外一个引用,那么这个引用是一个强引用。如果我们希望是一个弱引用的话,可以使用WeakRef。
    // ES12: WeakRef类
    // WeakRef.prototype.deref: 
    // > 如果原对象没有销毁, 那么可以获取到原对象
    // > 如果原对象已经销毁, 那么获取到的是undefined
    
    let obj = { name: "why" };
    let info = new WeakRef(obj);

    // 置空 info是弱引用 会被回收的
    obj = null

    // 被回收之前 能够打印
    console.log(info.deref()?.name)

    // 等待GC回收obj 我们再来打印弱引用  info.deref()不存在的话会返回 undefined
    // 这里假设是10秒回收,但是具体多久回收 我也不知道
    setTimeout(() => {
      // 用可选链 + 空值合并
      console.log(info.deref()?.name ?? "啥也没有")
      // 如果不用可选链
      console.log(info.deref() && info.deref().name)
    }, 10000)
 

logical assignment operators

    // 1.逻辑或运算符
    let message = ""

    message = message || "Hello World";
    message ||= "Hello World";


    // 2.逻辑与操作符
    let obj = {
      name: "why",
      foo() {
        console.log('123')
      }
    }
    obj0 = obj && obj.foo;
    obj0()
    
    obj &&= obj.name;

    // 逻辑空运算符
    let foo = null;
    foo ??= "默认值"
    console.log(foo)