ES7新增到最新(完结版)

158 阅读14分钟

Tips:项目中,ES6+以上版本的兼容性都是利用 babel 处理的,将 es6+的 js 编译成 es5,以便能够运行在当前和旧版本的浏览器或其他环境。

ES7(2016) 新增

1.幂操作

math.pow(3,2); // ES5求幂
let a = 3**2; // ES7求幂       

2.数组方法---includes('要检测的数据')

返回值为true/false,区分字母大小写

let _arr = ["today", "tomorrow", "yesterday"];
console.log(_arr.includes("tomorrow")); //输出 true
console.log(_arr.includes("Tomorrow")); //输出 false

ES8(2017) 新增

1.Object.values()

let object = { name: "why", age: 18 };
console.log(Object.keys(object)); //--- ES5 输出 [ 'name', 'age' ]
console.log(Object.values(object)); //--- ES8 输出 [ 'why', 18 ]

2.Object.entries()

入参:obj 对象类型 返回值:

let object1 = { name: "Vivain", age: 18 };
console.log(Object.entries(object1)); // 输出 [ [ 'name', 'Vivain' ], [ 'age', 18 ] ]
for (let [key, value] of Object.entries(object1)) {
  console.log(`key: ${key} value:${value}`);
}
// 输出
// key: name value:Vivain
// key: age value:18

3.async/await 用法

为了优雅地解决Promise回调地狱问题。

async表示函数内部有异步操作,await 表示紧跟在后面的表达式需要等待结果。

eg:

async function getDevice() {
  const data = await sendServiceRequest(); // await 异步任务
  // do something else
}

4. String padding

设置字符串的前后距离 just like padding

console.log("hahaha".padEnd(10)); // 输出 'hahaha    '
console.log("hahaha".padStart(10)); //输出 '    hahaha'

5.函数参数列表结尾允许逗号

6.Object.getOwnPropertyDescriptors(obj)

作用:用来获取一个对象的所有自身属性的描述符--->还能用来克隆对象

let _obj = {
  a: { b: 1 },
  c: 3,
  set foot(value) {
    console.log(value);
  },
};
let _obj1 = Object.assign({}, _obj); //对于数据类型为引用类型的,Object.assign()为浅拷贝;无法正确拷贝set属性和get属性的对象
let _obj2 = {};
Object.assign(_obj2, Object.getOwnPropertyDescriptors(_obj)); // 可以结合getOwnPropertyDescriptors实现set/get方法的拷贝
_obj.a.b = 2;
_obj.c = 4;
console.log("_obj>>>", _obj, "_obj1>>>", _obj1, "_obj2>>>", _obj2);
//输出 _obj>>> { a: { b: 2 }, c: 4 } _obj1>>> { a: { b: 2 }, c: 3 }
/* _obj2>>> {
  a: {
    value: { b: 2 },
    writable: true,
    enumerable: true,
    configurable: true
  },
  c: { value: 3, writable: true, enumerable: true, configurable: true },
  foot: {
    get: undefined,
    set: [Function: set foot],
    enumerable: true,
    configurable: true
  }
}
*/

Object.getOwnPropertyDescriptors(obj)返回了一个对象的所有自身属性的描述符。而这描述符又分了两种类型;In fact,在ECMAScript 中这两种属性:数据属性访问器属性。接下来就让我们细究一下~

(一)数据属性

数据属性有四个,它们分别是 configurable、enumerable、writable、value

configurable: 表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。默认为true。  
enumerable:表示能否通过 for-in 循环返回属性。默认为true。  
writable: 表示能否修改属性的值。默认为true。  
value:属性的数据值。默认为undefined

对于怎么修改这些属性的值,以下这个网址是我看到比较详细的,俺就不一一赘述了。 外部链接

(二)访问器属性

访问器属性也有四个,它们分别是 configurable、enumerable、get、set

configurable: 表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。默认为true。  
enumerable:表示能否通过 for-in 循环返回属性。默认为true。
get:在读取属性时调用的函数。默认值为 undefined。  
set:在写入属性时调用的函数。默认值为 undefined

