前言:本文旨在本人对ES6功能点的查漏补缺,以及ESn功能的用法做一下记录。主要参考阮一峰老师的《ECMAScript6入门》
let 和 const
for循环设置循环变量是一个副作用域,循环体内是单独的子作用域
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
es6的6种声明变量方法
var function let const import class
顶层对象
顶层对象在js中指window,在node中指global
var创建的属于顶层对象,let和const不属于
var a = 1;
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // 1
let b = 1;
window.b // undefined
es2020引入globalThis作为顶层对象。也就是说,任何环境下,globalThis都是存在的,都可以从它拿到顶层对象,指向全局环境下的this。
字符串的扩展
标签模版
模版字符串可以跟在函数后面,这个函数会调用处理这个模板字符串。
let a = 5;
let b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);
简单理解下:
- tag的第一个参数是数组,里面的元素是没有变量替换的部分,上述例子里就是hello和world
- 其余的元素就是变量被替换的值,上述例子里就是
a+b的结果和a*b的结果 - 替换的规则是 数组的第一项元素
Hello+ 变量替换元素115+ 数组第二项元素world+ 变量替换元素250,如果变量替换在模版字符串最后,那么数组会多加一项空元素
主要的作用:
- 过滤 HTML 字符串,防止用户输入恶意内容
- 国际化
这里不过多讨论具体用法,可以自行查阅
includes(), startsWith(), endsWith()
这三种方法都支持传入第二个参数,表示位置
let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true,针对前n个字符
s.includes('Hello', 6) // false
padStart(),padEnd()
第一个参数表示填充之后的长度
- 参数小于字符本身的长度则无效
第二个参数表示填充的字符
- 填充字符超出长度,则自动截断
- 不传默认用空字符串填空
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
函数的扩展
length属性
函数的length属性,将返回没有指定默认值的参数个数
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
rest 参数
函数的arguments属性是类数组,使用时需要Array.from转一下,但是rest参数是真正的数组
// arguments变量的写法
function sortNumbers() {
return Array.from(arguments).sort();
}
// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();
尾调用优化
尾调用(Tail Call)就是指某个函数的最后一步是调用另一个函数。
function f() {
let m = 1;
let n = 2;
return g(m + n);
}
f();
// 等同于
function f() {
return g(3);
}
f();
// 等同于
g(3);
尾调用优化只适用于,内部的函数不会使用外部函数的变量
function addOne(a){
var one = 1;
function inner(b){
return b + one;
}
return inner(a); // 用到了外部函数变量one,所以不会进行尾调用优化
}
数组的扩展
Array.from
Array.from和扩展运算符的区别
扩展运算符背后调用的是遍历器接口(Symbol.iterator),如果一个对象没有部署这个接口,就无法转换。
Array.from方法还支持类似数组的对象。所谓类似数组的对象,本质特征只有一点,即必须有length属性。因此,任何有length属性的对象,都可以通过Array.from方法转为数组,而此时扩展运算符就无法转换。
Array.from({ length: 3 });
// [ undefined, undefined, undefined ]
Array.from可以接收第二个参数
效果等同于Array.from().map()
Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x);
Array.of
第一次知道还有这个。。。
Array.of和Array的区别
// Array.of()总是返回参数值组成的数组。如果没有参数,就返回一个空数组
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of() // []
Array.of(undefined) // [undefined]
// Array()只有当参数个数不少于 2 个时,才会返回由参数组成的新数组。
// 参数只有一个正整数时,实际上是指定数组的长度。
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
includes()
indexOf的缺点:
1、找到的是下标,需和-1比较,不够直观
2、内部执行全等,所以不够准确
[NaN].indexOf(NaN) // -1
对象的扩展
Object.values()
如果Object.values方法的参数是一个字符串,会返回各个字符组成的一个数组。
Object.values('foo')
// ['f', 'o', 'o']
如果参数不是对象,Object.values会先将其转为对象。由于数值和布尔值的包装对象,都不会为实例添加非继承的属性。所以,Object.values会返回空数组。
Object.values(42) // []
Object.values(true) // []
由于数值和布尔值的包装对象,都不会为实例添加非继承的属性
这句话可以参考Object.keys,理解成该方法都会返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名,由于number和boolean类型都是不可遍历(enumerable)的,所以会返回空数组。实现方法大概是这样:
Object.values = Object.values || function values(object) {
if (object === null || object === undefined) {
throw new TypeError("Cannot convert undefined or null to object");
}
let result = [];
if (isArrayLike(object) || isPlainObject(object)) {
for (let key in object) {
object.hasOwnProperty(key) && result.push(object[key]);
}
}
return result;
};
参考自:Object.values:返回一个给定对象自身的所有可枚举属性值的数组
Object.entries()
用处:
将对象转成Map
const obj = { foo: 'bar', baz: 42 };
const map = new Map(Object.entries(obj));
map // Map { foo: "bar", baz: 42 }
Object.fromEntries()
用处:
1、将Map转成对象
// 例一
const entries = new Map([
['foo', 'bar'],
['baz', 42]
]);
Object.fromEntries(entries)
// { foo: "bar", baz: 42 }
// 例二
const map = new Map().set('foo', true).set('bar', false);
Object.fromEntries(map)
// { foo: true, bar: false }
2、配合URLSearchParams处理url参数
Object.fromEntries(new URLSearchParams('foo=bar&baz=qux'))
// { foo: "bar", baz: "qux" }
运算符的扩展
Null 判断运算符??
与 ||的不同是, ||判断的是左侧是falsy,??左侧必须是undefined或者null:
const a = false || 1 // 1
const b = false ?? 1 // false
逻辑赋值运算符
// 或赋值运算符
x ||= y
// 等同于
x || (x = y)
// 与赋值运算符
x &&= y
// 等同于
x && (x = y)
// Null 赋值运算符
x ??= y
// 等同于
x ?? (x = y)
// 老的写法
user.id = user.id || 1;
// 新的写法
user.id ||= 1;