ES7(ECMAScript 2016)引入了一些新的特性和语法。以下是 ES7 中的全部特性:
一.指数运算符
引入了双星号(**
)作为指数运算符,用于计算一个数的幂。例如:2 ** 3
表示 2 的 3 次方。
let result = 2 ** 3; // 2 的 3 次方
console.log(result); // 输出 8
在这个例子中,2 ** 3
表达式表示对 2 进行 3 次幂运算,因此结果为 8。
指数运算符提供了一种更简洁、直观的方式来表示幂运算,相比于传统的 Math.pow 方法或者使用乘法实现幂运算,指数运算符使得代码更易读、更符合数学表达习惯。
这样,JavaScript 开发者可以更方便地进行幂运算,同时也使代码更加清晰易懂。
二.Array.prototype.includes()
方法
该方法用于判断数组是否包含指定的元素,并返回布尔值。它可以替代使用 indexOf() 方法进行元素查找。
const fruits = ['apple', 'banana', 'orange'];
console.log(fruits.includes('apple')); // true
console.log(fruits.includes('grape')); // false
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3)); // true
console.log(numbers.includes(6)); // false
通过使用 includes()
方法,我们可以轻松地检查数组中是否包含特定的元素。
三.Object.values()
方法
该方法返回对象自身可枚举属性的值组成的数组。这样可以方便地获取对象属性的值,而不需要遍历对象的键。
const person = {
name: 'Alice',
age: 30,
gender: 'female'
};
const values = Object.values(person);
console.log(values); // ['Alice', 30, 'female']
通过使用 Object.values()
方法,我们可以轻松地获取对象的所有值,并将它们存储在一个数组中。
四.Object.entries()
方法
该方法返回对象自身可枚举属性的键值对组成的数组。它可以很方便地将对象转换为可迭代的键值对集合。
const person = {
name: 'Alice',
age: 30,
gender: 'female'
};
const entries = Object.entries(person);
console.log(entries); // [['name', 'Alice'], ['age', 30], ['gender', 'female']]
通过使用 Object.entries()
方法,我们可以轻松地获取对象的所有键值对,并将它们存储在一个二维数组中。
另外,Object.entries()
方法还可以用于获取数组的索引和值的键值对
const colors = ['red', 'green', 'blue'];
const colorEntries = Object.entries(colors);
console.log(colorEntries); // [['0', 'red'], ['1', 'green'], ['2', 'blue']]
通过使用 Object.entries()
方法,我们可以直接获取数组的索引和值的键值对组成的数组。
五.async/await
引入了 async
和 await
关键字,用于编写异步操作更加简洁和易读的代码。async
关键字用于定义一个异步函数,await
关键字用于等待一个异步操作的结果。
// 异步函数,返回一个 Promise
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 异步函数使用 async 关键字定义
async function fetchData() {
console.log('Fetching data...');
await delay(2000); // 等待2秒钟
return 'Data fetched!';
}
// 使用 async/await 调用异步函数
async function handleAsyncOperation() {
try {
const result = await fetchData();
console.log(result);
} catch (error) {
console.error('An error occurred:', error);
}
}
handleAsyncOperation();
在上述示例中,我们定义了一个异步函数 fetchData()
,它模拟了一个异步操作,通过延迟2秒来模拟数据获取。然后,在另一个异步函数 handleAsyncOperation()
中,我们使用 await
关键字等待 fetchData()
函数的执行结果,并在控制台打印数据。
通过使用 async/await
,我们可以更清晰地表达异步操作的流程,并且可以使用类似同步代码的风格来编写异步代码,提高了代码的可读性和维护性。
六.字符串填充方法(ES8)
新增了字符串填充方法 padStart() 和 padEnd(),用于按指定的长度填充字符串。
1、padStart()
方法
用于在当前字符串的开头填充指定的字符串,直到字符串达到指定的长度。如果当前字符串长度大于或等于指定的长度,则返回当前字符串,不做任何操作。
const str = "Hello";
const paddedStr = str.padStart(10, '12345');
console.log(paddedStr); // 输出:"123451Hello"
//原始字符串 "Hello" 由于长度小于10,所以通过 padStart() 方法在其开头填充了 '12345',直到达到长度为10。
2、 padEnd()
方法
用于在当前字符串的结尾填充指定的字符串,直到字符串达到指定的长度。如果当前字符串长度大于或等于指定的长度,则返回当前字符串,不做任何操作。
const str = "JavaScript";
const paddedStr = str.padEnd(15, '-');
console.log(paddedStr); // 输出:"JavaScript-----"
//原始字符串 "JavaScript" 由于长度小于15,所以通过 padEnd() 方法在其结尾填充了 '-',直到达到长度为15。
七.对象 Rest/Spread 属性(ES9)
1.Rest 属性
Rest 属性允许你收集对象中剩余的属性,这些属性没有被解构赋值到已经定义的变量中。Rest 属性使用三个点(...)来表示。
const person = {
name: '小米',
age: 30,
country: 'china',
gender: 'female'
};
const { name, age, ...rest } = person;
console.log(name); // 输出:"小米"
console.log(age); // 输出:30
console.log(rest); // 输出:{ country: 'china', gender: 'female' }
我们使用 Rest 属性将 person
对象中除了 name
和 age
之外的属性收集到 rest
变量中。这样,rest
变量中存储了剩余的属性 { country: 'china', gender: 'female' }
。
2.Spread 属性
Spread 属性允许将一个对象的属性展开到另一个对象中。Spread 属性同样使用三个点(...)来表示。
const person = {
name: '小米',
age: 30
};
const details = {
...person,
country: 'china',
gender: 'female'
};
console.log(details);
// 输出:{ name: '小米', age: 30, country: 'china', gender: 'female' }
我们使用 Spread 属性将 person
对象的属性展开到 details
对象中,并添加了额外的属性 country
和 gender
。最终得到的 details
对象包含了所有属性:{ name: '小米', age: 30, country: 'china', gender: 'female' }
。
八、Promise.prototype.finally()
加了 finally 方法,用于指定不管 Promise 对象状态如何都会执行的回调函数
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const randomNum = Math.random();
if (randomNum < 0.5) {
resolve('Data fetched successfully');
} else {
reject('Error fetching data');
}
}, 2000);
});
}
fetchData()
.then((data) => {
console.log(data);
})
.catch((error) => {
console.log(error);
})
.finally(() => {
console.log('Fetching operation completed');
});
fetchData() 函数返回一个 Promise 对象,该对象在随机时间后根据随机数结果决定是成功还是失败。然后我们使用 then() 方法处理 Promise 成功的情况,使用 catch() 方法处理 Promise 失败的情况,并使用 finally() 方法指定一个在 Promise 结束后无论如何都会执行的回调函数。
无论 Promise 最终的状态是成功还是失败,finally() 方法中的回调函数都会被调用,
输出结果:
Data fetched successfully
Fetching operation completed
九、Array.prototype.flat() 方法
flat()
方法用于将嵌套数组扁平化,即将多层嵌套的数组结构转换为一层数组。
const nestedArray = [1, 2, [3, 4], [5, [6, 7]]];
const flatArray = nestedArray.flat();
console.log(flatArray);
// 输出:[1, 2, 3, 4, 5, 6, 7]
十、Array.prototype.flatMap() 方法
flatMap()
方法首先映射每个元素,然后将结果扁平化为一个新数组。它结合了 map()
和 flat()
两个方法的功能。
const array = [1, 2, 3, 4];
const mappedArray = array.flatMap(num => [num * 2, num * 3]);
console.log(mappedArray);
// 输出:[2, 3, 4, 6, 6, 9, 8, 12]
flatMap()
方法首先对数组中的每个元素进行映射操作(这里将每个数字乘以2和3),然后将结果扁平化为一个新数组。
通过使用 flat()
和 flatMap()
方法,我们可以更方便地处理嵌套数组并对数组元素进行操作。
十一、String.prototype.trimStart() 方法
trimStart()
方法用于移除字符串开头(左侧)的空白字符,包括空格、制表符、换行符等。
const stringWithWhitespace = " Hello, world!";
const trimmedString = stringWithWhitespace.trimStart();
console.log(trimmedString);
// 输出:"Hello, world!"
十二、String.prototype.trimEnd() 方法
trimEnd()
方法用于移除字符串结尾(右侧)的空白字符,同样包括空格、制表符、换行符等。
const stringWithWhitespace = "Hello, world! ";
const trimmedString = stringWithWhitespace.trimEnd();
console.log(trimmedString);
// 输出:"Hello, world!"
通过使用 trimStart()
和 trimEnd()
方法,我们可以方便地去除字符串开头和结尾的空白字符,使得字符串的处理更加简洁和准确。
十三、Object.fromEntries()
方法
用于将键值对的数组转换为对象的方法。这个方法在处理键值对数组时非常有用。
const entries = [
['name', 'apple'],
['age', 30],
['gender', 'female']
];
const obj = Object.fromEntries(entries);
console.log(obj);
// 输出:{ name: 'apple', age: 30, gender: 'female' }
我们有一个名为 entries
的数组,其中包含了多个键值对的子数组。然后,我们使用 Object.fromEntries()
方法将这些键值对的数组转换为对象,并将结果存储在 obj
变量中。最终得到的 obj
对象包含了所有的键值对:{ name: 'apple', age: 30, gender: 'female' }
。
十四、可选链操作符 ?.
用于简化访问可能不存在的属性或方法的操作的语法特性,通过使用 ?.
操作符可以避免出现 TypeError 错误。
假设我们有一个包含嵌套对象的数据结构,我们想要安全地访问这些对象的属性而不担心可能不存在的情况。
const user = {
name: 'Alice',
address: {
city: 'New York',
postalCode: '10001'
}
};
// 使用可选链操作符进行安全访问
const postalCode = user.address?.postalCode;
const country = user.address?.country;
console.log(postalCode); // 输出:'10001'
console.log(country); // 输出:undefined
我们定义了一个 user 对象,其中包含了一个嵌套的 address 对象。通过使用可选链操作符 ?.,我们可以安全地访问 user.address 对象的 postalCode 属性,即使 address 对象可能不存在。如果属性存在,则返回相应的值;如果属性不存在,则返回 undefined。
十五、空值合并运算符 ??
用于设定默认值的运算符,只有在操作数为 null
或 undefined
时才会返回默认值。这个运算符可以帮助简化代码,并且避免意外情况下使用不合适的默认值。
假设我们有一个变量,我们想要为其设定一个默认值,但只在变量的值为 null 或 undefined 时才应用该默认值。
const userInput = ''; // 或者为 null 或 undefined
// 使用空值合并运算符设定默认值
const username = userInput ?? 'Guest';
console.log(username); // 输出:''
我们定义了一个 userInput 变量,其值为空字符串。然后,我们使用空值合并运算符 ?? 来设定默认值 'Guest' 给 username 变量。由于 userInput 的值为空字符串而不是 null 或 undefined,因此空值合并运算符不会触发默认值的应用,最终输出为空字符串。
如果我们将 userInput 的值改为 null 或 undefined,那么空值合并运算符将会使用默认值 'Guest':
const userInput = null;
const username = userInput ?? 'Guest';
console.log(username); // 输出:'Guest'
通过使用空值合并运算符,我们可以更精确地控制在变量为 null 或 undefined 时使用默认值的情况,避免意外情况下产生错误的行为。希望这个示例能够帮助你理解空值合并运算符的用法
十六、全局对象 globalThis
全局对象 globalThis
提供了一种标准的方式来获取全局对象,不受执行环境的限制。通过使用 globalThis
,可以在不同的 JavaScript 环境中统一地访问全局对象,无论是在浏览器、Node.js 还是其他 JavaScript 运行时环境中。
// 在浏览器环境下
console.log(globalThis === window); // 输出:true
// 在 Node.js 环境下
console.log(globalThis === global); // 输出:true
// 在 Web Worker 环境下
self.addEventListener('message', () => {
console.log(globalThis === self); // 输出:true
});
// 在 iframe 中
console.log(globalThis === window); // 输出:false
console.log(globalThis === window.parent); // 输出:true
我们首先通过比较 globalThis
和特定环境下的全局对象(如 window
、global
、self
)来验证 globalThis
的用法。在不同的 JavaScript 运行时环境中,globalThis
都应该指向全局对象,确保了跨环境的统一性。
十七、Promise.any()
Promise.any()
是一个 Promise 静态方法,它接收一组 Promise 对象,并在其中任何一个 Promise 解决(fulfilled)时返回该 Promise 的结果。如果所有 Promise 都被拒绝(rejected),则会抛出一个 AggregateError 错误,其中包含所有 Promise 的 rejection 原因。
const promises = [
new Promise((resolve, reject) => setTimeout(() => resolve('Promise 1 resolved'), 1000)),
new Promise((resolve, reject) => setTimeout(() => reject('Promise 2 rejected'), 500)),
new Promise((resolve, reject) => setTimeout(() => resolve('Promise 3 resolved'), 1500))
];
Promise.any(promises)
.then(result => {
console.log('First resolved promise:', result);
})
.catch(error => {
console.log('All promises were rejected:', error);
});
在上面的示例中,我们定义了一个包含三个 Promise 对象的数组 promises
,每个 Promise 在不同的延迟后会解决或拒绝。我们调用 Promise.any(promises)
来等待这些 Promise 中任何一个解决,并获取其结果。
根据上述示例代码的执行顺序,最先解决的 Promise 是第二个 Promise(500 毫秒后被拒绝),因此在 .then()
回调中会输出 'First resolved promise: Promise 1 resolved'
。如果所有 Promise 都被拒绝,将会执行 .catch()
回调并输出 'All promises were rejected: [Array containing rejection reasons]'
。
通过使用 Promise.any()
方法,我们可以方便地处理多个 Promise 对象,并快速获取最先解决的 Promise 的结果
十八、WeakRef
WeakRef
是 JavaScript 中的一个类,它提供了对对象的弱引用支持。通过使用 WeakRef
,可以创建对对象的弱引用,这种引用不会阻止垃圾回收器回收对象。弱引用通常用于需要跟踪对象但又不希望阻止对象被垃圾回收的情况。
let obj = { key: 'value' };
// 创建对象的弱引用
const weakRef = new WeakRef(obj);
// 获取弱引用指向的对象
let objFromWeakRef = weakRef.deref();
console.log(objFromWeakRef); // 输出:{ key: 'value' }
// 解除原对象的引用
obj = null;
// 由于只有弱引用指向对象,对象可能已经被垃圾回收
objFromWeakRef = weakRef.deref();
console.log(objFromWeakRef); // 输出:null
在上面的示例中,我们首先创建一个普通对象 obj
,然后使用 WeakRef
类来创建这个对象的弱引用 weakRef
。我们通过弱引用的 deref()
方法获取弱引用指向的对象,并打印出对象内容。接着,我们将原始对象引用置为 null
,这意味着只有弱引用指向该对象。最后,再次使用 deref()
方法获取弱引用指向的对象,此时应该返回 null
,因为原始对象已经被垃圾回收。
十九、WeakMap 和 WeakSet 的新方法
1、WeakMap
WeakMap 是一种集合,其中键是对象,值可以是任意类型。WeakMap 中的键是弱引用,这意味着当没有其他强引用指向键时,这些键会被自动地从 WeakMap 中删除。
set(key, value)
: 将键值对添加到 WeakMap 中。get(key)
: 根据键获取对应的值。has(key)
: 检查 WeakMap 中是否存在特定键。delete(key)
: 从 WeakMap 中删除指定键let weakMap = new WeakMap(); let key = { id: 1 }; let value = 'Secret Data'; weakMap.set(key, value); console.log(weakMap.get(key)); // 输出: 'Secret Data' key = null; // 让原始对象的引用失效 // 由于 key 的引用失效,该键值对将被自动删除 console.log(weakMap.get(key)); // 输出: undefined
2、 WeakSet
WeakSet 是一种集合,其中存储的是对象的引用,且每个对象只能在 WeakSet 中出现一次。与 WeakMap 类似,WeakSet 中的对象也是弱引用的。
add(value)
: 向 WeakSet 中添加新的对象。has(value)
: 检查 WeakSet 中是否存在特定对象。delete(value)
: 从 WeakSet 中删除指定对象。-
let weakSet = new WeakSet(); let obj1 = { name: 'Alice' }; let obj2 = { name: 'Bob' }; weakSet.add(obj1); weakSet.add(obj2); console.log(weakSet.has(obj1)); // 输出: true console.log(weakSet.has(obj2)); // 输出: true // 从 WeakSet 中删除一个对象 weakSet.delete(obj1); console.log(weakSet.has(obj1)); // 输出: false