修改的方式同上 😀,who 愿意 say 废话捏~

7. SharedArrayBuffer

用途:用来表示一个通用的、固定长度的原始二进制数据缓冲区,类似于 ArrayBuffer对象,它们都可以用来在共享内存(shared memory)上创建视图。与 ArrayBuffer 不同的是,SharedArrayBuffer 不能被转移。

8. Atomics

用法:Atomics 对象提供了一组静态方法对 SharedArrayBuffer 和 ArrayBuffer 对象进行原子操作。

具体有哪些方法可看下 🤪 MDN

ES9(2018) 新增

1.Async iterators 异步迭代器

Async iterators对象的 next() 方法返回一个 Promise,这个 Promise 的返回值可以被解析成 {value, done} 的格式

const asyncIterator = () => {
    const array = [1, 2];
    return {
      next: function() {
        if(array.length) {
          return Promise.resolve({
            value: array.shift(),
            done: false
          });
        }
        return Promise.resolve({
          done: true
        });
      }
    }
  }
  let iterator = asyncIterator();
  let test = async() => {
    await iterator.next().then(console.log);  // {value: 1, done: false}
    await iterator.next().then(console.log);  // {value: 2, done: false}
    await iterator.next().then(console.log);  // {done: true}
  }
  test();
//可以使用 for-await-of 在循环中异步调用函数-
  const promises = [
    new Promise((resolve) => resolve(1)),
    new Promise((resolve) => resolve(2)),
    new Promise((resolve) => resolve(3)),
  ];
  
  const test = async() => {
    for await (const p of promises) {
      console.log('p', p);
    }
  };
  
  test();
  // p 1
  // p 2
  // p 3

2.rest 剩余属性的使用

  • null不能使用扩展运算符
//例如: 
let { a, b, ...rest } = null; //❌
let test = { a: 1, b: 2, c: 3, d: 4 };
let { a, b,...rest } = test;
console.log(a); // 1
console.log(b); // 2
console.log(rest); // {c: 3, d: 4}

3. ... 扩展属性

let test = { a: 1,b: 2}
let result = {c: 3, ...test};
console.log(result);             // {c: 3, a: 1, b: 2}

4.Promise.prototype.finally

  • 在Promise结束的时候,不管是结果是resolved还是rejected,都会调用finally中的方法
  • finally中的回调函数不接受任何参数
const promise = new Promise((resolve, reject) => {
    resolve(1);
    reject(2);
  });
  const test = () => {
    console.log(3);
    promise.then((res) => {
      console.log(4, res);
    }).catch(err => {
      console.log(5, err);
    }).finally(() => {
      console.log(6);
    });
  };
  
  test();  // 3 4 1 6

ES10 新增

1.数组方法flat()以及flatMap()

  • flat()方法会按照一个可指定的深度遍历递归数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
  • flatMap()方法首先使用映射函数映射数组(深度值为1)的每个元素,然后将结果压缩成一个新数组。
//1.flat()
const arr = [1, 2, [[[[3, 4]]]]];
arr.flat();          // [1, 2, [[[3, 4]]]]
arr.flat(3);         // [1, 2, [3, 4]]
arr.flat(-1);        // [1, 2, [[[[3, 4]]]]]
arr.flat(Infinity);  // [1, 2, 3, 4]

//注意:flat()会移除数组中的空项
let arr = [1, 2, , , 3];
arr.flat();           // [1, 2, 3]

//2.flatMap()
let arr = ['My name', 'is', '', 'Lisa'];
let newArr1 = arr.flatMap(cur => {cur.split(' ');});
let newArr2 = arr.map(cur => {cur.split(' ');});
console.log(newArr1); // ["My", "name", "is", "", "Lisa"]
console.log(newArr2); // [["My", "name"], ["is"], [""], ["Lisa"]]

2.Object.fromEntries() —— 把键值对列表转换成一个对象

