ホームページ > 記事 > ウェブフロントエンド > JavaScript ECMAScript 6 のすべての新機能の概要
この記事では、javascript に関する関連知識を紹介します。主に JavaScript ECMAScript 6 (ES2015~ES2022) のすべての新機能の概要を紹介します。この記事では、次のテーマを中心に詳細な内容を紹介します。以下に参考値を見てみましょう。皆様の参考になれば幸いです。
[関連する推奨事項: JavaScript ビデオ チュートリアル 、Web フロントエンド ]
ECMAScript が正式にリリースされてからES6 がリリースされてから 8 年が経過し、2015 年からは毎年 6 月に今年をバージョン番号として新しいバージョンがリリースされます。
これらの多くのバージョンには多くの新機能が登場していますが、記憶を容易にするために、この記事ではすべての新機能を整理しました。
ps: ES2015 以降のすべてのバージョンを総称して ES6 と呼ぶという情報もありますし、ES6 は ES2015、ES7 は ES2016 などを意味するという情報もありますが、ここでは説明しません。
ES2015 は最も大きな変更が加えられたバージョンです。基本的に ES2015 より前のすべての内容が拡張されています。次の図に示すように:
ES6 より前には、変数を宣言する方法は 1 つだけでした。 ES2015 では、変数と定数を宣言するために let
キーワードと const
キーワードが追加されています。 #コードは次のとおりです。
// 声明变量 let v = 100 v = 200 // 声明常量 const V = 200 // 修改常量 // V = 300 // 报错let キーワードと
const キーワードの両方を使用して宣言された変数または定数は、ブロック レベルのスコープ
# # を持ちます。 #サンプル コードは次のとおりです。
{ var v = 100 } { let val = 200 } console.log(v) console.log(val) // 报错 val is not defined
let または
const キーワードを使用して宣言された変数には、変数プロモーション機能があり、一時的なデッドゾーンの特性を持っています。 関数の拡張
// es2015之前 function foo(v) { v = v ? v : 100 return v } // es2015 function bar(v = 100) { return v }
注目に値します。 thatIf there 複数のパラメータがある場合、デフォルトのパラメータは後ろから前まで である必要があります。
ES2015 では、新しいアロー関数が追加されました。これは関数 ,
の短縮形です。サンプル コードは次のとおりです。function foo(v) {
return v``
}
// 箭头函数写法
const foo = (v) => {
return v
}
// 简写形式 1
const foo = v => { // 只有一个参数可以省略括号
return v
}
// 简写形式 2
const foo = v => v // 语句中只有return时可以省略return和花括号
アロー関数の this は実行コンテキストに基づいて決定され、
は内部的にバインドされていないことに注意してください。 アロー関数を使用する場合、内部引数オブジェクトはありませんが、代わりに残りのパラメータが使用されます。
const foo = (...args) => { // console.log(arguments) // ReferenceError: arguments is not defined console.log(args) // args 是一个数组 } foo(1, 2, 3, 4) // [ 1, 2, 3, 4 ]
In ES2015 で関数に追加された name 属性は、関数の名前を指します。
サンプル コードは次のとおりです。function foo(v) { return v } const bar = v => v console.log(foo.name) // foo console.log(bar.name) // bar
Extension of the function value ES2015 での数値の拡張では、主に
Math という 2 つのオブジェクトにいくつかのメソッドが追加され、さらにバイナリおよび 8 進数の表現メソッドが追加されます。 ES2015 では、バイナリを表すには
0b
または
を使用し、8 進数を表すには 0o
または 0O
を使用します。 サンプル コードは次のとおりです。
console.log(0b111111111 === 511) // true console.log(0o777 === 511) // true
Number 用に拡張されたプロパティとメソッドは次のとおりです。
プロパティ/メソッド名
Number.EPSILON | |
---|---|
# Number.MIN_SAFE_INTEGER | 最小安全番号( |
Number.MAX_SAFE_INTEGER | 最大安全な数値(|
Number.parseInt() | パラメータを整数に解析して返します|
Number.parseFloat() | パラメータを浮動小数点数として解析して返します |
Number.isFinite() | 有限値かどうか判定 |
Number.isNaN() | NaN |
Number かどうか判定.isInteger() | NaN かどうかの判定整数の場合 |
Number.isSafeInteger() | 値が安全な範囲内かどうかを判定 |
Math 用に拡張されたメソッドは次のとおりです。 |
メソッド名
Math.trunc( ) | 数値の整数部分を返します | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Math.sign () | 数値型を返します ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<h3>字符串的扩展</h3>
<p>ES2015引入模板字符串,使用反引号(`)定义,模板字符串会保留格式,且可以使用变量,</p>
<p><strong>示例代码如下:</strong></p><pre class="brush:js;">// 使用 ` 定义模板字符串
let str = `一碗周`
// 模板字符串可以保留格式
let str2 = `一
碗
周`
// 模板字符串可以使用变量
const myName = &#39;一碗周&#39;
let str3 = `author: ${myName}` // 使用 ${} 进行包裹</pre><p><strong>ES2015还为String和String的实例扩展了一些方法,如下:</strong></p>
<table><tbody>
<tr class="firstRow">
<th>方法名</th>
<th>描述</th>
</tr>
<tr>
<td>String.fromCodePoint()</td>
<td>用于从 Unicode 码点返回对应字符</td>
</tr>
<tr>
<td>String.raw()</td>
<td>返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,往往用于模板字符串的处理方法。</td>
</tr>
<tr>
<td>String.prototype.codePointAt()</td>
<td>返回字符对应码点(String.fromCodePoint()的逆操作)</td>
</tr>
<tr>
<td>String.prototype.normalize()</td>
<td>把字符的不同表示方法统一为同样形式,返回新字符串(Unicode正规化)</td>
</tr>
<tr>
<td>String.prototype.repeat()</td>
<td>把字符串重复n次,返回处理后的字符串</td>
</tr>
<tr>
<td>String.prototype.includes()</td>
<td>判断是否存在指定字符串</td>
</tr>
<tr>
<td>String.prototype.startsWith()</td>
<td>判断字符串是否存在原始字符串的头部</td>
</tr>
<tr>
<td>String.prototype.endsWith()</td>
<td>判断字符串是否存在原始字符串的尾部</td>
</tr>
</tbody></table>
<h3>数组的扩展</h3>
<p>在ES2015中提供了展开运算符,即...,在数组中使用可以将数组展开,并以逗号分隔,</p>
<p><strong>示例代码如下:</strong></p><pre class="brush:js;">const arr = [1, 2, 3, 4, 5, 6]
const newArr = [...arr] // 复制数组
console.log(Math.max.call(null, ...arr)) // 将数组中的每一项作为参数使用</pre><p><strong>除此之外,还为Array以及数组提供了一系列方法,来逐个介绍:</strong></p>
<p><code>Array.from() :将类数组对象或者可迭代对象创建为一个新的数组,示例代码如下:function foo() { return Array.from(arguments) // 将 arguments 转换为数组 } console.log(foo(1, 2, 3, 4, 5, 6)) // [ 1, 2, 3, 4, 5, 6 ]
Array.of(1) // [1] Array.of(true, 1, '一碗周') // [true, 1, '一碗周'] Array.prototype.copyWithin(),浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。 示例代码如下: const arr = [1, 2, 3, 4] // 从索引 2 开始,到结束 将内容复制到索引 0 的位置 arr.copyWithin(0, 2) // [ 3, 4, 3, 4 ]
const arr = [1, 2, 3, 4] arr.find(item => item === 2) // 2(表示元素)、
const arr = [1, 2, 3, 4] arr.findIndex(item => item === 2) // 1 (表示索引)
const arr = [1, 2, 3, 4] // 将给定值填充索引1-3 arr.fill('一碗周', 1, 3) // [ 1, '一碗周', '一碗周', 4 ]
const arr = [1, true, '一碗周'] const keys = arr.keys() for (const i of keys) { console.log(i) // 遍历结果 0 1 2 }
示例代码如下: const arr = [1, true, '一碗周'] const values = arr.values() for (const i of values) { console.log(i) // 遍历结果 1 true 一碗周 }
示例代码如下: const arr = [1, true, '一碗周'] const iterator = arr.entries() console.log(Array.from(iterator)) // [ [ 0, 1 ], [ 1, true ], [ 2, '一碗周' ] ] 对象的扩展ES2015中允许对象的属性名和属性值一致时可以只写属性名, 示例代码如下: const myName = '一碗周' const age = 18 const person = { myName, age } console.log(person) // { myName: '一碗周', age: 18 } 还有就是在定义对象时,允许使用[]包裹表达式作为属性名,示例代码如下: const myName = '一碗周' const age = 18 const person = { myName, ['a' + 'g' + 'e']: age, } console.log(person) // { myName: '一碗周', age: 18 }
示例代码如下: console.log(NaN === NaN) // false console.log(+0 === -0) // true console.log(Object.is(NaN, NaN)) // true console.log(Object.is(+0, -0)) // false
示例代码如下: const person = Object.assign({}, { name: '一碗周' }, { age: 18 }) console.log(person) // { name: '一碗周', age: 18 }
类在ES2015中提出了类的概念,在语法的层面上有了类,示例代码如下: class Person { constructor(age) { // 属性 this.myName = '一碗周' this.age = age } // 静态方法 static print() { console.log() } // 访问器 get myName() { console.log('getter') return '一碗周' } set myName(v) { console.log('setter' + v) } setName(v) { this.myName = v } } const person = new Person(18) person.setName('ywanzhou') // 触发 setter 访问器 console.log(person.myName) // 触发 getter 访问器 模块化在ES2015中提出ESModel模块化规范,这是第一个官方层面的模块化规范,在这个规范中允许我们使用export导出模块,使用import引入模块, 示例代码如下: import a from 'm' // 导入模块 m 中的默认导出,将其命名为 a import a, { b } from 'm' // 导入模块 m 中的默认导出以及单独导入成员 b import * as A from 'm' // 导入模块中的所有成员 import 'm' // 执行 m 模块 export const b = 1 // 单独导出 export default b // 默认导出 export { b } // 按需导出 export { b as bb } // 改名导出 export { b } from 'm' // 导入模块 m 中的成员 b 并导出 解构赋值ES2015新增了解构赋值的语法,允许我们使用按照一定的模式,在数组或者对象中提取指定的值, 示例代码如下: // 数组的解构赋值 let [name, age, hobby = 'coding' /* 结构赋值的默认值 */] = ['一碗周', 18] // 交换两个变量的值 let a = 1 let b = 2 ;[a, b] = [b, a] console.log(a, b) // 2 1 // 对象的结构赋值 let { name: ObjName /* 解构赋值重命名 */, sex } = { name: '一碗周', sex: 1 } // 函数参数的解构赋值 function bar({ name, age }) { return name + age } bar({ name: '一碗周', age: 18 }) // 一碗周18 SymbolSymbol是ES2015中新增的一种数据类型,通过 通过Symbol()方法创建的symbol值都是唯一的,示例代码如下: /** * 语法 * Symbol([description]) * * description -> 是一个可选的描述信息 */ // 创建一个 Symbol 类型的值 const mySymbol = Symbol() console.log(mySymbol) // Symbol() const myName = Symbol('一碗周') console.log(typeof myName) // symbol Symbol还有一系列属性和方法这里就不作介绍了。 PromisePromise是ES2015中提供的一个异步解决方案,解决了回调地狱的问题。 通过
状态的切换只有两种,分别是:
一旦状态发生改变,就不会再次改变
如下图所示:
示例代码如下: new Promise((resolve, reject) => { console.log('我是第一个Promise中的log') resolve() }) .then(() => { console.log('我是第一个then中的log') }) .then(() => { console.log('我是第二个then中的log,但是我出现了异常') throw new Error('Error') }) .then(() => { console.log('我是第三个then中的第一个回调的log,但是我不会执行,因为我上面出现了异常') }, () => { console.log('我是第三个then中的第二个回调的log,我执行了') }) .then(() => { console.log('我是第四个then中的log,我可以正常执行') }) /* 执行结果如下 我是第一个Promise中的log 我是第一个then中的log 我是第二个then中的log,但是我出现了异常 我是第三个then中的第二个回调的log,我执行了 我是第四个then中的log,我可以正常执行 */ 有关Promise的一些方法如下:
IteratorIterator即迭代器,它是一种接口,为各种不同的数据结构提供了统一的访问机制,换句话说,只要有任何数据结构部署了迭代接口,就可以使用统一的方式的来遍历它。 实现可迭代接口的数据结构,一般都自身实现或继承了以 一个包含 如下所示:
JavaScript原生提供的迭代器接口如下图所示: 现在我们为obj来实现一个迭代器,代码如下: const obj = { [Symbol.iterator] () { return { next () { console.log('迭代器执行了'); return { value: '', done: true // 标志是否结束,true表示已经结束 } } } } } 我们在
GeneratorGenerator是ES2015中提供的一种异步编程解决方案,定义Generator函数在 示例代码如下: function* testGenerator() { // yield定义一个状态 yield '一碗周' yield 'es新特性' return 'generator' // 终结Generator,后面即使有yield关键字也无效 } const g = testGenerator() // 返回 Generator 对象,通过next()方法移动状态 g.next() /* { value: '一碗周', done: false } */ g.next() /* { value: 'es新特性', done: false } */ g.next() /* { value: 'generator', done: true } */ Proxy和ReffectProxy对象用于创建一个代理对象,从而实现基本操作的拦截和自定义,基本操作包含13种,如下表所示:
Vue3就是基于 <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.0.2/css/bootstrap.min.css" rel="external nofollow" rel="stylesheet" /> <title>通过set自动更新dom</title> </head> <body> <div style="width: 300px; margin: 100px auto"> <div> <h1 id="name"></h1> <button id="btn" class="btn btn-primary">修改</button> </div> </div> <script> // 获取DOM节点 const name = document.getElementById('name') const btn = document.getElementById('btn') // 定义一个修改值的函数 const updateDOM = (el, value) => { el.innerHTML = value } const person = new Proxy({ name: '一碗粥', }, { set(target, propKey, value) { // 如果里面的值改变就去调用我们的updateDOM updateDOM(name, value) target[propKey] = value return true }, }) name.innerHTML = person.name // 点击按钮触发修改操作 btn.addEventListener('click', () => { person.name === '一碗周' ? (person.name = '一碗粥') : (person.name = '一碗周') }) </script> </body> </html> 上面的代码就利用set方法进行数据绑定,如果对象发生改变,就自动更新我们的DOM。 Reflect是ECMAScript2015提供的一个对象,它提供了一些拦截JavaScript操作的静态方法,这些方法与Proxy中的 Reflect并不是一个构造函数,也就是说它不能够被实例化。
具体如下:
Set、Map、WeakSet、WeakMap
Set对象在实际开发中最常见的就是实现数据去重,示例代码如下: const arr = [1, 2, 2, 3, 4, 3, 5] const set = new Set(arr) // set对象可以使用 ... 展开 所有项 console.log([...set]) // [ 1, 2, 3, 4, 5 ]
ES2016(ES7)ES2016发布的新特性比较少,主要就两个新特性,如下图所示:
指数运算符ES2016中新增指数 示例代码如下: console.log(2 ** 10 === Math.pow(2, 10)) // true Array.prototype.includes()方法在ES2016中在数组原型上增加了 示例代码如下: const arr = [1, 2, 3, 4, 5, NaN] console.log(arr.indexOf(NaN)) // -1 console.log(arr.includes(NaN)) // true 值得注意的是使用 ES2017(ES8)async/await语法糖Promise的出现虽然解决了回调地狱的问题,但是如果链式调用特别多的话可读性还是会变差,在ES2017中新增了 async/await语法糖解决了这个问题。 Promise的写法如下: ;(function () { function promise(v) { return new Promise((resolve, reject) => { resolve(v) }) } const p = promise(1) p.then(res => { return promise(res) }).then(res => { console.log(res) }) })() 如果下一个Promise依赖于上一个,这种链式调用就会非常的长,现在我们用 async/await语法糖改写一下: ;(async function () { function promise(v) { return new Promise((resolve, reject) => { resolve(v) }) } const r1 = await promise(1) const r2 = await promise(r1) const res = await promise(r2) console.log(res) })() 可以看到,我们可以利用 async/await语法糖将Promise改写为平级的写法。 Atomics对象ES2017中新增了Atomics对象,该对象提供了一系列静态方法用于操作SharedArrayBuffer和ArrayBuffer对象,该对象并不能使用 对象扩展在ES2017中为Object扩展了三个静态方法,如下所示:
函数扩展在ES2017中允许我们在函数参数列表的最后面添加逗号,这个小特性非常的有用,因为为尾逗号的更新的时候仅仅需要改动一行代码,如果不适用尾逗号则是改动两行代码。 实例代码如下: function fun( aaaaa, bbbbb, ccccc, ) {} 如果存在尾逗号,只需要在最后面添加一行就好;如果不存在则需要在后面添加要给逗号,然后在添加一行。这在版本管理中就改动了两行,而不是一行。 字符串扩展在ES2017中为字符串新增了两个实例方法,分别是:
示例代码如下: const str = '一碗周' console.log(str.padStart(10)) /* 一碗周 */ console.log(str.padEnd(10)) /* 一碗周 */ ES2018(ES9)异步迭代在ES2018中新增了 示例代码如下: var asyncIterable = { [Symbol.asyncIterator]() { return { i: 0, next() { if (this.i < 3) { return Promise.resolve({ value: this.i++, done: false }) } return Promise.resolve({ done: true }) }, } }, } ;(async function () { for await (num of asyncIterable) { console.log(num) } })() // 0 // 1 // 2 正则的扩展在ES2018中,对正则表达式进行了如下扩展: 正则表达式分组命名: 在ES2018之前,我们无法对正则表达式中的分组命名,在ES2018中引入了该特性,该特性既方便了正则的阅读又方便了引用, 示例代码如下: const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/ const matchObj = RE_DATE.exec('2022-02-22') const year = matchObj.groups.year // 2022 const month = matchObj.groups.month // 02 const day = matchObj.groups.day // 22 s修饰符/dotALl模式:新增的s修饰符允许使用 反向断言:ES2018之前仅存在正向断言,而ES2018中新增了反向断言和反向否定断言。 对象展开运算符ES2015中新增数组的展开运算符,在ES2018中将这一特性加入到了对象中,示例代码如下: const n = { name: '一碗周' } const a = { age: 18 } const person = { ...n, ...a } // 合并对象 console.log(person) // { name: '一碗周', age: 18 } Promise.prototype.finally()
示例代码如下: fetch(url) .then(res => { console.log(res) }) .catch(error => { console.log(error) }) .finally(() => { console.log('结束') }) ES2019(ES10)优化在ES2019中优化了以下两个内容:
try { console.log('一碗周') } catch { console.error('一碗周') } trimStart()/trimLeft()和trimEnd()/trimRight()
数组的扩展在ES2019中扩展了两个数组方法,分别是:
const arr = [0, 1, 2, [3, 4]] console.log(arr.flat()) // [ 0, 1, 2, 3, 4 ]
Object.fromEntries()ES2019中新增的 示例代码如下: const person = { name: '一碗周', age: '18', } const e = Object.entries(person) const p = Object.fromEntries(e) console.log(p) // { name: '一碗周', age: '18' } Symbol.prototype.descrption
ES2020(ES11)模块化 在ES2020中加入了动态导入,也就是我们需要该模块的时候才会进行加载,这可以减少开销和页面加载时间,示例代码如下: import('/modules/my-module.js').then(module => { // Do something with the module. }) 动态导入使用 在ES2020中,还为 BigInt数据类型BigInt的出现时解决JavaScript中允许的最大数字是 const theBiggestInt = 9007199254740991n; const alsoHuge = BigInt(9007199254740991); // ↪ 9007199254740991n const hugeString = BigInt("9007199254740991"); // ↪ 9007199254740991n const hugeHex = BigInt("0x1fffffffffffff"); // ↪ 9007199254740991n const hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111"); // ↪ 9007199254740991n globalThis对象ES2020中引入 // 之前 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') { // no setTimeout in this environment! } // 之后 if (typeof globalThis.setTimeout !== 'function') { // no setTimeout in this environment! } 空值合并运算符空值合并运算符是由两个问号来表示,该运算符也是一个逻辑运算符,该运算符与逻辑或运算符类似。其计算规则为,只要左运算元为 示例代码如下: console.log(null ?? 10) // 10 console.log(undefined ?? 10) // 10 console.log(false ?? 10) // false 该运算符用于为没有值的变量赋值很有用,例如:如果这个数没有值,就为其赋值,否则不赋值, 示例代码如下: var value // 如果value的值不为 null 或者 undefined 为其赋值10 value = value ?? 10 console.log(value) // 10
可选链操作符可选链操作符用于读取某对象链下深处属性的值,使用这个操作符不必验证对象下的每个属性必须存在,例如我们想要访问 使用可选链操作符就不会出现这样的问题,当我们访问某个属性时,只要有一处不存在,就会返回 var A = {} // console.log(A.a.b) // 报错 console.log(A.a?.b) // undefined 可选链操作符也可用于对象下方法的调用,示例代码如下: var obj = {} // 如果存在 obj.fun() 这个方法,下面则会直接调用,如果不存在则会返回undefined obj.fun?.A() Promise.allSettled()
ES2021(ES12)String.prototype.replaceAll()
const str = '一碗粥' const newStr = str.replaceAll('粥', '周') console.log(newStr) // 一碗周 数值分隔符严格意义上讲数值分隔符( console.log(1_0000_0000) // 100000000 这个符号仅仅起到了便于阅读的目的,有与没有的结果并不影响,看下面的代码 1_1 === 11 // true WeakRefES2021中新增的 Promise.any()ES2021中新增的 逻辑赋值操作符ES2021中新增了一些赋值运算符,具体如下:
实际上它与普通的赋值运算符一致,示例代码如下: const [f1, f2, f3] = [true, false] f1 &&= '一碗周' // 等同于 str = str && '一碗周' f2 ||= '一碗周' // 等同于 str = str || '一碗周' f3 ??= '一碗周' // 等同于 str = str ?? '一碗周' ES2022class的扩展在ES2022中允许我们并不在 class C { myName = '一碗周' } /* 两者是一致的 */ class C { constructor() { myName = '一碗周' } }
在ES2022中允许我们使用 示例代码如下: class C { #myName = '一碗周' } const c = new C() console.log(#myName) // Private field '#myName' must be declared in an enclosing class await在顶层使用在ES2022中新增了允许在顶层使用 import { AsyncFun } from 'module' await AsyncFun() console.log(123) Object.hasOwn()
const person = { name: '一碗周', age: 18, } console.log(Object.hasOwn(person, 'name')) // true console.log(Object.hasOwn(person, 'sex')) // false Array.prototype.at()ES2022中新增的 const arr = [1, 2, 3, 4, 5, 6] console.log(arr.at(-1)) // 6 // 等同于 arr[arr.length - 1] d修饰符正则表达式增加了一个 示例代码如下: const str = 'JavaScript' const r = /a/d const m = r.exec(str) console.log(m.indices[0]) //[ 1, 2 ] 写在最后这篇文章到这就结束了,这篇文章中整理了ES2015到ES2022的新特性,有可能会有疏漏,望谅解。 脑图如下: 【相关推荐:javascript视频教程、web前端】 |
以上がJavaScript ECMAScript 6 のすべての新機能の概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。