跳到主要内容 JavaScript 高级进阶 ES6 至 ES13 详解 | 极客日志
JavaScript Node.js 大前端
JavaScript 高级进阶 ES6 至 ES13 详解 JavaScript 从 ES6 到 ES13 经历了显著的语言特性演进。本文详细解析了各版本核心更新,包括 ES6 的 let/const、箭头函数、模板字符串及数据结构(Set/Map);ES7 的指数运算符与 includes;ES8 的对象方法与字符串填充;ES10 的数组扁平化与参数处理;ES11 的空值合并、可选链及 globalThis;以及 ES12 和 ES13 引入的弱引用、逻辑赋值、负索引访问和类私有成员等。内容涵盖语法变化、作用域机制、内存管理及新 API 应用,旨在帮助开发者掌握现代 JavaScript 标准规范。
1. ES6 - 对象字面量增强
对象字面量的增强写法主要体现在以下几个方面,以提高代码的可读性、可维护性和功能性:
属性简写:当属性名和变量名相同时,可以省略属性名,直接写变量名
方法简写:可以省略 function 关键字,直接写方法名
计算属性名:使用表达式的结果作为对象属性的键名
当前有多个变量,想要把它们放入到对象中,并且在对象中定义一个方法,在 ES6 之前是这样写的:
const name =
age =
object = {
: name,
: age,
: ( ) {}
}
'liang'
const
20
const
name
age
foo
function
const name = 'liang'
const age = 20
const object = {
name, age,
foo ( ) {}
}
可以使用箭头函数作为方法,这样可以更简洁地定义函数,但是要注意箭头函数中的 this 指向。
const object = {
foo ( ) { console .log (this ) },
bar : () => { console .log (this ) }
}
计算属性名:[] 是计算属性名的语法,使用表达式的结果作为对象属性的键名。
const name = 'liang'
const object = {
[name + 456 ]() { console .log ('ES6 的计算属性写法' ); }
}
object[name + '123' ] = function ( ) { console .log ('ES6 之前的计算属性写法' ); }
object.liang123 ()
object.liang456 ()
2. ES6 - 对象和数组的解构 ES6 解构赋值是一种强大的语法特性,它允许你从数组或对象中提取数据,并将其赋值给变量。这种语法使得从复杂的数据结构中提取数据变得更加简洁和直观。
const arr = ['html' , 'css' , 'js' ]
const item1 = arr[0 ]
const item2 = arr[1 ]
const item3 = arr[2 ]
const [value1, value2, value3] = arr
const { name, age } = { name : 'liang' , age : 20 }
3. ES6 - let / const 的基本使用 在 ES5 中声明变量都是使用的 var 关键字,从 ES6 开始新增了两个关键字可以声明变量:let、const。
var a = 1
let b = 2
const c = 3
通过 let、const 声明的变量不可以重复定义。
var a = 1
var a = 1
let b = 2
const c = 3
const 本质上是传递的值不可以修改,如果传递的是引用类型,可以通过引用找到对象,去修改对象内部的属性。
const obj = { name : 'liang' }
obj.name = 'hello'
4. ES6 - let / const 的作用域提升 let、const 和 var 的另一个重要区别是作用域提升:
var 声明的变量是会进行作用域提升的,在声明之前使用该变量不会报错,只是没有值
使用 let、const 声明的变量,在声明之前使用该变量会报错
console .log (a)
var a = 1
console .log (b)
let b = 1
它表达的意思是在一个代码中,使用 let/const 声明的变量,在声明之前变量都是不可访问的
我们将这种现象称之为暂时性死区
5. ES6 - let / const 和 window 的关系
全局通过 var 声明的变量,会被添加到 window 对象上,作为 window 对象的属性
let、const 是不会给 window 上添加任何属性的
var name = 'liang'
console .log (window .name )
let title = 'vue'
console .log (window .title )
6. ES6 - 新增的块级作用域 在 ES5 中只有两个东西会形成作用域:全局作用域、函数作用域。
在 ES6 中新增了块级作用域,并且通过 let、const、function、class 声明的标识符是具备块级作用域限制的。
if (true ) {
let foo = 'foo'
}
console .log (foo)
let color = 'red'
switch (color) {
case 'red' :
var bar = 'bar'
let bgColor = '#000'
}
console .log (bar)
console .log (bgColor)
for (var i = 0 ; i < 5 ; i++) {}
console .log (i)
for (let j = 0 ; j < 5 ; j++) {}
console .log (j)
我们来看一下 for 循环语句中,起始变量使用 var 声明的导致的问题:无论点击哪个按钮输出结果都是一样的。
const btns = document .getElementsByTagName ('button' )
for (var i = 0 ; i < btns.length ; i++) {
btns[i].onclick = function ( ) {
console .log ('第' + i + '个按钮被点击' )
}
}
这是因为 var 声明的变量 i 是全局作用域,函数中没有变量 i 就会往上级作用域找,循环结束后 i 就已经变为 3。
学习过块级作用域后,只需要将 i 的声明从 var 改为 let 即可,这就是块级作用域给我们带来的好处。
for (let i = 0 ; i < btns.length ; i++) {
btns[i].onclick = function ( ) {
console .log ('第' + i + '个按钮被点击' )
}
}
7. ES6 - 模板字符串的使用 ES6 模板字符串是一种增强型的字符串表示方式,使用反引号包裹内容,支持在字符串中嵌入变量、表达式以及多行文本,极大的简化了字符串拼接和格式化操作。
基本语法:模板字符串通过反引号定义,可以包含变量和表达式,使用 ${} 语法进行插入。
const string = `my name is ${name} , age is ${age + 5 } , height is ${height} `
多行文本:模板字符串天然支持多行文本,无需使用 和字符串拼接,可以直接换行书写。
const html = `<div>
<button>按钮</button>
<button>按钮</button>
<button>按钮</button>
</div>`
8. ES6 - 标签模板字符串 标签模板字符串是 ES6 中的一个高级特性,它允许你通过一个函数来处理模板字符串。
function foo (m, n, x ) {
console .log ({ m, n, x })
}
const name = 'liang'
const age = 18
foo`hello${name} world${age} !`
9. ES6 - 函数参数的默认值 在 ES6 中,函数参数的默认值功能极大的简化了函数定义和调用过程。
function foo (m = '默认值' ) {
}
function foo ({ name, age, gender = '男' } = { name: 'liang' , age: 20 } ) {
}
函数的 length 属性值为其参数数量,对于有参数默认值的函数,从有默认值的参数开始,后续参数不做数量统计。
function bar (a, b, c = 3 ) {}
console .log (bar.length )
10. ES6 - 函数的剩余参数 ES6 中的剩余参数(Rest Parameter)是一种强大特性,可以将不定数量的参数放入到一个数组。
function foo (a, b, ...args ) {
console .log (a)
console .log (b)
console .log (args)
}
foo (1 , 2 , 3 , 4 , 5 )
11. ES6 - 箭头函数的补充 箭头函数是没有显式原型的,所以不能作为构造函数,无法通过 new 来创建对象。
const foo = ( ) => {}
console .log (foo.__proto__ )
new foo ()
12. ES6 - 展开语法的使用 展开语法(Spread Syntax)最初在 ES6 中引入,主要用于数组操作,到了 ES9,展开语法被扩展到了对象处理。
function foo (a, b, c ) {
console .log ({ a, b, c })
}
foo (...['html' , 'css' , 'js' ])
const name = 'liang'
const hobby = ['html' , 'css' ]
const newArr = [...name, ...hobby]
console .log (newArr)
const info = { name : 'liang' , age : 20 }
const object = { title : 'profile' , ...info, gender : 1 }
console .log (object)
const info = { name : 'liang' , profile : { age : 18 } }
const user = { ...info }
user.profile .age = 20
console .log (info.profile .age )
13. ES6 - 二进制和八进制连接符 const num1 = 100
const num2 = 0b100
const num3 = 0o100
const num4 = 0x100
console .log (num1)
console .log (num2)
console .log (num3)
console .log (num4)
const num = 10_000_000_000
console .log (num)
14. ES6 - Symbol 数据类型的使用 Symbol 是 ES6 中新增的一个基本数据类型,翻译为:符号。
Symbol 即使多次创建值,它们也是不同的:Symbol 函数执行后,每次创建出来的值都是独一无二的。
const s1 = Symbol ()
const s2 = Symbol ()
console .log (s1 === s2)
const s3 = Symbol ('aaa' )
console .log (s3.description )
Symbol 值作为对象的属性 key 的多种写法:
const s1 = Symbol ()
const s2 = Symbol ()
const s3 = Symbol ()
const s4 = Symbol ()
const obj = {
[s1]: '111' ,
[s2]: '222'
}
obj[s3] = '333'
Object .defineProperty (obj, s4, {
enumerable : true ,
configurable : true ,
writable : true ,
value : '444'
})
console .log (obj[s1])
前面我们说过,Symbol() 返回的值都是独一无二的,那么有没有办法让它返回相同的值呢?
Symbol.for(key) 是 ES6 中的一个静态方法,用于创建或查找全局注册表中的 Symbol。
const s1 = Symbol .for ('aaa' )
const s2 = Symbol .for ('aaa' )
console .log (s1 === s2)
const key = Symbol .keyFor (s1)
console .log (key)
15. ES6 - 数据结构 Set(元素不可重复) Set 是一个新增的数据结构,可以用来保存数据,类似于数组,但是和数组的区别是 Set 的元素不能重复。
const set = new Set ()
set.add (10 )
set.add (20 )
set.add (30 )
set.add (30 )
console .log (set);
因为 Set 结构具有元素不会重复的特性,所以我们可以用于 数组去重。
const arrSet = new Set ([32 , 10 , 25 , 10 , 32 , 15 ])
const newArr3 = [...arrSet]
const set = new Set ([32 , 10 , 25 , 10 , 32 , 15 ])
console .log (set.size )
set.add (18 )
set.delete (10 )
console .log (set.has (25 ))
console .log (set)
16. ES6 - 数据结构 WeakSet(存放对象) WeakSet 中只能存放对象类型,不能存放基本数据类型。WeakSet 对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,那么 GC 可以对该对象进行回收。
const weakSet = new WeakSet ()
let obj = { name : 'liang' }
weakSet.add (obj)
17. ES6 - 数据结构 Map(支持对象属性 key) Map 是一种新的数据结构,用于存储键值对,它与传统对象(Object)相比,具有更灵活的键类型和更好的性能特性。
const map = new Map ()
map.set (user, 'aaa' )
map.set (profile, 'bbb' )
map.set ('name' , 'liang' )
console .log (map)
const map = new Map ([['name' , 'liang' ], ['music' , '天空之外' ]])
console .log (map.size )
map.set ('age' , 20 ).set ('height' , 190 )
console .log (map.get ('name' ))
console .log (map.has ('age' ))
map.delete ('height' )
map.clear ()
console .log (map)
18. ES6 - 数据结构 WeakMap(key 只能是对象) WeakMap 的 key 只能使用对象,不接受其他的类型作为 key。WeakMap 的 key 对对象的引用是弱引用,如果没有其他引用引用这个对象,那么 GC 可以回收该对象。
let obj2 = { name : 'liang' }
const map2 = new WeakMap ()
map2.set (obj2, 'bbb' )
obj2 = null
19. ES7 - Array.includes 方法和指数运算符 ES7 新增了 includes 方法,可以直接判断数据是否在数组中。
const arr = ['html' , 'css' , 'js' ]
if (arr.includes ('css' )) {
console .log ('在数组中' )
}
20. ES8 - Object.values、Object.entries 方法 在 ES8 中提供了 Object.values() 来获取所有的 value 值。
const user = { name : 'liang' , age : 20 , height : 180 }
console .log (Object .keys (user))
console .log (Object .values (user))
通过 Object.entries() 可以获取到一个数组,数组中会存放可以枚举属性的键值对数组。
console .log (Object .entries (user))
21. ES8 - String.padStart、String.padEnd 方法 在 ES8 中,引入了两个字符串方法:padStart、padEnd,用于在字符串的开头或结尾填充指定字符,使其达到指定长度。
const string = 'hello'
console .log (string.padStart (8 ))
console .log (string.padStart (8 , '*' ))
console .log (string.padEnd (8 , '*' ))
尾逗号(Trailing Commas)是指在数组、对象字面量或函数参数列表的最后一个元素后添加的额外逗号。
function foo (m, n, ) {
console .log ({ m, n })
}
foo (111 , 222 ,)
22. ES10 - Array.flat、Array.flatMap 方法 flat() 和 flatMap() 是两个用于处理数组扁平化的常用方法。
const nums = [1 , [2 ], [[3 ]], [[[4 ]]]]
console .log (nums.flat (1 ))
console .log (nums.flat (2 ))
console .log (nums.flat (Infinity ))
const slogan = ['what are you doing' , 'how old are you' ]
const words2 = slogan.flatMap (item => item.split (' ' ))
console .log (words2)
23. ES10 - Object.fromEntries、String.trimStart 方法 Object.fromEntries() 方法用于将键值对列表转换为一个普通对象。
const entries = Object .entries (user)
console .log (Object .fromEntries (entries))
const string = ' hello world '
console .log ({ trimStart : string.trimStart () })
console .log ({ trimEnd : string.trimEnd () })
24. ES11 - 大整数类型 Bigint 在早期的 JavaScript 中,我们不能正确的表示过大的数字。大于 Number.MAX_SAFE_INTEGER 的数值,表示的值可能是不正确的。
const bigInt = 900719925474099100n
console .log (bigInt)
console .log (bigInt + 10n )
25. ES11 - 空值合并运算符 ?? 空值合并运算符(Nullish Coalescing Operator),当左侧操作数为 null/undefined 时,返回右侧操作数。
let bar = 0
console .log (bar ?? 'hello' )
26. ES11 - 可选链操作符 ?. ES11 进入了一个非常实用的特性:可选链操作符(Optional Chaining Operator)。
const profile = { name : 'liang' }
console .log (profile.info ?.age )
27. ES11 - globalThis 和 for...in 标准化 globalThis 是 ES11 引入的一个标准化的全局对象引用,用于在任何 JavaScript 环境中统一访问全局对象。
console .log (window )
console .log (global )
console .log (globalThis)
28. ES12 - FinalizationRegistry 执行清理回调 FinalizationRegistry 是 ES12 引入的一个高级特性,用于在对象被垃圾回收(GC)后执行清理回调。
let user = { name : 'liang' }
const finalRegistry = new FinalizationRegistry (() => {
console .log ('注册到 finalRegistry 的某个对象被销毁' );
})
finalRegistry.register (user)
user = null
29. ES12 - WeakRef 创建对象的弱引用 WeakRef 是 ES12 引入的一个特性,用于创建对对象的弱引用。
let user = { name : 'liang' }
let info = new WeakRef (user)
console .log (info.deref ())
30. ES12 - 逻辑赋值运算符、String.replaceAll() JavaScript 中的三种逻辑赋值运算符是 ES12 引入的语法糖。
let message = ''
message ||= 'default'
let a = 1
let b = 2
a &&= b
let c = ''
let d = 2
c ??= d
String.prototype.replaceAll() 是 ES12 引入的一个字符串方法。
const string = 'good idea good'
console .log (string.replaceAll ('good' , 'aaa' ))
console .log (string.replaceAll (/good/g , 'bbb' ))
31. ES13 - Array/String.at()、Object.hasOwn() Array.prototype.at() 和 String.prototype.at() 是 ES13 引入的新方法,支持负数索引取值。
const arr = ['html' , 'css' , 'js' , 'vue' ]
console .log (arr.at (-1 ))
ES13 中 Object 新增了一个静态方法(类方法):Object.hasOwn(obj, key)。
const user = { name : 'liang' }
console .log (Object .hasOwn (user, 'name' ))
console .log (Object .hasOwn (user, 'age' ))
32. ES13 - 类中新增的成员(私有化成员) 从 ES13 开始,正式支持在类中定义真正的私有化属性(private)。
class Person {
height = 180
#info = 'real private info'
constructor (name, age ) {
this .name = name
this .age = age
}
running ( ) {
console .log (this .#info)
this .#showName ()
}
#showName ( ) {
console .log ('name: ' + this .name );
}
}
const p = new Person ('liang' , 20 )
p.running ()
class Person {
static name = 'liang'
static #age = 20
static showName ( ) {
console .log (this .#age);
}
static {
console .log ('hello world' );
}
}
console .log (Person .name )
Person .showName ()
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online