let map = new Map([
  ["a", 1],
  ["b", 2],
]);
let mapToObj = Object.fromEntries(map);
console.log(mapToObj); // {a: 1, b: 2}

let arr = [
  ["a", 1],
  ["b", 2],
];
let arrToObj = Object.fromEntries(arr);
console.log(arrToObj); // {a: 1, b: 2}

let obj = { a: 1, b: 2 };
let newObj = Object.fromEntries(
  Object.entries(obj).map(([key, val]) => [key, val * 2])
);
console.log(newObj); // {a: 2, b: 4}

3.String.prototype.{trimStart, trimEnd}

  • trimStart() 方法用来删除字符串的开头的空白字符。trimLeft() 是它的别名。
  • trimEnd() 方法用来删除字符串末尾的空白字符。 trimRight() 是它的别名。
let str = '    a b cd  ';
str.trimStart();   // 'a b cd  '
str.trimLeft();    // 'a b cd  '

str.trimEnd();   // '    a b cd'
str.trimRight(); // '    a b cd'

4.Symbol.prototype.description —— 返回Symbol对象的可选描述的字符串

Symbol('foo').description;      // 'foo'
Symbol().description;           // undefined
Symbol.for('foo').description;  // 'foo'

5.Optional catch binding

//以前的用法:
try {

} catch(err) {
  console.log('err', err);
}
//ES10 的用法:
try {

} catch {

}

6.JSON.stringify() 的增强力

  • 在 ES10 修复了对于一些超出范围的 Unicode 展示错误的问题,所以遇到 0xD800-0xDFF 之内的字符会因为无法编码成 UTF-8 进而导致显示错误。在 ES10 它会用转义字符的方式来处理这部分字符而非编码的方式,这样就会正常显示了。
JSON.stringify('😊'); // '"😊"'

7.修订 Function.prototype.toString()

  • 以前的 toString 方法来自 Object.prototype.toString(),现在 的 Function.prototype.toString() 方法返回一个表示当前函数源代码的字符串。以前只会返回这个函数,不会包含空格、注释等。
function foo() {
    // es10新特性
    console.log('imooc')
}
console.log(foo.toString());

ES11

1.空值合并运算符 —— ??

空值合并操作符(??)是一个逻辑操作符,当左边的操作数为 null 或 undefined 的时候,返回其右侧操作符,否则返回左侧操作符。

undefined ?? 'foo'  // 'foo'
null ?? 'foo'  // 'foo'
'foo' ?? 'bar' // 'foo'
NaN ?? 1  // NaN
false ?? 'bar'  // false

注意:不可以将 ?? 与 AND(&&)OR(||)一起使用,会报错。

2.可选链

可选链操作符(?.)允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用都是否有效。?. 操作符的功能类似于.链式操作符,不同之处在于,在引用为 null 或 undefined 时不会报错,该链路表达式返回值为 undefined。

// #以前的写法:
const street = user && user.address && user.address.street;
const num = user && user.address && user.address.getNum && user.address.getNum();
console.log(street, num);
// #ES11 的写法:
const street2 = user?.address?.street;
const num2 = user?.address?.getNum?.();
console.log(street2, num2);

注意:可选链不能用于赋值

let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment

3.globalThis全局this属性

  • 全局属性 globalThis 包含全局的this 值,类似于全局对象(global object)。
  • 在以前,从不同的 JavaScript 环境中获取全局对象需要不同的语句。在 Web 中,可以通过 window、self或者 frames 取到全局对象,但是在 Web Workers中,只有self可以。在 Node.js 中,它们都无法获取,必须使用 global。
  • 在松散模式下,可以在函数中返回 this 来获取全局对象,但是在严格模式和模块环境下,this 会返回 undefined。
  • globalThis 提供了一个标准的方式来获取不同环境下的全局 this 对象(也就是全局对象自身)。不像 window 或者 self这些属性,它确保可以在有无窗口的各种环境下正常工作。所以,你可以安心的使用 globalThis,不必担心它的运行环境。为便于记忆,你只需要记住,全局作用域中的 this 就是 globalThis。

