ES6的学习
字符串的扩展
- ES6 加强了对 Unicode 的支持,允许采用
\uxxxx
形式表示一个字符,其中xxxx表示字符的 Unicode 码点。 - 字符串的遍历器接口,ES6 为字符串添加了遍历器接口(详见《Iterator》一章),使得字符串可以被for…of循环遍历。
- 模板字符串
字符串的新增方法
fromCodePoint
用于从 Unicode 码点返回对应字符,与fromCharCode
的区别就是能不能识别码点大于0xFFFF
的字符String.fromCodePoint方法有多个参数,则它们会被合并成一个字符串返回。String.fromCodePoint(0x20BB7) // "𠮷"
codePointAt
方法会正确返回 32 位的 UTF-16 字符的码点let s = '𠮷a'; s.codePointAt(0).toString(16) // "20bb7" s.codePointAt(2).toString(16) // "61"
includes
返回布尔值,表示是否找到了参数字符串startsWith
返回布尔值,表示参数字符串是否在原字符串的头部。startsWith
返回布尔值,表示参数字符串是否在原字符串的尾部。
以上三个方法都可接收第二个参数使用第二个参数n时,endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束let s = 'Hello world!'; s.startsWith('Hello') // true s.endsWith('!') // true s.includes('o') // true let s = 'Hello world!'; s.startsWith('world', 6) // true s.endsWith('Hello', 5) // true s.includes('Hello', 6) // false
repeat
方法返回一个新字符串,表示将原字符串重复n次。'x'.repeat(3) // "xxx" 'hello'.repeat(2) // "hellohello" 'na'.repeat(0) // "" //参数如果是小数,会被取整。 'na'.repeat(2.9) // "nana" // 如果repeat的参数是负数或者Infinity,会报错。 // 如果参数是 0 到-1 之间的小数,则等同于 0, // 参数NaN等同于 0。 // 如果repeat的参数是字符串,则会先转换成数字。
padStart
字符串补全长度,用于头部补全'x'.padStart(5, 'ab') // 'ababx' 'x'.padStart(4, 'ab') // 'abax'
padEnd
用于尾部补全
padStart()和padEnd()一共接受两个参数'x'.padEnd(5, 'ab') // 'xabab' 'x'.padEnd(4, 'ab') // 'xaba'
,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串
。如果原字符串的长度,等于或大于最大长度,则字符串补全不生效,返回原字符串
。如果省略第二个参数,默认使用空格补全长度。trimStart
消除字符串头部的空格,返回的都是新字符串,不会修改原始字符串。trimEnd
消除尾部的空格,返回的都是新字符串,不会修改原始字符串。const s = ' abc '; s.trim() // "abc" s.trimStart() // "abc " s.trimEnd() // " abc"
matchAll
方法返回一个正则表达式在当前字符串的所有匹配,详见《正则的扩展》的一章。replaceAll
历史上,字符串的实例方法replace()只能替换第一个匹配,如果要使用replace替换所有字符,就要使用正则表表达式。但是使用replaceAll可以一次性替换所有匹配。返回一个新字符串,不会改变原字符串
'aabbcc'.replace(/b/g, '_') // 使用replace替换所有字符 'aabbcc'.replaceAll('b', '_') // 使用replaceAll方法,一次性替换所有匹配
at
方法接受一个整数作为参数,返回参数指定位置的字符,支持负索引(即倒数的位置)const str = 'hello'; str.at(1) // "e" str.at(-1) // "o"
正则的扩展(暂无研究)
数值的扩展
- 二进制和八进制表示法
- 数值分隔符
ES2021,允许 JavaScript 的数值使用下划线(_)作为分隔符。
123_00 === 12_300 // true 12345_00 === 123_4500 // true 12345_00 === 1_234_500 // true
Number.isFinite
用来检查一个数值是否为有限的(finite)如果参数类型不是数值,Number.isFinite一律返回false。Number.isFinite(15); // true Number.isFinite(0.8); // true Number.isFinite(NaN); // false Number.isFinite(Infinity); // false Number.isFinite(-Infinity); // false Number.isFinite('foo'); // false Number.isFinite('15'); // false Number.isFinite(true); // false
Number.isNaN
用来检查一个值是否为NaN。如果参数类型不是NaN,Number.isNaN一律返回false。Number.isNaN(NaN) // true Number.isNaN(15) // false Number.isNaN('15') // false Number.isNaN(true) // false Number.isNaN(9/NaN) // true Number.isNaN('true' / 0) // true Number.isNaN('true' / 'true') // true
Number.parseInt
ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。Number.parseFloat
Number.isInteger
用来判断一个数值是否为整数。Number.EPSILON
新增一个极小的常量Number.EPSILON。根据规格,它表示 1 与大于 1 的最小浮点数之间的差。Number.MAX_SAFE_INTEGER
和Number.MIN_SAFE_INTEGER
这两个常量,用来表示这个范围的上下限(整数范围在-2^53 到 2^53之间)。
10.Number.isSafeInteger
判断整数是否在上面那两个常量之间
Math对象的扩展
Math.trunc
方法用于去除一个数的小数部分,返回整数部分。Math.sign
方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值它会返回五种值。 Math.sign(-5) // -1 参数为负数,返回-1; Math.sign(5) // +1 参数为正数,返回+1; Math.sign(0) // +0 参数为 0,返回0; Math.sign(-0) // -0 参数为-0,返回-0; Math.sign(NaN) // NaN 其他值,返回NaN。
Math.cbrt()
方法用于计算一个数的立方根
还有其他不常用的Math函数,具体看ECMAScript 6 入门-数值的扩展
BigInt (大整数)数据类型
JavaScript 所有数字都保存成 64 位浮点数,这给数值的表示带来了两大限制。一是数值的精度只能到 53 个二进制位(相当于 16 个十进制位),大于这个范围的整数,JavaScript 是无法精确表示,这使得 JavaScript 不适合进行科学和金融方面的精确计算。二是大于或等于2的1024次方的数值,JavaScript 无法表示,会返回Infinity。
函数的扩展(简单了解一下)
- 函数参数的默认值
- rest 参数
- 严格模式
- name 属性
- 箭头函数
数组的扩展
- 扩展运算符
...
它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列- 用法
console.log(...[1, 2, 3]) // 1,2,3
- 用法
复制数组
const a1 = [1, 2]; // 写法一 const a2 = [...a1]; // 写法二 const [...a2] = a1;
- 用法三
合并数组
const arr1 = ['a', 'b']; const arr2 = ['c']; const arr3 = ['d', 'e']; // ES5 的合并数组 arr1.concat(arr2, arr3); // [ 'a', 'b', 'c', 'd', 'e' ] // ES6 的合并数组 [...arr1, ...arr2, ...arr3] // [ 'a', 'b', 'c', 'd', 'e' ]
- 任何定义了遍历器(Iterator)接口的对象(参阅 Iterator 一章),都可以用扩展运算符转为真正的数组(
Set, Map , Generator
)
- 用法
Array.from()
,将两类对象转为真正的数据:类数组
,以及可遍历对象(包括Map以及Set数据类型)
let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; // ES5的写法 var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c'] // ES6的写法 let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
Array.of()
将一组值,转换为数组Array.of() // [] Array.of(undefined) // [undefined] Array.of(1) // [1] Array.of(1, 2) // [1, 2]
copyWithin
数组的实例方法 ,当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组Array.prototype.copyWithin(target, start = 0, end = this.length) target(必需):从该位置开始替换数据。如果为负值,表示倒数。 start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示从末尾开始计算。 end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示从末尾开始计算。 [1, 2, 3, 4, 5].copyWithin(0, 3) // 将该数组的从索引3开始的数据到最后的数据,复制到索引0开始的位置
find
找出第一个符合条件的数组成员,参数是一个函数。返回符合这个函数的第一个成员,没有的话返回undefined[1, 4, -5, 10].find((n) => n < 0)
findIndex
与上一个方法类似,不过返回值是找到的成员的索引,如果没有的话就返回-1[1, 5, 10, 15].findIndex(function(value, index, arr) { return value > 9; }) // 2
fill
使用给定值,填充一个数组new Array.fill('填充的数据','开始位置','结束位置') ['a', 'b', 'c'].fill(7) // [7, 7, 7] ['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c'] // 如果开始位置,结束位置都没有的话 就从开始到结束 // 如果开始位置有,结束位置没有的话也是从开始到结束
entries(),keys() 和 values()
for (let index of ['a', 'b'].keys()) { console.log(index); } // 0 // 1 for (let elem of ['a', 'b'].values()) { console.log(elem); } // 'a' // 'b' for (let [index, elem] of ['a', 'b'].entries()) { console.log(index, elem); } // 0 "a" // 1 "b" // 如果不使用for...of循环,可以手动调用遍历器对象的next方法,进行遍历。 let letter = ['a', 'b', 'c']; let entries = letter.entries(); console.log(entries.next().value); // [0, 'a'] console.log(entries.next().value); // [1, 'b'] console.log(entries.next().value); // [2, 'c']
includes
表示数组中是否包含给定的值,与字符串中的includes相似,返回值为true,falseincludes('查找的值','开始位置') // 该方法的第二个参数表示搜索的起始位置,默认为0。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为-4,但数组长度为3),则会重置为从0开始。
flat
将嵌套的数组“拉平flatMap
方法对原数组的每个成员执行一个函数(相当于执行Array.prototype.map()),然后对返回值组成的数组执行flat()方法// flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1。 [1, 2, [3, [4, 5]]].flat() // [1, 2, 3, [4, 5]] [1, 2, [3, [4, 5]]].flat(2) // [1, 2, 3, 4, 5] // 相当于 [[2, 4], [3, 6], [4, 8]].flat() [2, 3, 4].flatMap((x) => [x, x * 2]) // [2, 4, 3, 6, 4, 8]
at
接受一个整数作为参数,返回对应位置的成员,支持负索引,参数超过范围的话默认返回值为undefinedconst arr = [5, 12, 8, 130, 44]; arr.at(2) // 8 arr.at(-2) // 130 // 参数位置超出了数组范围,at()返回undefined。
对象的扩展
- ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
const foo = 'bar'; const baz = {foo}; baz // {foo: "bar"} // 等同于 const baz = {foo: foo};
- 对象中的属性名可以使用表达式
let lastWord = 'last word'; const a = { 'first word': 'hello', [lastWord]: 'world' }; a['first word'] // "hello" a[lastWord] // "world" a['last word'] // "world"
- 方法的
name
属性 (方法的name属性返回函数名) - super 关键字
我们知道,this关键字总是指向函数所在的当前对象,ES6 又新增了另一个类似的关键字super,指向当前对象的原型对象。
- 对象的扩展运算符(与数组的扩展运算符一致,ES2018将这个运算符引入到了对象)
对象的新增方法
Object.is
比较两个值是否相同,注意 -0 和 0 比较式不相同的Object.is(120,120) // true Object.is(NaN,NaN) // true
Object.assign(target,source)
方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)- 如果只有一个参数,Object.assign()会直接返回该参数。
const obj = {a: 1}; Object.assign(obj) === obj // true
- 如果该参数不是对象,则会先转成对象,然后返回。
typeof Object.assign(2) // "object"
- 由于
undefined
和null
无法转成对象,所以如果它们作为参数,就会报错。 - Object.assign()拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)。
const target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3} Object.assign()方法的第一个参数是目标对象,后面的参数都是源对象。 注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
- 如果只有一个参数,Object.assign()会直接返回该参数。
Object.getOwnPropertyDescriptors
返回指定对象所有自身属性(非继承属性)的描述对象。const obj = { foo: 123, get bar() { return 'abc' } }; Object.getOwnPropertyDescriptors(obj) // { foo: // { value: 123, // writable: true, // enumerable: true, // configurable: true }, // bar: // { get: [Function: get bar], // set: undefined, // enumerable: true, // configurable: true } }
Object.setPrototypeOf
与 __proto__相同,用来设置一个对象的原型对象// 使用方式 Object.setPrototypeOf(object, prototype) let proto = {}; let obj = { x: 10 }; Object.setPrototypeOf(obj, proto); proto.y = 20; proto.z = 40;
Object.getPrototypeOf
该方法与Object.setPrototypeOf
方法配套,用于读取一个对象的原型对象。Object.getPrototypeOf(obj);
Object.keys(),
返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。var obj = { foo: 'bar', baz: 42 }; Object.keys(obj) // ["foo", "baz"]
Object.values(),
方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值const obj = { foo: 'bar', baz: 42 }; Object.values(obj) // ["bar", 42]
Object.entries()
方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。const obj = { foo: 'bar', baz: 42 }; Object.entries(obj) // [ ["foo", "bar"], ["baz", 42] ]
Object.fromEntries
Object.fromEntries()方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。Object.fromEntries([ ['foo', 'bar'], ['baz', 42] ]) // { foo: "bar", baz: 42 } // 该方法的主要目的,是将键值对的数据结构还原为对象,因此特别适合将 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 ** 2 // 4 2 ** 3 // 8
- 链判断运算符
// 如果存在一个值,需要连续判断该值的上层是否存在。这种情况下可以使用链判断运算符 const firstName = (message && message.body && message.body.user && message.body.user.firstName) || 'default'; // 上面是正常情况下判断 // 下面是链判断运算符 const firstName = message?.body?.user?.firstName || 'default'; //上面代码使用了?.运算符,直接在链式调用的时候判断,左侧的对象是否为null或undefined。如果是的,就不再往下运算,而是返回undefined。
- Null 判断运算符
??
读取对象属性的时候,如果某个属性的值是null或undefined,有时候需要为它们指定默认值。常见做法是通过||运算符指定默认值。const headerText = response.settings.headerText || 'Hello, world!'; const animationDuration = response.settings.animationDuration || 300; const showSplashScreen = response.settings.showSplashScreen || true; 上面的三行代码都通过||运算符指定默认值,但是这样写是错的。开发者的原意是,只要属性的值为null或undefined,默认值就会生效,但是属性的值如果为空字符串或false或0,默认值也会生效。 为了避免这种情况,ES2020 引入了一个新的 Null 判断运算符??。它的行为类似||,但是只有运算符左侧的值为null或undefined时,才会返回右侧的值。 const headerText = response.settings.headerText ?? 'Hello, world!'; const animationDuration = response.settings.animationDuration ?? 300; const showSplashScreen = response.settings.showSplashScreen ?? true; // 上面代码中,默认值只有在左侧属性值为null或undefined时,才会生效。 // 这个运算符的一个目的,就是跟链判断运算符?.配合使用,为null或undefined的值设置默认值。 const animationDuration = response.settings?.animationDuration ?? 300;
- 逻辑赋值运算符
// 或赋值运算符 x ||= y // 等同于 x || (x = y) // 与赋值运算符 x &&= y // 等同于 x && (x = y) // Null 赋值运算符 x ??= y // 等同于 x ?? (x = y)