前言
ES全称是ECAMScript,它是由ECAM国际标准化组织制定的一项脚本语言的标准化规范
从ES5之后的更新,从2015年6月开始每1年更新1次,并增加1次版本号
如2015年6月的版本为ES2015,又被称为ES6
数组通过forEach()函数进行遍历
ES5.js1 2 3 4 5
| var arr = [];
var result = arr.forEach(function (currentValue, index, array, thisArg) { console.log(currentValue, index, array, thisArg); });
|
数组通过filter()函数进行筛选
ES5.js1 2 3 4 5
| const arr = [];
var result = arr.filter(function (currentValue, index, array, thisArg) { return currentValue; });
|
数组通过some()函数进行查找
ES5.js1 2 3 4 5
| const arr = [];
var exist = arr.some(function (currentValue, index, array, thisArg) { return true; });
|
字符串去除首尾空白字符
ES5.js1 2 3
| const str = " hello world ";
const result = str.trim();
|
对象的属性描述符
ES5.js1 2 3 4 5 6 7 8
| var obj = { key: "value" };
Object.defineProperty(obj, "key", { configurable: false, enumerable: false, writable: false, value: "", });
|
ES5.js1 2 3 4 5 6 7 8 9 10 11 12
| var obj = { _key: "value" };
Object.defineProperty(obj, "key", { configurable: false, enumerable: false, get: function () { return obj._key; }, set: function (value) { return obj._key = value; }, });
|
具有块级作用于的变量
ES5.js1 2 3 4
| var a = null; { console.log(a); }
|
ES6.js1 2 3 4
| const b = null; { console.log(b); }
|
- var定义的变量可以再次被定义,let和const定义的变量不能再次定义
ES5.js1 2
| var a = null; var a = "";
|
ES6.js
- var在全局作用域定义的变量会作为window对象的属性,let和const在全局作用域定义的变量不会作为window对象的属性
ES5.js1 2
| var a = null; console.log(window.a);
|
ES6.js1 2
| const a = null; console.log(window.a);
|
let关键字
ES6.js
ES6.js
const关键字
- const定义的变量是只读变量,不能被修改
- const必须直接定义变量,不能先声明变量再赋值
ES6.js
ES6.js
对象增强
对象属性的增强
- 将一个变量值作为对象的一个属性值时,如果变量名与属性名相同,可以简写
ES5.js1 2 3 4 5
| var key = "value";
var obj = { key: key }
|
ES6.js1 2 3 4 5
| const key = "value";
const obj = { key }
|
对象方法的增强
ES5.js1 2 3
| var obj = { fn: function () {} }
|
ES6.js1 2 3
| const obj = { fn() {} }
|
计算属性名
- 在对象中定义一个属性时,如果这个属性名是可能会变化的,可以将变量值作为属性名
ES6.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const key = "filed-name";
const obj = { [key]: "value" };
obj[key] = "value";
delete obj[key];
Object.defineProperty(obj, key, {})
|
Symbol
定义Symbol
ES6.js
Symbol的应用
ES6.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const symbol = Symbol();
const obj = { [symbol]: "value" };
obj[symbol] = "value";
delete obj[symbol];
Object.defineProperty(obj, symbol, {})
|
获取对象的属性
ES5.js1
| var keys = Object.keys(obj);
|
ES6.js1
| const symbols = Object.getOwnPropertySymbols(obj);
|
Symbol的描述
定义具有描述的Symbol
ES10.js1
| const symbol = Symbol("description");
|
获取Symbol的描述
ES10.js1
| console.log(symbol.description);
|
定义相同的Symbol
ES10.js1 2 3
| const symbol1 = Symbol("description"); const symbol2 = Symbol("description"); console.log(symbol1 === symbol2);
|
- 如果使用
for()函数定义Symbol,如果描述相同,则Symbol相同
ES10.js1 2 3
| const symbol1 = Symbol.for("description"); const symbol2 = Symbol.for("description"); console.log(symbol1 === symbol2);
|
解构(Destructuring)
- 一些编程语言,…,允许多个变量被并行的赋值,…,如果赋值的右手侧是一个单一变量(比如一个数组或结构),这个特征就叫做解包(unpacking)或解构(维基百科)
数组的解构
ES6.js1 2
| const arr = ["value", "value"]; const [ key1, key2 ] = arr;
|
- 解构数组时,如果数值对应索引的值被抛弃,则对应索引位置的变量需留空
ES6.js1 2 3
| const arr = ["value1", "value2", "value3"]; const [ key1, , key3 ] = arr; console.log(key3);
|
- 解构数组时,映射到等号左面的变量个数超出,则多出来的变量值为
undefined
ES6.js1 2 3
| const arr = ["value", "value"]; const [ key1, key2, key3 ] = arr; console.log(key3);
|
- 解构数组时,映射到等号左边的变量期望是数组时,需要使用
...扩展运算符,得到剩余参数
ES6.js1 2 3 4
| const key2 = [] const arr = ["value1", "value2", "value3"]; const [ key1, ...keyOther ] = arr; console.log(keyOther);
|
ES6.js1 2 3 4
| const arr = ["value1", undefined]; const [ key1, key2 = "default2", key3 = "default3" ] = arr; console.log(key2); console.log(key3);
|
对象的结构
- 通过与对象相同的属性名的变量进行解构匹配
- 解构对象时,映射到等号左面的变量名没有顺序要求
ES6.js1 2
| const obj = { key1: "value", key2: "value" }; const { key1, key2 } = obj;
|
ES6.js1 2 3 4
| const obj = { key1: "value1", key2: "value2" }; const { key1: key3, key2 } = obj; console.log(key3); console.log(key2);
|
- 解构对象时,映射到等号左边的变量期望是对象时,需要使用
...扩展运算符,得到剩余参数
ES6.js1 2 3
| const obj = { key1: "value1", key2: "value2", key3: "value3" }; const { key1, ...keyOther } = obj; console.log(keyOther);
|
ES6.js1 2 3 4
| const obj = { key1: undefined, key2: undefined }; const { key1: key3 = "default1", key2 = "default2" } = obj; console.log(key3); console.log(key2);
|
展开语法(Spread Syntax)
可展开的变量
数组
ES6.js1 2
| const arr = []; console.log(...arr);
|
字符串
ES6.js1 2
| const str = ""; console.log(...str);
|
对象
ES9.js1 2 3 4 5 6 7 8 9 10
| const obj1 = { key1: "value", };
const obj2 = { ...obj1, key2: "value", };
console.log(obj2);
|
展开语法的使用场景
调用函数时
ES6.js1 2 3 4 5 6 7
| const arr = [ "value1", "value2" ]; function fn(arg1, arg2) { console.log(arg1); console.log(arg2); }
fn(...arr);
|
定义数组时
ES6.js1 2 3
| const arr1 = [ "value1", "value2" ];
const arr2 = [ ...arr1, "value3" ];
|
创建对象时
- 将一个对象在另一个对象中展开,这个对象的所有属性键值对会赋值给另一个对象
ES9.js1 2 3 4 5 6 7 8 9 10
| const obj1 = { key1: "value", };
const obj2 = { ...obj1, key2: "value", };
console.log(obj2);
|
模板字符串
ES5.js1 2
| const a = ""; const b = "文本内容" + a;
|
ES6.js1 2
| const a = ""; const b = `文本内容${a}`;
|
通过模板字符串调用函数并传递参数
- 将模板字符串中的字符串作为第一个参数传递给函数,如果字符串中插入了变量,会根据变量位置拆分字符串,以字符串数组的形式作为第一个参数,其他参数依次是插入的变量值
ES5.js1 2 3
| function fn(...args) {}
fn(["front", "middle", "back"], 1, 2);
|
ES6.js1 2 3 4
| function fn(...args) {}
fn`front{1}middle${2}back`;
|
变量默认值
通过空值合并操作符为变量定义默认值
- 为变量赋值时,如果变量值为
null或undefined,则实际使用默认值赋值
ES11.js1 2
| const a = null; const b = a ?? "default";
|
为函数形参定义默认值
- 为函数形参赋值时,如果实参值为
undefined,则实际使用默认值赋值
ES6.js1 2 3
| function fn(a = "default") {}
fn();
|
形参具有默认值时的形参书写顺序(推荐)
ES6.js1 2 3
| function fn(a, b = "default") {}
fn("value")
|
- 具有多个形参时,具有默认值的形参与剩余参数最好都写在最后,剩余参数最好写在具有默认值的形参之后
ES6.js1 2 3
| function fn(a, b = "default", ...args) {}
fn("value")
|
形参具有默认值时的参数个数统计
- 函数的形参具有默认值时,统计参数个数时,不会被算在内
ES6.js1 2 3
| function fn(a = "default") {}
console.log(fn.length);
|
- 函数的形参具有默认值时,统计arguments的长度时,会根据实参决定arguments的长度
ES6.js1 2 3 4 5
| function fn(a = "default") { console.log(arguments.length); }
fn();
|
ES6.js1 2 3 4 5
| function fn(a = "default") { console.log(arguments.length); }
fn(null);
|
函数的默认值定义为对象
ES6.js1 2 3
| function fn(obj = { key: "value" }) {}
fn();
|
ES6.js1 2 3
| function fn({ key } = { key: "value" }) {}
fn();
|
ES6.js1 2 3
| function fn({ key = "value" } = {}) {}
fn();
|
箭头函数
- 箭头函数不能作为构造函数使用
- 箭头函数没有super
- 箭头函数不绑定this指向,其this指向是上层this指向
- 箭头函数没有arguments,无法通过arguments获取参数
ES6.js1
| const fn = (arg1, arg2) => {console.log()};
|
ES6.js1
| const fn = arg => {console.log()};
|
- 代码块内只有一句代码,且为返回语句,可以省略大括号和
return关键字
ES6.js1
| const fn = (arg1, arg2) => "value";
|
- 代码块内只有一句代码,且为返回语句,且返回的是对象,虽然可以省略大括号和
return关键字,但要使用()包裹返回的对象
ES6.js1
| const fn = (arg1, arg2) => ({ key: "value" });
|
不同进制数的字面量表示
十进制数
ES5.js
二进制数
ES6.js
八进制数
ES5.js
ES6.js
十六进制数
ES5.js
Set集合
- Set集合中的值不会重复,如果添加重复数据,会自动去重
Set集合
定义Set集合
ES6.js
获取元素总数
ES6.js1
| const result = set.size;
|
添加元素
ES6.js
删除元素
ES6.js1
| const success = set.delete("value");
|
删除所有元素
ES6.js
判断是否包含指定元素
ES6.js1
| const exist = set.has("value");
|
遍历Set集合
ES6.js1 2 3
| for (const item of set) { console.log(item); }
|
ES6.js1 2 3
| set.forEach(item => { console.log(item); });
|
Set集合与数组互转
数组转换为Set集合
ES6.js1 2 3
| const arr = [];
const set = new Set(arr);
|
Set集合转换为数组
ES6.js1
| const arr = Array.from(set);
|
WeakSet集合
- WeakSet集合只能存储引用类型数据,不能存储基本类型数据
- WeakSet集合存储的引用类型数据是弱引用,如果加入到集合的数据没有被其他引用,则会被GC清理
- WeakSet集合不能被遍历,因为元素可能不存在,所以没有
size属性和clear()方法
定义WeakSet集合
ES6.js1
| const weakSet = new WeakSet();
|
添加元素
ES6.js1 2 3
| const key = "value";
weakSet.add(key);
|
删除元素
ES6.js1 2 3
| const key = "value";
weakSet.delete(key);
|
判断是否包含指定元素
ES6.js1 2 3
| const key = "value";
const exist = weakSet.has(key);
|
Map映射
Map映射
- Map对象在
toString()操作时会完整返回结构,而Object对象在toString()操作时只会输出[Object object]
- 所以相比于Object对象,Map对象更适合作为计算属性名
- Map不仅可以将任意类型数据作为值,还可以将任意类型数据作为键,而Object对象只能将字符串或Symbol作为键
定义Map映射
ES6.js
获取键值对总数
ES6.js1
| const result = map.size();
|
添加或修改键值对
ES6.js1
| map.set("key", "value");
|
根据指定键获取值
ES6.js1
| const value = map.get("key");
|
根据指定键删除键值对
ES6.js1
| const success = map.delete("key");
|
删除所有键值对
ES6.js
根据指定键判定键值对是否存在
ES6.js1
| const exist = map.has("key");
|
遍历键值对
ES6.js1 2 3 4 5 6
| for (const item of map) { const [key, value] = item; console.log(item); console.log(key); console.log(value); }
|
ES6.js1 2 3
| map.forEach(value => { console.log(value); });
|
WakeMap映射
- WeakMap映射的键只能存储引用类型数据,不能存储基本类型数据
- WeakMap映射存储的键值对的键是弱引用,如果加入到映射的键没有被其他引用,则会被GC清理
- WeakMap映射不能被遍历,因为键值对可能不存在,所以没有
size属性和clear()方法
定义WeakMap映射
ES6.js1
| const weakMap = new WeakMap();
|
添加或修改键值对
ES6.js1
| weakMap.set("key", "value");
|
根据指定键获取值
ES6.js1
| const value = weakMap.get("key");
|
根据指定键删除键值对
ES6.js1
| const success = weakMap.delete("key");
|
根据指定键判定键值对是否存在
ES6.js1
| const exist = weakMap.has("key");
|
判断数组中是否存在指定元素
ES7.js1 2 3
| const arr = [];
const exist = arr.includes("value");
|
指定开始查找位置
0:缺省值,从头查找
ES7.js1 2 3
| const arr = [];
const exist = arr.includes("value", 0);
|
计算乘方
ES5.js1
| const result = Math.pow(2, 3);
|
ES7.js
获取对象的所有键和所有值
ES5.js1 2 3
| const obj = {};
const keys = Object.keys(obj);
|
ES8.js1 2 3
| const obj = {};
const values = Object.values(obj);
|
将对象转换为二维数组
ES8.js1 2 3
| const obj = { key1: "value", key2: "value" };
const arr = Object.entries(obj);
|
将字符串转换为二维数组
ES8.js1 2 3
| const str = "value";
const arr = Object.entries(str);
|
字符串根据长度补齐空白
从字符串首部补齐空白
2:字符串最短长度
"0":用于填充空白字符的字符串
ES8.js1 2 3
| const str = "1";
const result = str.padStart(2, "0");
|
从字符串尾部补齐空白
ES8.js1 2 3
| const str = "1";
const result = str.padEnd(2, "0");
|
允许参数列表末尾添加逗号
ES8.js1 2 3 4 5
| function fn(arg, ) { }
fn("", )
|
获取对象的属性描述符
ES8.js1 2 3
| const obj = {}
const result = Object.getOwnPropertyDescriptors(obj);
|
对象上使用展开运算符
ES9.js1 2 3 4 5 6 7 8 9 10
| const obj1 = { key1: "value", };
const obj2 = { ...obj1, key2: "value", };
console.log(obj2);
|
将多维数组数组扁平化
仅进行扁平化
1:指定层级
Infinity:无穷大,展开所有层级
ES10.js1 2 3
| const arr = [1, [2]];
const result = arr.flat(1);
|
先处理数据再进行扁平化
ES10.js1 2 3 4 5 6
| const arr = [ "key1 value1 value2", "key2 value", ];
const result = arr.map((item) => item.split(" ")).flat(1);
|
1 2 3 4 5 6
| const arr = [ "key1 value1 value2", "key2 value", ];
const result = arr.flatMap((item) => item.split(" "));
|
将二维数组转换为对象
ES10.js1 2 3
| const arr = [["key1", "value"], ["key2", "value"]];
const obj = Object.fromEntries(arr);
|
字符串去除首尾空白字符
去除首尾空白字符
ES5.js1 2 3
| const str = " hello world ";
const result = str.trim();
|
去除首部空白字符
ES10.js1 2 3
| const str = " hello world ";
const result = str.trimStart();
|
去除尾部空白字符
ES10.js1 2 3
| const str = " hello world ";
const result = str.trimEnd();
|
Symbol的描述
BigInt
ES11.js1
| const bigInt = 9007199254740993n;
|
空值合并操作符
可选链操作符
安全的访问属性
通过短路与
ES5.js1 2 3
| const obj = { key: "value" }
const value = obj && obj.key;
|
通过可选链操作符
ES11.js1 2 3
| const obj = { key: "value" }
const value = obj?.key;
|
安全的执行函数
通过短路与
ES5.js1 2 3
| const obj = { method: function () {} }
obj && obj.method();
|
通过可选链操作符
ES11.js1 2 3
| const obj = { method: function () {} }
obj?.method?.();
|
全局对象
ES5.js
ES11.js1
| console.log(globalThis);
|
for…in标准化
- for…in从ES3开始就被定义,但直到ES11才被标准化,定义for…in遍历对象时,只会遍历对象的键
ES11.js1 2 3 4 5
| const obj = { key: "value" }
for (const key in obj) { console.log(key); }
|
对象被GC回收后的回调函数
ES12.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| let obj1 = {} let obj2 = {}
const finalizationRegistry = new FinalizationRegistry((value) => { console.log(value, "callback success") });
finalizationRegistry.register(obj1); finalizationRegistry.register(obj2, "obj2");
obj1 = null; obj2 = null;
|
弱引用对象
ES12.js1 2 3 4 5 6 7 8 9 10 11
| let obj = { key: "value", fn: function () {} }
let weakRef = new WeakRef(obj);
console.log(weakRef.deref().key);
weakRef.deref().fn();
|
逻辑赋值运算符
ES12.js1 2 3
| function fn(key) { key ||= "default"; }
|
- 如果传递了undefined或null,则使用默认值为变量赋值
ES12.js1 2 3
| function fn(key) { key ??= "default"; }
|
- 如果对象中存在指定属性,就将指定属性的值作为对象的值
ES12.js1 2 3
| const obj = { obj: { key: "value" } };
obj &&= obj.obj;
|
长数字分隔符
- 利用
_分隔数字,可以提高代码的可读性,不限制_书写的位置
英式数字分隔法
ES12.js1
| const oneBillion = 1_000_000_000;
|
中式数字分隔法
ES12.js1
| const oneBillion = 10_0000_0000;
|
字符串替换子串
ES5.js1 2 3
| const str = "old";
str.replace("old", "new");
|
ES12.js1 2 3
| const str = "old";
str.replaceAll("old", "new");
|
元素访问方法
- ES5通过
[]只能正向访问(从0开始),不能逆向访问
ES51 2 3
| const arr = [""]
arr[0];
|
- ES13通过
at()可以正向访问(从0开始),也可以逆向访问(从-1开始)
ES13.js1 2 3 4
| const arr = [""]
arr.at(0); arr.at(-1);
|
判断属性是否在当前对象上而非原型对象上
ES3.js1 2 3
| const obj = { key: "value" };
const exist = obj.hasOwnProperty("key");
|
ES13.js1 2 3
| const obj = { key: "value" };
const exist = Object.hasOwn(obj, "key");
|
类中的新成员
- 直接在类中定义实例属性,而不是在构造方法中定义实例属性
ES13.js1 2 3
| class Cls { key = "value"; }
|
公共属性和私有属性
公共属性
- 没有使用修饰符作为属性名前缀的属性为公共属性(public)
ES13.js1 2 3 4 5 6
| class Cls { key = "value"; }
const cls = new Cls(); console.log(cls.key);
|
约定的私有属性
使用_作为属性名前缀的属性仍然可以被在外部被访问
ES13.js1 2 3 4 5 6
| class Cls { _key = "value"; }
const cls = new Cls(); console.log(cls._key);
|
私有属性
- 真正的私有属性(private)使用
#作为属性名前缀
使用#作为属性名前缀的属性不可以在外部被访问,只能在类内部被访问
ES13.js1 2 3 4 5 6
| class Cls { #key = "value"; }
const cls = new Cls();
|
实例属性和静态属性
实例属性
- 没有使用修饰符修饰的属性为实例属性,实例属性只能通过对象访问
ES13.js1 2 3 4 5 6
| class Cls { key = "value"; }
const cls = new Cls(); console.log(cls.key);
|
静态属性
- 使用
static作为修饰符修饰的属性为静态属性,静态属性只能通过类访问
ES13.js1 2 3 4 5
| class Cls { static key = "value"; }
console.log(Cls.key);
|
静态私有属性
ES13.js1 2 3 4 5
| class Cls { static #key = "value"; }
|
静态代码块
- 静态代码块会在加载解析类时立即执行(创建对象之前)且只会执行一次
ES13.js1 2 3 4 5
| class Cls { static { ... } }
|
完成