以前的写法:

var getGlobal = function () {
  if (typeof self !== 'undefined') { return self; }
  if (typeof window !== 'undefined') { return window; }
  if (typeof global !== 'undefined') { return global; }
  throw new Error('unable to locate global object');
};

var globals = getGlobal();

if (typeof globals.setTimeout !== 'function') {
  // 此环境中没有 setTimeout 方法!
}

现在的写法:

if (typeof globalThis.setTimeout !== 'function') {
  //  此环境中没有 setTimeout 方法!
}

4.BigInt

  • BigInt 是一种内置对象,用来创建比 2^53 - 1(Number 可创建的最大数字) 更大的整数。可以用来表示任意大的整数。

如何定义一个 BigInt 在一个整数字面量后面加 n,例如 10n 调用函数 BigInt() 并传递一个整数值或字符串值,例如 BigInt(10) BigInt 的特点

  • BigInt 不能用于 Math 对象中的方法;
  • BigInt 不能与任何 Number 实例混合运算,两者必须转换成同一种类型。但是需要注意,BigInt 在转换成 Number 时可能会丢失精度。
  • 当使用 BigInt 时,带小数的运算会被向下取整
  • BigInt 和 Number 不是严格相等,但是宽松相等
0n === 0 // false
0n == 0  // true
  • BigInt 和 Number 可以比较
2n > 2   // false
2n > 1   // true
  • BigInt 和 Number 可以混在一个数组中排序
const mixed = [4n, 6, -12n, 10, 4, 0, 0n];
mixed.sort();  // [-12n, 0, 0n, 10, 4n, 4, 6]
  • 被 Object 包装的 BigInt 使用 object 的比较规则进行比较,只用同一个对象比较时才相等
0n === Object(0n); // false
Object(0n) === Object(0n); // false
const o = Object(0n);
o === o // true

BigInt 的方法

  • 1 BigInt.asIntN() 将 BigInt 值转换为一个 -2^(width-1) 与 2^(width-1) - 1 之间的有符号整数。
  • 2 BigInt.asUintN() 将一个 BigInt 值转换为 0 与 2^(width) - 1 之间的无符号整数。
  • 3 BigInt.prototype.toLocaleString() 返回此数字的 language-sensitive 形式的字符串。覆盖 Object.prototype.toLocaleString() 方法。
  • 4 BigInt.prototype.toString() 返回以指定基数 (base) 表示指定数字的字符串。覆盖 Object.prototype.toString() 方法。
  • 5 BigInt.prototype.valueOf() 返回指定对象的基元值。覆盖 Object.prototype.valueOf() 方法。

5.String.prototype.matchAll() —— 返回一个包含所有匹配正则表达式的结果及分组捕获组的迭代器

const regexp = /t(e)(st(d?))/g;
const str = 'test1test2';

const array = [...str.matchAll(regexp)];
console.log(array[0]);  // ["test1", "e", "st1", "1"]
console.log(array[1]); // ["test2", "e", "st2", "2"]

6.Promise.allSettled()

  • 类方法,返回一个在所有给定的 promise 都已经 fulfilled 或 rejected 后的 promise,并带有一个对象数组,每个对象表示对应的 promise 结果。
Promise.allSettled([
  Promise.resolve(33),
  new Promise((resolve) => setTimeout(() => resolve(66), 0)),
  99,
  Promise.reject(new Error("an error")),
]).then((values) => console.log(values)); 
// [
//   { status: 'fulfilled', value: 33 },
//   { status: 'fulfilled', value: 66 },
//   { status: 'fulfilled', value: 99 },
//   { status: 'rejected', reason: Error: an error }
// ]

7.Dynamic import(按需引入)

  • import 可以在需要的时候,再加载某个模块。
button.addEventListener('click', event => {
  import('./dialogBox.js')
  .then(dialogBox => {
    dialogBox.open();
  })
  .catch(error => {
    /* Error handling */
  })
});

ES12

1.逻辑运算符和赋值表达式(&&=,||=,??=)

