范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

了解ES6ES12的特性

  ECMAScript 是一种由 Ecma国际 (前身为欧洲计算机制造商协会 ,European Computer Manufacturers Association)通过ECMA-262标准化的脚本程序设计语言 。也可以说是JavaScript的一个标准
  在程序员的世界只有两个版本: ES5    和 ES6   ,说是ES6,实际上是2015年发布的,也是大前端时代正式开始的时间,也就是说以2015年为界限,2015年之前叫 ES5    ,2016年之后则统称ES6
  关于 ES6   特性的可看看阮一峰老师的《ES6标准入门》 ES6
  声明
  let & const
  let、const 和 var 之间的区别: var 声明的变量存在变量提升,而 let、const 不存在变量提升的问题。 变量提升:变量是否可在声明前调用 var 不存在块级作用域,let 和 const 存在块级作用域 var 可以重复声明变量,let 和 const 在一个作用域内不允许重复声明,并且 const 声明的是一个  只读  的变量,并且一定要 赋值
  另外,当 const   声明了一个对象,对象能的属性可以改变,因为:const声明的obj只保存着其对象的引用地址,只要地址不变,便不会出错
  解构赋值
  数组的解构 按次序排列 可以从数组中提取值,按照对应位置,对变量赋值,这种写法属于 模式匹配 可以使用  ...   进行解构,代表剩余全部如果原数组没有,则在对应值上可设置默认值,如果不设置,则为 undefined    let [a, b, c] = [1, 2, 3]  console.log(a, b, c) // 1 2 3    let [a, , c] = [1, 2, 3]  console.log(a, , c) // 1 3    let [a, b, ...c] = [1, 2, 3, 4, 5]  console.log(a, b, c) // 1 2 [3, 4, 5]    let [a, b, ...c] = [1]  console.log(a, b, c) // 1 undefined []    let [a = 1, b = a] = []  const.log(a, b) // 1 1    let [a = 1, b = a] = [2]  const.log(a, b) // 2 2
  对象的结构 无次序行,只需变量与属性名同名即可 如果变量和对象的属性名没有重复,则会导致变量的值为 undefined   注意 :   ,他相当于别名 let { a, b } = { a: 1, b: 2 };  console.log(a, b);  // 1 2    let { a } = { b: 2 };  console.log(a);  // undefined    let { a, b = 2 } = { a: 1 };  console.log(a, b);  // 1 2    let { a: b = 2 } = { a: 1 };  console.log(a);  // 不存在 a 这个变量  console.log(b);  // 1
  对字符串的解构 字符串也可以进行解构,它相当于转化为类似数组的对象 自带一个  length    属性,代表个数 let [a, b, c, d, e] = "hello"  console.log(a, b, c, d, e) // h e l l o    let { length } = "hello"  console.log(length) // 5
  对数字和布尔值的解构 解构的只要不死对象或数组,都会先将其转化为对象,所以数字类型和布尔类型也换转化为对象  let { toString: s } = 123;  console.log(s === Number.prototype.toString) // true    let { toString: s } = true;  console.log(s === Boolean.prototype.toString) // true
  对函数参数的解构 函数的参数可以进行解构,也可以带有默认值 undefined 可以触发默认值 注意两种指定默认值的方法,一种是对变量指定,一种是对参数指定,会得到不同的答案  let arr = [[1,2], [3, 4]]  let res = arr.map([a, b] => a + b)  console.log(res) // [3, 7]    let arr = [1, undefined, 2]  let res = arr.map((a = "test") => a);  console.log(res) // [1, "test", 2]    let func = ({x, y} = {x: 0, y: 0}) => {     return [x, y]  }  console.log(func(1, 2)) // [undefined, undefined]  console.log(func()) // [0, 0]  console.log(func({})) // [undefined, undefined]  console.log(func({x: 1})) // [1, undefined]      let func = ({x=0, y=0}) => {     return [x, y]  }    console.log(func(1, 2)) // [1, 2]  console.log(func()) // [0, 0]  console.log(func({})) // [0, 0]   console.log(func({x: 1})) // [1, 0]
  正则扩展
  正则其实是一个非常难懂的知识点,要是有人能完全掌握,那真的是非常厉害,在这里就简单的说下
  首先分为两种风格: JS分格    和 perl 分格
  JS分格: RegExp()  let re = new RegExp("a"); //查找一个字符串内是否有a  let re = new RegExp("a", "i"); //第一个是查找的对象,第二个是选项
  perl风格: / 规则 /选项,且可以跟多个,不分顺序  let re = /a/; //查找一个字符串内是否有a  let re = /a/i;//第一个是查找的对象,第二个是选项
  这里介绍一个正则表达式在线测试(附有常见的正则表达式): 正则在线测试
  字符串扩展  Unicode :  大括号包含   表示Unicode字符codePointAt() : 返回字符对应码点,与fromCharCode()对应 String.fromCharCode() : 将对对应的码点返回为字符,与codePointAt()对应 String.raw() :返回把字符串所有变量替换且对斜杠进行转义的结果 startsWith() : 返回布尔值,表示参数字符串是否在原字符串的头部。 endsWith() :返回布尔值,表示参数字符串是否在原字符串的尾部。 repeat() :方法返回一个新字符串,表示将原字符串重复n次 遍历:for-of includes() :返回布尔值,表示是否找到了参数字符串。 trimStart() : 方法从字符串的开头删除空格。trimLeft() 是此方法的别名。 trimEnd() : 方法从一个字符串的末端移除空白字符。trimRight() 是这个方法的别名。  //Unicode  console.log("a", "a"); // a a  console.log("d", "u{4E25}"); // d 严    let str = "Domesy"    //codePointAt()  console.log(str.codePointAt(0)) // 68    //String.fromCharCode()  console.log(String.fromCharCode(68)) // D    //String.raw()  console.log(String.raw`Hi ${1 + 2}`); // Hi 3  console.log(`Hi ${1 + 2}`); // Hi 3    let str = "Domesy"    //startsWith()  console.log(str.startsWith("D")) // true  console.log(str.startsWith("s")) // false   //endsWith()  console.log(str.endsWith("y")) // true  console.log(str.endsWith("s")) // false    //repeat(): 所传的参数会自动向上取整,如果是字符串会转化为数字  console.log(str.repeat(2)) // DomesyDomesy  console.log(str.repeat(2.9)) // DomesyDomesy    // 遍历:for-of   for(let code of str){     console.log(code) // 一次返回 D o m e s y   }      //includes()   console.log(str.includes("s")) // true   console.log(str.includes("a")) // false      // trimStart()   const string = "   Hello world!   ";   console.log(string.trimStart()); // "Hello world!   "   console.log(string.trimLeft()); // "Hello world!   "      // trimEnd()   const string = "   Hello world!   ";   console.log(string.trimEnd()); // "   Hello world!"   console.log(string.trimRight()); // "   Hello world!"
  其他
  字符串模板 可单行可多行插入,使用 `  let str = `Dome     sy`  console.log(str) //会自动换行    // Dome  // sy
  标签模板:  const str = {      name: "小杜杜",      info: "大家好‘  }  console.log(`${str.info}, 我是`${str.name}`) // 大家好,我是小杜杜
  数组扩展  Array.of() : 将一组值转化为数组,返回一个新数组,并且不考虑参数的数量或类型。 copyWithin() :把指定位置的成员复制到其他位置,返回 原数组 find() : 返回第一个符合条件的值 findIndex() : 返回第一个符合条件的索引 keys() :对键名的遍历,返回一个遍历器对象,可用 for-of 循环, values() :与 keys() 用法一样,不过是对 键值 的遍历 entries() :与 keys() 用法一样,不过是对 键值对 的遍历 Array.from() : 从一个类似数组或可迭代对象中创建一个新的数组实例。 fill() : 使用制定的元素填充数组,返回 原数组 includes() :判断是否包含某一元素,返回布尔值,对 NaN 也有效,但不能进行定位  let arr = [1, 2, 3, 4, 5]   //Array.of()  let arr1 = Array.of(1, 2, 3);  console.log(arr1) // [1, 2, 3]    //copyWithin(): 三个参数 (target, start = 0, end = this.length)  // target: 目标的位置  // start: 开始位置,可以省略,可以是负数。  // end: 结束位置,可以省略,可以是负数,实际位置是end-1。  console.log(arr.copyWithin(0, 3, 5)) // [4, 5, 3, 4, 5]    //find()  console.log(arr.find((item) => item > 3 )) // 4    //findIndex()  console.log(arr.findIndex((item) => item > 3 )) // 3    // keys()  for (let index of arr.keys()) {      console.log(index); // 一次返回 0 1 2 3 4  }    // values()  for (let index of arr.values()) {      console.log(index); // 一次返回 1 2 3 4 5  }    // entries()  for (let index of arr.entries()) {      console.log(index); // 一次返回 [0, 1] [1, 2] [2, 3] [3, 4] [4, 5]  }     let arr = [1, 2, 3, 4, 5]    // Array.from(): 遍历的可以是伪数组,如 String、Set结构,Node节点  let arr1 = Array.from([1, 3, 5], (item) => {      return item * 2;  })  console.log(arr1) // [2, 6, 10]     // fill(): 三个参数 (target, start = 0, end = this.length)  // target: 目标的位置  // start: 开始位置,可以省略,可以是负数。  // end: 结束位置,可以省略,可以是负数,实际位置是end-1。  console.log(arr.fill(7)) // [7, 7, 7, 7, 7]  console.log(arr.fill(7, 1, 3)) // [1, 7, 7, 4, 5]    let arr = [1, 2, 3, 4]    //includes()  console.log(arr.includes(3)) // true  console.log([1, 2, NaN].includes(NaN)); // true
  其他
  扩展运算符:...  // 其作用为展开数组  let arr = [3, 4, 5]  console.log(...arr) // 3 4 5    let arr1 = [1, 2, ...arr]  console.log(...arr) // 1 2 3 4 5
  对象扩展  Object.getPrototypeOf() :返回对象的原型对象 Object.setPrototypeOf() :设置对象的原型对象 proto :返回或设置对象的原型对象 Object.getOwnPropertyNames() : 返回对象自身非Symbol属性键组成的数组 Object.getOwnPropertySymbols() : 返回对象自身非Symbol属性键组成的数组 Reflect.ownKeys() : 返回对象自身全部属性键组成的数组 Object.is() :判断两个对象是否相等, 数组指向的地址不同,所以只要是数组比较,必定为 false 遍历: for-in   Object.keys() :返回属性名 Object.assign() : 用于将所有可枚举属性的值从一个或多个源对象复制到目标对象,返回目标对象, 此时的目标对象也会改变 //Object.is() console.log(Object.is("abc", "abc")) // true console.log(Object.is([], [])) // false   //遍历:for-in let obj = { name: "Domesy", value: "React" }  for(let key in obj){     console.log(key); // 依次返回属性值 name value     console.log(obj[key]); // 依次返回属性值 Domesy React }  //Object.keys() console.log(Object.keys(obj)) // ["name", "value"]   //Object.assign()  const target = { a: 1, b: 2 };  const source = { b: 4, c: 5 };    const result = Object.assign(target, source)    console.log(result) // {a: 1, b: 4, c: 5}  console.log(target) // {a: 1, b: 4, c: 5}
  其他
  简洁表示法   let a = 1;   let b = 2;   let obj = { a, b }   console.log(obj) // { a: 1, b: 2 }      let method = {       hello() {           console.log("hello")       }   }   console.log(method.hello())// hello
  属性表达式: 直接用变量或者表达式来定义 Object 的 key  let a = "b"  let obj = {      [a]: "c"  }  console.log(obj) // {b : "c"}
  扩展运算符 ... 在 ES9 中增加了许多额外的功能,如合并、转义字符串等操作  // 其作用为展开数组  let { a, b, ...c } = { a: 1, b: 2, c: 3, d: 4};  console.log(c) // {c: 3, d: 4}    let obj1 = { c: 3 }  let obj = { a: 1, b: 2, ...obj1}  console.log(obj) // { a: 1, b: 2, c: 3}
  数值扩展  二进制 : 0b    或 0B    开头,表示二进制八进制 : 00    或 0O    开头,表示二进制Number.isFinite() : 用来检查一个数值是否有限的,返回布尔值 Number.isNaN() : 用来检查一个数值是否是 NaN,返回布尔值 Number.isInteger() : 用来检查一个数值是否是整数,返回布尔值 Number.isSafeInteger() : 用来检查一个数值是否是"安全整数"(safe integer),返回布尔值 Math.cbrt() : 返回立方跟 Math.abrt()() : 返回立方跟 Math.cbrt() : 返回立方跟 Math.clz32() : 返回数值的32位无符号整数形式 Math.imul() : 返回两个数值相乘 Math.fround() : 返回数值的32位单精度浮点数形式 Math.hypot() : 返回所有数值平方和的平方根 Math.expm1() : 返回e^n - 1 Math.log1p() : 返回1 + n的自然对数(Math.log(1 + n)) Math.log10() : 返回以10为底的n的对数 Math.log2() : 返回以2为底的n的对数 Math.trunc() : 将数字的小数部分去掉,只保留整数部分 Math.sign() : 返回数值类型  正数为1   、负数为-1   、正零 0   、负零 -0   、NaN   Math.abrt() : 返回立方根 Math.sinh() : 返回双曲正弦 Math.cosh() : 返回双曲余弦 Math.tanh() : 返回双曲正切 Math.asinh() : 返回反双曲正弦 Math.acosh() : 返回反双曲余弦 Math.atanh() : 返回反双曲正切 Number.parseInt() : 返回值的整数部分,此方法等价于  parseInt   Number.parseFloat() : 返回值得浮点数部分,此方法等价于  parseFloat    //二进制  console.log(0b101) // 5  console.log(0o151) //105    //Number.isFinite()  console.log(Number.isFinite(7)); // true  console.log(Number.isFinite(true)); // false    //Number.isNaN()  console.log(Number.isNaN(NaN)); // true  console.log(Number.isNaN("true" / 0)); // true  console.log(Number.isNaN(true)); // false    //Number.isInteger()  console.log(Number.isInteger(17)); // true  console.log(Number.isInteger(17.58)); // false    //Number.isSafeInteger()  console.log(Number.isSafeInteger(3)); // true  console.log(Number.isSafeInteger(3.0)); // true  console.log(Number.isSafeInteger("3")); // false  console.log(Number.isSafeInteger(3.1)); // false     //Math.trunc()  console.log(Math.trunc(13.71)); // 13  console.log(Math.trunc(0)); // 0  console.log(Math.trunc(true)); // 1  console.log(Math.trunc(false)); // 0     //Math.sign()  console.log(Math.sign(3)); // 1  console.log(Math.sign(-3)); // -1  console.log(Math.sign(0)); // 0  console.log(Math.sign(-0)); // -0  console.log(Math.sign(NaN)); // NaN  console.log(Math.sign(true)); // 1  console.log(Math.sign(false)); // 0    //Math.abrt()  console.log(Math.cbrt(8)); // 2     //Number.parseInt()  console.log(Number.parseInt("6.71")); // 6  console.log(parseInt("6.71")); // 6    //Number.parseFloat()  console.log(Number.parseFloat("6.71@")); // 6.71  console.log(parseFloat("6.71@")); // 6.71
  函数扩展  函数参数尾逗号:允许函数最后一个参数有尾逗号 参数默认赋值具体的数值  //参数默认赋值具体的数值  let x = 1  function fun(x, y = x){     console.log(x, y)  }  function fun1(c, y = x){     console.log(c, x, y)  }  fun(2); //2 2  fun1(1); //1 1 1
  其他
  Rest参数(扩展运算符 ...)  function fun(...arg){    console.log(arg) // [1, 2, 3, 4]  }    fun(1, 2, 3, 4)
  箭头函数 以 => 定义函数  let arrow = (v) => v + 2  console.log(arrow(1)) // 3
  箭头函数与普通函数的区别 箭头函数和普通函数的样式不同,箭头函数语法更加简洁、清晰,箭头函数是  =>定义函数 ,普通函数是  function定义函数 。 Set 没有键只有值,可以认为 键和值 都一样 箭头函数其实是没有 this 的,箭头函数中的 this 只取决包裹箭头函数的第一个普通函数的 this。 箭头函数没有自己的arguments。在箭头函数中访问arguments实际上获得的是外层局部(函数)执行环境中的值。 call、apply、bind  并不会影响其 this 的指向。 箭头函数的this指向上下文  ,而  普通函数的this并非指向上下文,需要时加入 bind(this)
  Set
  Set 是ES6中新的数据结构,是类似数组, 但成员的值是唯一的,没有重复的值
  声明: const set = new Set()
  属性: size :返回 Set 对象中值的个数
  方法: add() : 在Set对象尾部添加一个元素。返回该Set对象 delete() : 移除Set的中与这个值相等的元素,有则返回true,无则返回false clear() : 清楚Set的所有元素 has() : 是否存在这个值,如果存在为 true,否则为false keys() :以属性值遍历器的对象 values() :以属性值遍历器的对象 entries() :以属性值和属性值遍历器的对象 forEach() :遍历每个元素
  特别注意: 遍历器的为 iterator   对象,按插入顺序,为 [Key, Value] 形式加入 Set 的值不会发生类型转化,所以1和"1"是两个不同的值 在Set内部是通过 === 来判断,也就是说,两个对象永远不可能相同,原因是地址不同 唯一的区别是 NaN  let list = new Set()    //add()  list.add("1")  list.add(1)  console(list) // Set(2) {1, "1"}    //size  console(list.size) // 2    //delete()  list.delete("1")  console(list) // Set(1) {1}    //has()  list.has(1) // true  list.has(3) // false    //clear()  list.clear()  console(list) // Set(0) {}    let arr = [{id: 1}, {id: 2}, {id: 3}]  let list = new Set(arr)    // keys()  for (let key of list.keys()) {     console.log(key); // 以此打印:{id: 1} {id: 2} {id: 3}  }    //values()  for (let key of list.values()) {     console.log(key); // 以此打印:{id: 1} {id: 2} {id: 3}  }    //entries()  for (let data of list.entries()) {     console.log(data); // 以此打印:[{id: 1},{id: 1}] [{id: 2},{id: 2}] [{id: 3},{id: 3}]  }    //forEach  list.forEach((item) => {     console.log(item)// 以此打印:{id: 1} {id: 2} {id: 3}  });
  应用:
  数组去重 需要注意一点的是  new Set    无法去除对象 let arr = [1,1,"true","true",true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,"NaN", 0, 0, "a", "a"];    console.log([...new Set(arr)])   //或   console.log(Array.from(new Set(arr)))  //  [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a"]
  可求并集,交集和差集  let a = new Set([1, 2, 3])  let b = new Set([2, 3, 4])    //并集  console.log(new Set([...a, ...b])) // Set(4) {1, 2, 3, 4}    //交集  console.log(new Set([...a].filter(v => b.has(v)))) // Set(2) {2, 3}    //差集  new Set([...a].filter(v => !b.has(v))) //  Set(1) {1}
  映射集合  let set = new Set([1,2,3])  console.log(new Set([...set].map(v => v * 2))) // Set(3) {2, 4, 6}
  WeakSet
  定义: 和Set的结构,但 成员值只能为对象
  声明:  const set = new WeakSet()
  方法: add() : 在WeakSet对象尾部添加一个元素。返回该实例 delete() : 移除WeakSet的中与这个值相等的元素, has() : 是否存在这个值,如果存在为 true,否则为false
  注意: WeakSet 成员的对象都是弱引用,即垃圾回收机制不考虑该对象的应用。简单地说 WebSet 的对象无法遍历 好处是,再删除实例的时候,不会出现内存泄露
  Map
  推荐指数:
  Map 是ES6中新的数据结构,是类似对象,成员键是任何类型的值
  声明: const set = new Map()
  属性: constructor : 构造函数,返回Map size :返回 Map 实例中值的个数
  方法: set() : 添加Map后的一个键值对,返回实例 get() : 返回键值对 delete() : 移除Map的中与这个值相等的元素,有则返回true,无则返回false clear() : 清楚Map的所有元素 has() : 是否存在这个值,如果存在为 true,否则为false keys() :以属性键遍历器的对象 values() :以属性值遍历器的对象 entries() :以属性键和属性值遍历器的对象 forEach() :遍历每个元素
  特别注意: 对同一个对象的引用,被视为一个键 相同的键,会进行覆盖  let map = new Set()    //set()  map.set("a", 1)  map.set("b", 2)  console(map) // Map(2) {"a" => 1, "b" => 2}    //get  map.get("a") // 1    //size  console(map.size) // 2    //delete()  map.delete("a") // true  console(map) // Map(1) {"b" => 2}    //has()  map.has("b") // true  map.has(1) // false    //clear()  map.clear()  console(map) // Map(0) {}    let arr = [["a", 1], ["b", 2], ["c", 3]]  let map = new Map(arr)    // keys()  for (let key of map.keys()) {     console.log(key); // 以此打印:a b c  }    //values()  for (let value of map.values()) {     console.log(value); // 以此打印:1 2 3  }    //entries()  for (let data of map.entries()) {     console.log(data); // 以此打印:["a", 1] ["b", 2] ["c", 3]  }    //forEach  map.forEach((item) => {     console.log(item)// 以此打印:1 2 3  });
  WeakMap
  定义: 和Map的结构,但 成员值只能为对象
  声明:  const set = new WeakMap()
  方法: set() : 添加键值对,返回实例 get() : 返回键值对 delete() : 删除键值对,如果存在为 true,否则为false has() : 是否存在这个值,如果存在为 true,否则为false
  Symbol(原始类型)
  Symbol 是ES6中引入的原始数据类型,代表着 独一无二   的
  声明: const sy = Stmbol()
  参数: string(可选)
  方法: Symbol.for() : 创建以参数作为描述的 Symbol值   ,如存在此参数则返回原有的Symbol值   (先搜索后创建,登记在全局环境)Symbol.keyFor() :返回已登记的 Symbol值   的描述(只能返回Symbol.for()   的key   )Object.getOwnPropertySymbols()  :返回对象中所有用作属性名的 Symbol值   的数组 // 声明  let a = Symbol();  let b = Symbol();  console.log(a === b); // false    //Symbol.for()  let c = Symbol.for("domesy");  let d = Symbol.for("domesy");  console.log(c === d); // true    //Symbol.keyFor()  const e = Symbol.for("1");  console.log(Symbol.keyFor(e)); // 1    //Symbol.description  let symbol = Symbol("es");  console.log(symbol.description); // es  console.log(Symbol("es") === Symbol("es")); // false  console.log(symbol === symbol); // true  console.log(symbol.description === "es"); // true
  Proxy
  Proxy用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种"元编程"(meta programming),即对编程语言进行编程
  可以这样理解,Proxy就是在目标对象之前设置的一层 拦截   ,外界想要访问都要经过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
  Proxy 在这里可以理解为 代理器
  声明:  const proxy = new Proxy(target, handler)   target : 拦截的对象 handler : 定义拦截的方法
  方法: get() : 拦截对象属性的读取 set() : 拦截对象设置属性,返回一个布尔值 has() : 拦截 propKey in proxy 的操作,返回一个布尔值 ownKeys() : 拦截对象属性遍历,返回一个数组 deleteProperty() :拦截 delete proxy[propKey] 的操作,返回一个布尔值() apply() :拦截函数的调用,call 和 apply 操作 construct() :拦截 new 命令,返回一个对象: 拦截 new 命令,返回一个对象  let obj = {   name: "domesy",   time: "2022-01-27",   value: 1  }    let data = new Proxy(obj, {      //get()      get(target, key){          return target[key].replace("2022", "2015")      },            //set()      set(target, key, value) {         if (key === "name") {            return (target[key] = value);         } else {            return target[key];          }      },            // has()     has(target, key) {         if (key === "name") {             return target[key];         } else {             return false;         }     },     // deleteProperty()     deleteProperty(target, key) {         if (key.indexOf("_") > -1) {             delete target[key];             return true;         } else {             return target[key];         }     },     // ownKeys()     ownKeys(target) {         return Object.keys(target).filter((item) => item != "time");     },  })    console.log(data.time) // 2015-01-27    data.time = "2020"  data.name = "React"  console.log(data) //Proxy {name: "React", time: "2022-01-27", value: 1}    // 拦截has()  console.log("name" in data) // true  console.log("time" in data) // false    // 删除deleteProperty()  delete monitor.time; // true    // 遍历 ownKeys()  console.log(Object.keys(data)); //["name", "value"]   //apply()  let sum = (...args) => {     let num = 0;     args.forEach((item) => {         num += item;     });     return num;  };   sum = new Proxy(sum, {     apply(target, ctx, args) {         return target(...args) * 2;     },  });    console.log(sum(1, 2)); // 6  console.log(sum.call(null, 1, 2, 3)); // 12  console.log(sum.apply(null, [1, 2, 3])); // 12    //constructor()  let User = class {     constructor(name) {         this.name = name;     }  }  User = new Proxy(User, {     construct(target, args, newTarget) {         return new target(...args);     },   });  console.log(new User("domesy")); // User {name: "domesy"}
  Reflect
  Reflect 与 Proxy 类似,只是保持 Object   的默认行为将 Object 对象的一些明显属于语言内部的方法(比如 Object.defineProperty),放到 Reflect 对象上。 现阶段,某些方法同时在 Object 和 Reflect 对象上部署,未来的新方法将只部署在 Reflect 对象上 修改某些 Object 方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而 Reflect.defineProperty(obj, name, desc)则会返回 false 让Object 操作变成函数行为
  Reflect 的方法与 Proxy 的方法一一对应,这里就不进行介绍了
  Class
  Class: 对一类具有共同特征的事物的抽象(构造函数语法糖)
  constructor() 基本定义和生成实例  class Parent {      constructor(name = "es6"){          this.name = name      }  }  let data = new Parent("domesy")  console.log(data) // Parent { name: "domesy"}
  extends 继承  class Parent {      constructor(name = "es6"){          this.name = name      }  }    // 普通继承  class Child extends Parent {}  console.log(new Child()) //  Child { name: "es6"}     // 传递参数  class Child extends Parent {     constructor(name = "child") {         super(name);         this.type = "child";     }  }  console.log(new Child("domesy")) //  Child { name: "domesy", type: "child"}
  getter setter 这个两个方法比较重要,常常用来封装API get 和 set 是属性,而不是方法  class Parent {      constructor(name = "es6"){          this.name = name      }      // getter      get getName() {          return "sy" + this.name      }       // setter      set setName(value){          this.name = value      }  }    let data = new Parent()  console.log(data.getName) // syes6    data.setName = "domesy"  console.log(data.getName) // domesy
  static 静态方法 静态方法,不能在类的实例上调用静态方法,而应该通过类本身调用  class Parent {      static getName = (name) => {          return `你好!${name}`      }  }    console.log(Parent.getName("domesy")) // 你好!domesy
  静态属性  class Parent {}  Parent.type = "test";    console.log(Parent.type); //test
  Promise
  Promise    就是为了解决"回调地狱"问题的,它可以将异步操作的处理变得很优雅。
  Promise    可以支持多个并发的请求,获取并发请求中的数据这个 Promise    可以解决异步的问题,本身不能说 Promise    是异步的
  定义: 包含异步操作结果的对象
  状态: pending: [待定]初始状态 fulfilled: [实现]操作成功 rejected:  [被否决]操作失败
  注意: Promise 会根据状态来确定执行哪个方法 Promise 实例化时状态默认为 pending 的, 如异步状态异常rejected,反之fulfilled 状态转化是单向的,不可逆转 ,已经确定的状态(fulfilled/rejected)无法转回初始状态(pending),而且 只能是从 pending 到 fulfilled 或者 rejected
  基本用法  //普通定义  let ajax = (callback) => {      console.log(" ")      setTimeout(() => {          callback && callback.call();      }, 1000)  }   ajax(() => {      console.log("timeout")  })  // 先会打出 开始执行,1s 后打出 timeout    //Promise  let ajax = () => {     console.log("开始执行");     return new Promise((resolve, reject) => {         setTimeout(() => {             resolve();         }, 1000);     });  };  ajax().then(() => {     console.log("timeout");   });  // 先会打出 开始执行,1s 后打出 timeout    // then()  let ajax = () => {     console.log("开始执行");     return new Promise((resolve, reject) => {         setTimeout(() => {             resolve();         }, 1000);     });  };  ajax()  .then(() => {      return new Promise((resolve, reject) => {         setTimeout(() => {             resolve();         }, 2000);     });  })  .then(() => {      console.log("timeout")  })  // 先会打出 开始执行,3s(1+2) 后打出 timeout    // catch()  let ajax = (num) => {     console.log("开始执行");     return new Promise((resolve, reject) => {         if (num > 5) {             resolve();         } else {             throw new Error("出错了");         }     });  };    ajax(6)  .then(function () {     console.log("timeout"); //  先会打出 开始执行,1s 后打出 timeout  })  .catch(function (err) {     console.log("catch", err);  });     ajax(3)  .then(function () {     console.log("timeout");   })  .catch(function (err) {     console.log("catch"); //  先会打出 开始执行,1s 后打出 catch  });
  Promise.all() 批量操作 Promise.all(arr)用于将多个promise实例,包装成一个新的Promise实例,返回的实例就是普通的promise 它接收一个数 组作 为参数 数组里可以是Promise对象,也可以是别的值,只有Promise会等待状态改变 当所有的子Promise都完成,该Promise完成,返回值是全部值得数组 有任何一个失败,该Promise失败,返回值是第一个失败的子Promise结果  //所有图片加载完成后添加到页面  const loadImg = (src) => {      return new Promise(resolve, reject) => {         let img = document.createElement("img");         img.src = src;         img.onload = function () {                 resolve(img);         };         img.onerror = function (err) {                 reject(err);         };     });  }    const showImgs = (imgs) => {      imgs.forEach((img) => {          document.body.appendChild(img);      })  }    Promise.all([     loadImg("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/71cf3bc79f3df8dcc6551159cd11728b46102889.jpg"),     loadImg("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/71cf3bc79f3df8dcc6551159cd11728b46102889.jpg"),     loadImg("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/71cf3bc79f3df8dcc6551159cd11728b46102889.jpg"),  ]).then(showImgs);
  Promise.race() race 与 all相似,只不过只要有一个执行完就会执行 //有一个执行完就回加载到页面 const loadImg = (src) => {     return new Promise(resolve, reject) => {        let img = document.createElement("img");        img.src = src;        img.onload = function () {                resolve(img);        };        img.onerror = function (err) {                reject(err);        };    }); }  const showImgs = (imgs) => {    let p = document.createElement("p");    p.appendChild(img);    document.body.appendChild(p); }  Promise.race([    loadImg("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/71cf3bc79f3df8dcc6551159cd11728b46102889.jpg"),    loadImg("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/71cf3bc79f3df8dcc6551159cd11728b46102889.jpg"),    loadImg("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/71cf3bc79f3df8dcc6551159cd11728b46102889.jpg"), ]).then(showImgs);
  Promise的问题 一旦执行,无法中途取消,链式调用多个then中间不能随便跳出来 错误无法在外部被捕捉到,只能在内部进行预判处理,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部 Promise内部如何执行,监测起来很难,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
  Generator
  Generator: 是可以用来控制迭代器的函数,也是封装多个内部状态的异步编程解决方案,也叫 生成器函数
  参数说明 yield 来 控制程序内部的执行的 "暂停" ,并返回一个对象,这个对象包括两个属性: value    和 done   其中  value    代表值, done   返回布尔(如果为false,代表后续还有,为true则已完成)next 来 恢复   程序执行Generator  函数的定义不能使用箭头函数 ,否则会触发 SyntaxError 错误  let data = function* (){      yield "a";      yield "b";      return "c"  }    let generator = data();  console.log(generator.next()) //{value: "a", done: false}   console.log(generator.next()) //{value: "b", done: false}   console.log(generator.next()) //{value: "c", done: true}   console.log(generator.next()) //{value: undefined, done: true}
  Iterator 遍历器
  Iterator是一种接口,为各种不同的数据结构提供统一的访问机制。 任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
  Iterator的作用: 一是为各种数据结构,提供一个统一的、简便的访问接口 使得数据结构的成员能够按某种次序排列 ES6创造了一种新的遍历命令for...of循环, Iterator接口主要供for...of消费 for-in遍历顺序:不同的引擎已就如何迭代属性达成一致,从而使行为标准化  ES11
  注意: 在ES6中,有些数据结构原生具备Iterator接口(比如数组),即不用任何处理,就可以被for...of循环遍历,有些就不行(比如对象) 在ES6中,有三类数据结构原生具备Iterator接口: 数组   、某些类似数组的对象   、Set   和Map结构   。一个为对象添加Iterator接口的例子。  // 基本使用  let arr = ["hello", "world"];  let map = arr[Symbol.iterator]();  console.log(map.next()); // {value: "hello", done: false}  console.log(map.next()); // {value: "world", done: false}  console.log(map.next()); // {value: undefined, done: true}    // for of 循环  let arr = ["hello", "world"];  for (let value of arr) {     console.log(value); // hello world  }    // 对象处理  let obj = {      start: [1, 5, 2],      end: [7, 9, 6],      [Symbol.iterator](){          let index = 0;          let arr = this.start.concat(this.end)          return {              next(){                  if(index < arr.length){                      return {                          value: arr[index++],                          done: false                      }                  }else{                      return {                          value: arr[index++],                          done: true                      }                  }              }          }      }  }  for (let key of obj) {     console.log(key); // 1 5 2 7 9 6  }
  Decorator 装饰器  使用 @   符号,用来扩展,修改类的行为使用的时候需要引入第三方库 如:  core-decorators    const name = (target) => {      target.name = "domesy"  }    @name  class Test{}    console.log(Test.name) //domesy
  模块化
  在早期,使用立即执行函数实现模块化是常见的手段,通过函数作用域解决了命名冲突、污染全局作用域的问题
  使用模块化的好处: 解决命名冲突 提供复用性 提高代码可维护性
  方案: CommonJS :用于服务器(动态化依赖) AMD :用于浏览器(动态化依赖,使用的很少) CMD :用于浏览器(动态化依赖,使用的很少) UMD :用于浏览器和服务器(动态化依赖) ESM :用于浏览器和服务器(静态化依赖)
  export 导出模块 默认导出:  export default Index   单独导出: `export const name = "domesy" 按需导出(推荐): `export { name, value, id }" 改名导出: export { name as newName }
  import 导入模块 默认导入(推荐):  import Index from "./Index"   整体导入:  import * as Index from "./Index"   按需导入(推荐):  import { name, value, id } from "./Index"   改名导入:  import { name as newName } from "./Index"   自执导入:  import "./Index"   符合导入(推荐):  import Index, { name, value, id } from "./Index"
  复合模式
  export命令   和import命令   结合在一起写成一行,变量实质没有被导入当前模块,相当于对外转发接口,导致当前模块无法直接使用其导入变量,适用于 全部子模块导出默认导入导出: `export { default } from "./Index" 整体导入导出: `export * from "./Index" 按需导入导出: `export { name, value, id } from "./Index" 默认改具名导入导出: `export { default as name } from "./Index" ES7
  数组扩展  includes() : 在ES6 的基础上增加了一个索引,代表是从哪寻找 ES7  let arr = [1, 2, 3, 4]    //includes() ES6  console.log(arr.includes(3)) // true  console.log([1, 2, NaN].includes(NaN)); // true    // includes() ES7  console.log(arr.includes(1, 0)) // true  console.log(arr.includes(1, 1)) // false
  数值扩展  幂运算符 :用  **    代表 Math.pow()      // 幂运算符 ES7  console.log(Math.pow(2, 3)) // 8  console.log(2 ** 8) // 256 ES8
  字符传扩展  padStart() :用于头部补全 padEnd() :用于尾部补全。  let str = "Domesy"    //padStart(): 会以空格的形式补位吗,这里用0代替,第二个参数会定义一个模板形式,会以模板进行替换  console.log("1".padStart(2, "0")); // 01  console.log("8-27".padStart(10, "YYYY-0M-0D")); //  YYYY-08-27     // padEnd():与padStart()用法相同  console.log("1".padEnd(2, "0")); // 10
  对象扩展  Object.values():返回属性值 Object.entries():返回属性名和属性值的数组 let obj = { name: "Domesy", value: "React" }  //Object.values() console.log(Object.values(obj)) // ["React", "React"]  //Object.entries() console.log(Object.entries(obj)) // [["name", "value"], ["React", "React"]]
  async await
  作用:  将异步函数改为同步函数 ,(Generator的语法糖)  const func = async () => {     let promise = new Promise((resolve, reject) => {     setTimeout(() => {           resolve("执行");         }, 1000);     });             console.log(await promise);       console.log(await 0);       console.log(await Promise.resolve(1));       console.log(2);       return Promise.resolve(3);  }    func().then(val => {       console.log(val); // 依次执行: 执行 0 1 2 3  });
  特别注意: Async 函数 返回  Promise   对象,因此可以使用 then   awit 命令, 只能用在 async 函数下,否则会报错 数组的  forEach()    执行 async/await   会失效,可以使用 for-of    和 Promise.all()   代替无法处理 promise 返回的  reject    对象,需要使用 try catch    来捕捉
  awiait 等到了之后做了什么?
  这里分为两种情况: 是否为 promise 对象
  如果不是promise , await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,把这个非promise的东西,作为 await表达式的结果。
  如果它等到的是一个 promise 对象,await 也会暂停async后面的代码,先执行async外面的同步代码,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果。
  async await 与 promise 的优缺点
  优点: 它做到了真正的串行的同步写法,代码阅读相对容易 对于条件语句和其他流程语句比较友好,可以直接写到判断条件里面 处理复杂流程时,在代码清晰度方面有优势
  缺点: 用 await 可能会导致性能问题,因为 await 会阻塞代码,也许之后的异步代码并不依赖于前者,但仍然需要等待前者完成,导致代码失去了并发性。 ES9
  字符传扩展  放松对标签模板里字符串转义的限制 :遇到不合法的字符串转义返回 undefined   ,并且从raw   上可获取原字符串。 // 放松字符串的限制  const test = (value) => {      console.log(value)  }  test `domesy` // ["domesy", raw: ["domesy"]]
  Promise
  Promise.finally() 不管最后状态如何都会执行的回调函数  let func = time => {      return new Promise((res, rej) => {          setTimeout(() => {              if(time < 500){                  res(time)              }else{                  rej(time)              }          }, time)      })  }    func(300)  .then((val) => console.log("res", val))  .catch((erro) => console.log("rej", erro))  .finally(() => console.log("完成"))  // 执行结果: res 300  完成     func(700)  .then((val) => console.log("res", val))  .catch((erro) => console.log("rej", erro))  .finally(() => console.log("完成"))  // 执行结果: rej 700  完成
  for-await-of
  for-await-of: 异步迭代器,循环等待每个 Promise对象   变为resolved状态   才进入下一步 let getTime = (seconds) => {      return new Promise(res => {          setTimeout(() => {              res(seconds)          }, seconds)      })  }   async function test(){     let arr = [getTime(2000),getTime(500),getTime(1000)]     for await (let x of arr){         console.log(x);      } }  test() //以此执行 2000  500 1000 ES10
  字符传扩展  JSON.stringify() : 可返回不符合UTF-8标准的字符串(直接输入U+2028和U+2029可输入)  //JSON.stringify() 升级  console.log(JSON.stringify(" ")); //   console.log(JSON.stringify("u{D800}")); //
  数组扩展  flatMap() : 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。(注:它与 map 连着深度值为1的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。) flat : 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。默认为1.(应用: 数组扁平化 (当输入  Infinity    自动解到最底层)) let arr = [1, 2, 3, 4]    // flatMap()  console.log(arr.map((x) => [x * 2])); // [ [ 2 ], [ 4 ], [ 6 ], [ 8 ] ]  console.log(arr.flatMap((x) => [x * 2])); // [ 2, 4, 6, 8 ]  console.log(arr.flatMap((x) => [[x * 2]])); // [ [ 2 ], [ 4 ], [ 6 ], [ 8 ] ]    const arr1 = [0, 1, 2, [3, 4]];  const arr2 = [0, 1, 2, [[[3, 4]]]];   console.log(arr1.flat()); // [ 0, 1, 2, 3, 4 ]  console.log(arr2.flat(2)); // [ 0, 1, 2, [ 3, 4 ] ]  console.log(arr2.flat(Infinity)); // [ 0, 1, 2, 3, 4 ]
  对象扩展
  Object.fromEntries() 返回键和值组成的对象,相当于 Object.entries()   的逆操作可以做一些数据类型的转化
  Map 转化为 Object  let map = new Map([     ["a", 1],     ["b", 2],  ]);    let obj = Object.fromEntries(map);  console.log(obj); // {a: 1, b: 2}
  Array 转化为 Object // 注意数组的形式 let arr = [     ["a", 1],     ["b", 2],  ]  let obj = Object.fromEntries(arr);  console.log(obj); // {a: 1, b: 2}
  对象转换  let obj = {     a: 1,     b: 2,     c: 3  }    let res = Object.fromEntries(      Object.entries(obj).filter(([key, val]) => value !== 3)  )    console.log(res) //{a: 1, b: 2}
  数值扩展  toString()改造 :返回函数原始代码(与编码一致)  //toString()  function test () {      consople.log("domesy")  }  console.log(test.toString());  //  function test () {  //      consople.log("domesy")  //  }
  可选的Catch参数
  在 ES10 中,try catch 可忽略 catch的参数   let func = (name) => {       try {          return JSON.parse(name)       } catch {          return false       }   }      console.log(func(1)) // 1   console.log(func({a: "1"})) // false ES11
  BigInt(原始类型)  新的原始数据类型:BigInt,表示一个任意精度的整数,可以表示超长数据,可以超出2的53次方 js 中 Number类型只能安全的表示-(2^53-1)至 2^53-1 范的值
  特别注意: Number类型的数字有精度限制,数值的精度只能到 53 个二进制位(相当于 16 个十进制位, 正负9007199254740992),大于这个范围的整数,就无法精确表示了。 Bigint没有位数的限制,任何位数的整数都可以精确表示。但是其只能用于表示整数,且为了与Number进行区分,BigInt 类型的数据必须添加后缀n。 BigInt 可以使用负号, 但是不能使用正号 number类型的数字和Bigint类型的数字不能混合计算  // Number  console.log(2 ** 53) // 9007199254740992  console.log(Number.MAX_SAFE_INTEGER) // 9007199254740991    //BigInt  const bigInt = 9007199254740993n  console.log(bigInt) // 9007199254740993n  console.log(typeof bigInt) // bigint  console.log(1n == 1) // true  console.log(1n === 1) // false  const bigIntNum = BigInt(9007199254740993n)  console.log(bigIntNum) // 9007199254740993n
  基本数据类型
  在ES6中一共有7种,分别是: srting   、number   、boolean   、object   、null   、undefined   、symbol
  其中  object    包含: Array   、Function   、Date   、RegExp
  而在ES11后新增一中,为 8中 分别是: srting   、number   、boolean   、object   、null   、undefined   、symbol   、BigInt
  Promise
  Promise.allSettled(): 将多个实例包装成一个新实例,返回全部实例状态变更后的状态数组(齐变更再返回) 无论结果是 fulfilled 还是 rejected, 无需 catch 相当于增强了  Promise.all()    Promise.allSettled([     Promise.reject({       code: 500,       msg: "服务异常",     }),     Promise.resolve({       code: 200,       data: ["1", "2", "3"],     }),     Promise.resolve({       code: 200,       data: ["4", "5", "6"],     }),   ]).then((res) =>{       console.log(res) // [{ reason: {code: 500, msg: "服务异常"}, status: "rejected" },                       // { reason: {code: 200, data: ["1", "2", "3"]}, status: "rejected" },                       // { reason: {code: 200, data: ["4", "5", "6"]}, status: "rejected" }]       const data = res.filter((item) => item.status === "fulfilled");       console.log(data); // [{ reason: {code: 200, data: ["1", "2", "3"]}, status: "rejected" },                           // { reason: {code: 200, data: ["4", "5", "6"]}, status: "rejected" }]   })
  import(): 动态导入  按需获取的动态 import. 该类函数格式(并非继承 Function.prototype)返回 promise 函数 与 require   的区别是:require()   是同步加载,import()   是异步加载 // then()  let modulePage = "index.js";  import(modulePage).then((module) => {     module.init();  });    // 结合 async await  (async () => {   const modulePage = "index.js"   const module = await import(modulePage);   console.log(module)  })
  globalThis  全局this, 无论是什么环境(浏览器,node等),始终指向全局对象 // 浏览器环境 console.log(globalThis) //  window  // node console.log(globalThis) //  global
  可选链  符号 ?代表是否存在 TypeScript 在 3.7 版本已实现了此功能  const user = { name: "domesy" }  //ES11之前  let a = user && user.name    //现在  let b = user?.name
  空值合并运算符  处理默认值的便捷运算符 与 || 相比,空值合并运算符 ?? 只会在左边的值严格等于 null 或 undefined 时起作用。   "" || "default value"; // default value   "" ?? "default value"; // ""     const b = 0;  const a = b || 5;  console.log(a); // 5    const b = null // undefined  const a = b ?? 123;  console.log(a); // 123 ES12
  字符传扩展
  replaceAll() replace()  方法仅 替换一个 字符串中某模式(pattern)的首个实例 replaceAll()  会返回一个新字符串,该字符串中用一个替换项替换了原字符串中 所有匹配 了某模式的部分。 模式可以是一个字符串或一个正则表达式,而替换项可以是一个字符串或一个应用于每个匹配项的函数。 replaceAll()  相当于增强了 replace() 的特性,全量替换  let str = "Hi!,这是ES6~ES12的新特性,目前为ES12"    console.log(str.replace("ES", "SY")); // Hi!,这是SY6~ES12的新特性,目前为ES12  console.log(str.replace(/ES/g, "Sy")); // Hi!,这是Sy6~Sy12的新特性,目前为Sy12    console.log(str.replaceAll("ES", "Sy")); // Hi!,这是Sy6~Sy12的新特性,目前为Sy12  console.log(str.replaceAll(/ES/g, "Sy")); // Hi!,这是Sy6~Sy12的新特性,目前为Sy12
  Promise
  Promise.any() 其区别于 Promise.race(), 尽管某个 promise 的 reject 早于另一个 promise 的 resolve,Promise.any() 仍将 返回那个首先 resolve 的 promise。  Promise.any([     Promise.reject("Third"),     Promise.resolve("Second"),     Promise.resolve("First"),  ])  .then((res) => console.log(res)) // Second  .catch((err) => console.error(err));     Promise.any([     Promise.reject("Error 1"),     Promise.reject("Error 2"),     Promise.reject("Error 3"),  ])  .then((res) => console.log(res))  .catch((err) => console.error(err));  // AggregateError: All promises were rejected    Promise.any([     Promise.resolve("Third"),     Promise.resolve("Second"),     Promise.resolve("First"),  ])  .then((res) => console.log(res)) // Third  .catch((err) => console.error(err));
  WeakRefs  允许创建对象的弱引用。这样就能够在 跟踪现有对象时不会阻止对其进行垃圾回收。对于缓存和对象映射非常有用 必须用 new关键字创建新的 WeakRef deref() 读取引用的对象 正确使用 WeakRef 对象需要仔细的考虑,最好尽量避免使用。避免依赖于规范没有保证的任何特定行为也是十分重要的。何时、如何以及是否发生垃圾回收取决于任何给定 JavaScript 引擎的实现。  let weakref = new WeakRef({name: "domesy", year: 24})    weakref.deref() // {name: "domesy", year: 24}  weakref.deref().year // 24
  逻辑操作符和赋值表达
  &&= let num1 = 5; let num2 = 10; num1 &&= num2; console.log(num1); // 10  // 等价于 num1 && (num1 = num2); if (num1) {     num1 = num2;  }
  ||= let num1; let num2 = 10; num1 ||= num2; console.log(num1); // 10  // 等价于 num1 || (num1 = num2); if (!num1) {    num1 = num2; }
  ??= 空值合并运算符 ?? 只会在左边的值严格等于 null 或 undefined 时起作用 let num1; let num2 = 10; let num3 = null; // undefined  num1 ??= num2; console.log(num1); // 10  num1 = false; num1 ??= num2; console.log(num1); // false  num3 ??= 123; console.log(num3); // 123  // 等价于 // num1 ?? (num1 = num2);
  数值分隔符  let num1 = 100000; let num2 = 100_000;  console.log(num1); // 100000 console.log(num2); // 100000  const num3 = 10.12_34_56 console.log(num3); // 10.123456
  希  望这篇文章能够帮助你迅速了解,喜欢的点个赞

这届打工人真不易,曝知乎通过员工检测系统获知员工跳槽信息2月11日,今日爆料称知乎被曝裁员消息引发热议。有网友在社交媒体发文称,知乎通过行为感知系统,可提前获知员工跳槽信息。根据其提供的信息,该行为感知系统可对离职倾向工作效率日志网速泄七款骁龙8Gen1手机游戏性能排行,最早发布的MOTOX30表现出乎意料测试机型小米12小米12ProiQOO9iQOO9Pro一加10ProMOTOEdgeX30真我GT2Pro(详细测试视频见请不要叫我测评卷)测试环境变量控制1全程连接相同是WIF花1800买的iPad8,开机玩游戏到底如何?玩游戏真爽要不是朋友找我测评,可能对于iPad8真的没什么印象!今天花了一千八买了部平板ipad8,开机玩游戏到底如何?玩游戏真爽!外观首先看一下外观!ipad8这个四边的边边角角没有什么磕9个运维最常用的脚本整理(经典版本)Dos攻击防范(自动屏蔽攻击IP)!binbashDATE(datedbYHM)LOGFILEusrlocalnginxlogsdemo2。access。logABNORMALIP多多进宝你还没有了解哪些优势。淘宝验号黑科技尽在黑号库今天来分析一下多多进宝有什么优势,它是一种拼多多平台给商家提供的一种全新营销工具,可以通过自己的商品设定一定的佣金比例,然后吸引那些推手去把这个商品分享出去,做一定的产品做推广,就python使用正则爬取豆瓣电影数据(值得收藏)!usrbinenvpython3codingutf8任务使用正则提取豆瓣电影数据思路1获取html内容文本2准备正则表达式3使用finditet()方法,对html文本一次性提取2022年了,现在买苹果11promax合适吗?作为一名用了两年多的iPhone11ProMax的用户,我必须说明一个观点,这手机非常好用,要不然我也不会用到现在还没换(当然更多原因是没钱)。但老实说,在2022年我是不怎么推荐9点1氪丨知乎回应裁员传闻国家医保局回应种植牙纳入集采方案基本成熟乐视网被恢复执行12。9亿元亚洲渔港金禄电子科技北京汉仪创新科技创业板上市委公告,亚洲渔港股份有限公司金禄电子科技股份有限公司北京汉仪创新科技股份有限公司首发2月18日上会。(证券时报)知乎被曝大裁员知乎视频排名超微信登顶AppStore后陷隐私传闻,产品经理被气哭,官方回应最近爆火的啫喱App摊上事了。2月12日消息,一位自称啫喱App的产品经理的博主xbcyyyyy在社交媒体上发长文称,从2月11日下午15时开始陆续接到用户反馈用户隐私安全的消息,数字政通今年有信心在无人驾驶相关的产品和技术上获得一些重要突破数字政通表示,无人驾驶网格车是一个新产品,利用无人驾驶技术以网格化的方式在城市运行采集相关的数据。虽然是一个跨界的产物,但是公司做这项业务的出发点是因为公司本身有劳动力密集型的城市国潮涌动下新国货崛起的营销密码来源人民论坛网原标题国潮涌动下新国货崛起的营销密码人们通常把数字经济赋能中国制造的创新产品称为新国货。近年来,新国货品牌纷纷借助大数据洞察消费者新需求,不断提升产品与服务质量,并且
物联网前景广阔市场超万亿美元,海康威视去年大赚百亿文杨剑勇数字化在各行各业如火如荼进行中,推动全球物联网产业呈现蓬勃发展态势。权威调研机构IDC所发布的2021年V1全球物联网支出指南显示2020年全球物联网支出达到6904亿美元阿里云与鸿蒙,走向两个方向的国产手机系统2012年,阿里云os正式发布,这是国内第一个国产手机系统。2021年,华为正式发布HarmonyOS2。阿里云发布以后,阿里投资了一批二三线的手机厂商,用来搭载yunos,其中包2021私域流量认知图谱,7个方面搭建完整体系近年来,很多人都发现,客户的消费方式不知不觉发生改变,以前是在逛街时顺便种草,看到哪家店顺眼就走进去,而现在多半都是先上网搜索,看到满意的再前往线下门店。意识到这一点,很多的商家都骁龙888集体发烧?这个2021年,不如捡漏旧旗舰冷静一下今年的骁龙888基于5nm工艺制程,虽然性能相比骁龙865强很多,但功耗更高,发热也非常明显,有人说这是因为5nm工艺还不成熟,芯片制造商为了遵循摩尔定律,强上5nm工艺导致的,但中科院5nm激光光刻,是否意味可以取代荷兰的ASML光刻机?极客谈科技,全新视角全新思路,伴您遨游神奇的科技世界。一个好消息传来,中科院苏州纳米技术与纳米仿生研究所张子旸与国家纳米中心刘前共同在NanoLetters上发表了一篇研究论文,论中国移动咪咕视频2020欧洲杯直播将支持HDRVivid画面IT之家6月4日消息6月4日,中国移动咪咕5G视听体育论坛举办,同时举行了5G欧洲杯发布仪式,公布了5G欧洲杯的升级玩法。IT之家获悉,当地时间6月11日晚9时,因疫情推迟举办的2腾讯告赢国家知识产权局,网友不愧是南山必胜客去年,腾讯发生了一件让人津津乐道的事情,那就是腾讯状告老干妈拖欠广告款败诉一事。原来,腾讯竟然遭遇了诈骗,老干妈企业从来没有提出广告要求。腾讯此后也自嘲自己是憨憨,吃了假的老干妈。买比特币交易在哪儿?哪个是正规平台?买比特币交易在哪?以前比特币刚诞生那会儿,人们对于这种虚拟货币背后的意义并不了解,那时候随便找个电脑就可以挖到一大堆比特币。随着比特币价值被越来越多的人认识,其价格也是几何式上升。两家中企反诉成功后,白宫升级特朗普禁令,将制裁名单再一次扩大美国自从特朗普政府开始对我国高科技企业展开制裁后,脚步就一直没停止,到特朗普离任时,已经将制裁名单扩大到了44家中企,无一例外均是科技行业。不久前,小米和箩筐技术对美国制裁反诉成功为什么感觉现在买卖音响的极少了?我认为,这个问题应该切确说为什么现在买卖大功率音响少了,原因如下(1)音响技术发展,尤其是数码技术发展,手机和电脑AI调音技术发展,普通人欣赏已经不需要大量的硬件来保证音质以及来调高通已向华为出货,接着会不会是台积电?其实,这次美国禁售华为芯片的行为,看上去是一个绝杀的狠招,细想起来反到是中国向国产芯片进军的动员令中国本就想在高科技领城要努力掌握自已的核心技术,这下子美国帮助中国下了这个决心!在