//#1.1 &&= :逻辑与赋值运算符 x &&= y 等价于 x && (x=y):意思是当 x 为真时,x = y。
let a = 1;
let b = 0;
a &&= 2;
console.log(a); // 2
b &&= 2;
console.log(b);  // 0

//#1.2 ||= :逻辑或赋值运算符 x ||= y 等价于 x || (x = y):意思是仅在 x 为 false 的时候,x = y。
const a = { duration: 50, title: '' };
a.duration ||= 10;
console.log(a.duration);  // 50
a.title ||= 'title is empty.';
console.log(a.title);  // "title is empty"

//#1.3 ??= :逻辑空赋值运算符 x ??= y 等价于 x ?? (x = y):意思是仅在 x 为 null 或 undefined 的时候,x = y。
const a = { duration: 50 };
a.duration ??= 10;
console.log(a.duration);  // 50
a.speed ??= 25;
console.log(a.speed);  // 25

2、String.prototype.replaceAll(pattern,replacement)

  • 返回一个新字符串,字符串中所有满足 pattern 的部分都会被 replacement 替换掉。原字符串保持不变。
  • pattern 可以是一个字符串或 RegExp;
  • replacement 可以是一个字符串或一个在每次被匹配被调用的函数。
'aabbcc'.replaceAll('b', '.');  // 'aa..cc'

//使用正则表达式搜索值时,必须是全局的:
'aabbcc'.replaceAll(/b/, '.');  // TypeError: replaceAll must be called with a global RegExp
'aabbcc'.replaceAll(/b/g, '.');  // "aa..cc"

3.数字分隔符

#ES12 允许 JavaScript 的数值使用下划线(_)作为分隔符,但是没有规定间隔的位数:
123_00  //输出12300

#小数和科学记数法也可以使用分隔符:
0.1_23
1e10_00

注:

  1. 不能放在数值的最前面和最后面;
  2. 不能将两个及两个以上的分隔符连在一起;
  3. 小数点的前后不能有分隔符;
  4. 科学记数法里,e 或 E 前后不能有分隔符。

4.Promise.any

Promise.any([promise1(), promise2(), promise3()])
  .then((first) => {
    // 只要有一个请求成功 就会返回第一个请求成功的
    console.log(first); // 会返回promise2
  })
  .catch((error) => {
    // 所有三个全部请求失败 才会来到这里
    console.log("error", error);
  });

ES13(2022)新增

1.引入了顶层 await,允许关键词 在模块的顶层使用

如果用script引入的话 要加个type=module

// 之前使用
const request = async () => {
  await axios.get('');
};

// 现在使用,可以直接在顶层使用
const fun = (timeout) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, timeout);
  });
};

await fun(3000);

2.类 Class

2.1 类的私有字段

通过 # 关键字,可以创建私有字段或者方法,不可以在外部被访问到,内部可以访问。

class Breeze {
  constructor() {
    this.age = 18;
  }
  name = "zhang";
  #girl = "bao";
  #eat() {
    console.log("eating");
  }
  miss() {
    console.log(this.#girl);
  }
  meet() {
    this.#eat();
  }
  testEat() {
    return #eat in this; //使用 in 判断是否是对象的私有属性
  }
  static {//静态块
    console.log(1);
  }
  static {
    console.log(2);
    getPrivateField = (el) => el.#girl; // 内部可以访问到私有属性
  }
}

const boy = new Breeze();
console.log(boy.#girl); // Uncaught SyntaxError: Private field '#girl' must be declared in an enclosing class
console.log(boy.miss()); // bao
console.log(boy.meet()); // eating

console.log(boy.testEat()) // true
console.log('name' in boy) // true

3./d 正则

正则表达式通过/d 标志匹配索引,该标志为匹配的子字符串提供开始和结束索引; 提供了一个字段 indices,值为数组,分别标志了匹配到的字符串的开始和结束位置

const str = 'Hello world!';
//查找"Hello"
const patt = /Hello/;
const res = patt.exec(str);
console.log(res); // ['Hello', index: 0, input: 'Hello world!', groups: undefined]

// 加上 d
const patt = /Hello/d;
const res = patt.exec(str);
console.log(res); // ['Hello', index: 0, input: 'Hello world!', groups: undefined, indices: [[0, 5], groups: undefined]]
console.log(res.indices); // [[0, 5], groups: undefined]

4.Error 对象的 cause 属性

function capture() {
  try {
    fun();
  } catch (err) {
    throw new Error('error message', { cause: err });
  }
}

// 调用
try {
  capture();
} catch (err) {
  console.log(err);
  console.log(`Cause by: ${err.cause}`);
}

5. at支持相对索引

一直以来 js 的数组只支持正序索引,要是想拿到 arr 数组最后一个元素只能 arr[arr.length - 1],不方便

const arr = [1, 2, 3, 4, 5];
arr[0]; // 1
arr.at(0); // 1
arr.at(-1); // 5

at 方法不仅支持数组,同样可以在字符串中使用

const str = 'hello';
str.at(0); // h
str.at(-1); // o

6. Object.hasOwn(obj,Property)

一个替代 Object.prototype.hasOwnProperty 的方案

const obj = { name: 'breeze' };
// 原先用法
console.log(Object.prototype.hasOwnProperty.call(obj, 'name')); // true
// 现在
console.log(Object.hasOwn(obj, 'name'));// true

ES14(2023)新增

1.四种新的数组方法

1.1 toReversed()

与之前Reverse的区别在于 Reverse会改变原数组

const array = [1, 2, 3];

// Using the `toReversed` method
const array2 = array.toReversed();
console.log(array2);
console.log(array); // (original array remains unchanged)
1.2 toSorted()

与之前sort的区别在于 sort会改变原数组

const array = [1, 2, 3];

// Using the `toSorted` method
const sortedArray = array.toSorted((a, b) => a - b);
console.log(sortedArray); // 
console.log(array); // (original array remains unchanged)
1.3 toSpliced(start, deleteCount?, item1?, item2?, itemN?)

返回一个新数组,而不是修改原始数组。 因此,此方法不会返回已删除的元素。

const array = [1, 2, 3];

// Using the `toSpliced` method
const splicedArray = array.toSpliced(1, 2);
console.log(splicedArray); // 
console.log(array); // (original array remains unchanged)
1.4 array.with(index, value)

返回一个新数组,而不是修改原始数组。 用value替换index位置的值。

const arr = [1, 2, 3, 4, 5];
console.log(arr.with(2, 6)); // [1, 2, 6, 4, 5]
console.log(arr); // [1, 2, 3, 4, 5]

2.两个新方法 findLast 和 findLastIndex ,它们允许从数组的最后一个位置查找元素

2.1 findLast 查找最后一个
const array = [1, 2, 3, 2, 1];

const lastElement = array.findLast((num) => num > 1);
console.log(lastElement); //2
2.2 findLastIndex 查找最后一个索引
const array = [1, 2, 3, 2, 1];

const lastIndex = array.findLastIndex((num) => num > 1);
console.log(lastIndex);//3

3.Symbols 作为 WeakMap 键

const keyA = Symbol("version");
const keyB = Symbol("version");

const map = new WeakMap();
map.set(keyA, "ES2023");

console.log(map.get(keyA)); // "ES2023"
console.log(map.get(keyB)); // undefined

4.Hashbang语法

Hashbang 也叫 Shebang,是一个由井号和叹号构成的字符序列 #!,用来指定使用哪种解释器执行此文件:

// hashbang.js
#!/usr/bin/env node
console.log('hashbang');

// nohashbang.js
console.log('no hashbang')

在执行hashbang.js文件时,可以不用node+文件名 可以直接文件名执行

参考文章: 【ES11(2020)】全局属性 globalThis 【JavaScript】ES7、ES8、ES9、ES10、ES11、ES12都增加了哪些新特性? ECMAScript 2023 (ES14) 的新特性你都了解了吗?