ES6为JavaScript提供了新一代的标准,牵扯到各个方面,当然忘不了对原来数据类型的查缺补漏。相信看过阮一峰的ES6入门教程网站的人都知道,在ES6前几章节基本上都是各个数据类型的扩展。字符串扩展,数值扩展,正则扩展,函数扩展,数组扩展,对象扩展,运算符扩展。这简直就是把我们原来的数据类型扩展了个遍啊(幸亏null和underfined没得扩展)。
本篇文章,我们不会逐条一个个的都学习一遍,我们要学习实际项目中经常用到的,剩下ES2021新添加的啊或者平时不常用的,大家就随便去瞅瞅就行了,知道出在哪里就好。哪怕到时候真的用到了,也可以知道去那里学习。随用随学吧。
1,字符串的扩展
模板字符串
(详见请看我另一篇文章:ES6学习(5)-- 模板字符串)
字符串的遍历器接口
ES6 为字符串添加了遍历器接口,使得字符串可以被for...of
循环遍历。除了遍历字符串,这个遍历器最大的优点是可以识别大于0xFFFF
的码点,传统的for
循环无法识别这样的码点。
let text = String.fromCodePoint(0x20BB7);
for (let i = 0; i < text.length; i++) {
console.log(text[i]);
}
// " "
// " "
for (let i of text) {
console.log(i);
}
// "𠮷"
String.fromCodePoint()
ES6提供了String.fromCodePoint()方法去识别大于0xFFFF的字符,弥补了ES5的String.fromCharCode()方法的不足。
String.fromCodePoint(0x20BB7)
// "𠮷"
String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y'
// true
String.row()
ES6 还为原生的 String 对象,提供了一个raw()
方法。该方法返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,往往用于模板字符串的处理方法。
String.raw`Hi\n${2+3}!`
// 实际返回 "Hi\\n5!",显示的是转义后的结果 "Hi\n5!"
String.raw`Hi\\n`
// 返回 "Hi\\\\n"
String.raw`Hi\\n` === "Hi\\\\n" // true
codePointAt()
ES6 提供了codePointAt()
方法,能够正确处理 4 个字节储存的字符,返回一个字符的码点。
let s = '𠮷a';
s.codePointAt(0) // 134071
s.codePointAt(1) // 57271
s.codePointAt(2) // 97
includes() , startsWith() , endsWith()
传统上,JavaScript 只有indexOf
方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6 又提供了三种新方法。
- includes():返回布尔值,表示是否找到了参数字符串
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部
- endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部
以上三种方法都支持有第二个参数,第二个参数为number,表示开始搜索的位置。但是要注意的是:使用第二个参数n
时,endsWith
的行为与其他两个方法有所不同。它针对前n
个字符,而其他两个方法针对从第n
个位置直到字符串结束。
let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
repeat()
repeat
方法返回一个新字符串,表示将原字符串重复n
次。
// n为正整数
'na'.repeat(3) // "nanana"
// n为小数会被取整,这里的取整就是单纯的取出来整数部分
'na'.repeat(2.9) // "nana"
// n为-1到0的小数,则判定为0
'na'.repeat(-0.9) // ""
// n为负数或者Infinity,会报错。
'na'.repeat(Infinity) // RangeError
'na'.repeat(-1) // RangeError
//n是NaN等同于 0
'na'.repeat(NaN) // ""
// n是字符串,则会先转换成数字
'na'.repeat('na') // ""
'na'.repeat('3') // "nanana"
padStart() , padEnd()
ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()
用于头部补全,padEnd()
用于尾部补全。
规则:padStart()
和padEnd()
一共接受两个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串。
// 如果原字符串的长度,等于或大于最大长度,则字符串补全不生效,返回原字符串。
'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'
// 如果用来补全的字符串与原字符串,两者的长度之和超过了最大长度,则会截去超出位数的补全字符串
'abc'.padStart(10, '0123456789') // '0123456abc'
'abc'.padEnd(10, '0123456789') // "abc0123456"
// 如果省略第二个参数,默认使用空格补全长度
'x'.padStart(4) // ' x'
'x'.padEnd(4) // 'x '
replaceAll()
原来的replace()方法只能替换第一个匹配到的子字符串,如果想要替换所有,就需要使用正则作为搜索对象并添加全局的 “ g ” 属性。为了简化此操作,ES2021 引入了replaceAll()
方法,可以一次性替换所有匹配。
规则:它的用法与replace()
相同,返回一个新字符串,不会改变原字符串。
'aabbcc'.replaceAll('b', '_') // 'aa__cc'
// replaceAll()的第二个参数replacement是一个字符串,表示替换的文本,其中可以使用一些特殊字符串。
// $&:匹配的字符串。
// $` :匹配结果前面的文本。
// $':匹配结果后面的文本。
// $n:匹配成功的第n组内容,n是从1开始的自然数。这个参数生效的前提是,第一个参数必须是正则表达式。
// $$:指代美元符号$。
// $& 表示匹配的字符串,即`b`本身
// 所以返回结果与原字符串一致
'abbc'.replaceAll('b', '$&')
// 'abbc'
// $` 表示匹配结果之前的字符串
// 对于第一个`b`,$` 指代`a`
// 对于第二个`b`,$` 指代`ab`
'abbc'.replaceAll('b', '$`')
// 'aaabc'
// $' 表示匹配结果之后的字符串
// 对于第一个`b`,$' 指代`bc`
// 对于第二个`b`,$' 指代`c`
'abbc'.replaceAll('b', `$'`)
// 'abccc'
// $1 表示正则表达式的第一个组匹配,指代`ab`
// $2 表示正则表达式的第二个组匹配,指代`bc`
'abbc'.replaceAll(/(ab)(bc)/g, '$2$1')
// 'bcab'
// $$ 指代 $
'abc'.replaceAll('b', '$$')
// 'a$c'
// replaceAll()的第二个参数replacement除了为字符串,也可以是一个函数,该函数的返回值将替换掉第一个参数searchValue匹配的文本。
'aabbcc'.replaceAll('b', () => '_') // 'aa__cc'
2,正则的扩展
RegExp 构造函数
RegExp
构造函数第一个参数是一个正则对象,那么可以使用第二个参数指定修饰符。而且,返回的正则表达式会忽略原有的正则表达式的修饰符,只使用新指定的修饰符。
// ES5
var regex = new RegExp(/xyz/, 'i'); // Uncaught TypeError: Cannot supply flags when constructing one RegExp from another
//ES6
new RegExp(/abc/ig, 'i').flags // "i"
RegExp.prototype.flags 属性
ES6 为正则表达式新增了flags
属性,会返回正则表达式的修饰符。
// ES5 的 source 属性
// 返回正则表达式的正文
/abc/ig.source
// "abc"
// ES6 的 flags 属性
// 返回正则表达式的修饰符
/abc/ig.flags
// 'gi'
具名组匹配
ES2018 引入了具名组匹配(Named Capture Groups),允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用。
规则:
“具名组匹配”在圆括号内部,模式的头部添加“问号 + 尖括号 + 组名”(?<year>
),然后就可以在exec
方法返回结果的groups
属性上引用该组名。
具名组匹配等于为每一组匹配加上了 ID,便于描述匹配的目的。如果组的顺序变了,也不用改变匹配后的处理代码。
如果具名组没有匹配,那么对应的groups
对象属性会是undefined
。
// 原来的正则组匹配的写法
// 想要获取到每个组的值,只能用数字序号(比如matchObj[1])引用,要是组的顺序变了,引用的时候就必须修改序号。
const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj[1]; // 1999
const month = matchObj[2]; // 12
const day = matchObj[3]; // 31
// ES2018引入具名组匹配的写法
// 想要获取到某个组的值,可以使用ID,在正则返回值的groups属性上直接读取。
const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj.groups.year; // "1999"
const month = matchObj.groups.month; // "12"
const day = matchObj.groups.day; // "31"
正则匹配索引
正则匹配结果的开始位置和结束位置,目前获取并不是很方便。原来正则实例的exec()
方法,返回结果有一个index
属性,可以获取整个匹配结果的开始位置,但是如果使用了组匹配,那么每个组的开始位置就无法得到了。
如何获取组匹配的组的开始和结束位置呢?ES6提供了一个新的方案:exec()
方法的返回结果加上indices
属性,在这个属性上面可以拿到匹配的开始位置和结束位置。
const text = 'zabbcdef';
const re = /ab+(cd(ef))/;
const result = re.exec(text);
result.indices // [ [1, 8], [4, 8], [6, 8] ]
// 说明:上面例子中,正则表达式中包含了两个组匹配,所以正则返回结果的indices属性就会返回三个元素的数组。其中,第一个元素是正则整体匹配结果('abbcdef')的开始位置和结束位置。第二个元素是第一个组匹配的结果('cdef')的开始位置和结束位置。第三个元素是第二个组匹配的结果('ef')的开始位置和结束位置。
注意,
开始位置包含在匹配结果之中,但是结束位置不包含在匹配结果之中。比如,匹配结果为ab
,分别是原始字符串的第1位和第2位,那么结束位置就是第3位。
如果获取组匹配不成功,indices
属性数组的对应成员则为undefined
,indices.groups
属性对象的对应成员也是undefined
。
String.prototype.matchAll()
如果一个正则表达式在字符串里面有多个匹配,现在一般使用g
修饰符或y
修饰符,在循环里面逐一取出。ES2020增加了String.prototype.matchAll()
方法,可以一次性取出所有匹配。不过,它返回的是一个遍历器(Iterator),而不是数组。
const string = 'test1test2test3';
const regex = /t(e)(st(\d?))/g;
for (const match of string.matchAll(regex)) {
console.log(match);
}
// ["test1", "e", "st1", "1", index: 0, input: "test1test2test3"]
// ["test2", "e", "st2", "2", index: 5, input: "test1test2test3"]
// ["test3", "e", "st3", "3", index: 10, input: "test1test2test3"]
3,数值的扩展
Number.isFinite()
用来检查一个数值是否为有限的(finite),即不是Infinity
。 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
。Number.isNaN()只有对于NaN
才返回true
,非NaN
一律返回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(), Number.parseFloat()
ES6 将全局方法parseInt()
和parseFloat()
,移植到Number
对象上面,行为完全保持不变。
Number.isInteger()
Number.isInteger()
用来判断一个数值是否为整数。
Number.isInteger(25) // true
Number.isInteger(25.1) // false
Number.isInteger() // false
Number.isInteger(null) // false
Number.isInteger('15') // false
Number.isInteger(true) // false
// 特殊情况1
Number.isInteger(25) // true
Number.isInteger(25.0) // true
// 特殊情况2: 数值的精度超过 53 个二进制位,第54位及后面的位就会被丢弃
Number.isInteger(3.0000000000000002) // true
Math 对象的扩展
(1)、Math.trunc
方法 :用于去除一个数的小数部分,返回整数部分。
Math.trunc(4.1) // 4
Math.trunc(-4.1) // -4
// 对于非数值,Math.trunc内部使用Number方法将其先转为数值。
Math.trunc('123.456') // 123
Math.trunc(true) //1
Math.trunc(false) // 0
Math.trunc(null) // 0
// 对于空值和无法截取整数的值,返回NaN
Math.trunc(NaN); // NaN
Math.trunc('foo'); // NaN
Math.trunc(); // NaN
Math.trunc(undefined) // NaN
(2)、Math.sign
方法:用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。
// 参数为负数,返回-1;
Math.sign(-5) // -1
// 参数为正数,返回+1;
Math.sign(5) // +1
// 参数为 0,返回0;
Math.sign(0) // +0
// 参数为-0,返回-0;
Math.sign(-0) // -0
// 其他值,返回NaN。
Math.sign(NaN) // NaN
//如果参数是非数值,会自动转为数值。对于那些无法转为数值的值,会返回NaN。
Math.sign('') // 0
Math.sign(true) // +1
Math.sign(false) // 0
Math.sign(null) // 0
Math.sign('9') // +1
Math.sign('foo') // NaN
Math.sign() // NaN
Math.sign(undefined) // NaN
到此为止!!!
各数据类型扩展的汇总(1)就结束了!!
东西很多,也比较杂乱,本篇文章中的都是我从原文中摘取出来的常见,常用,或者说有机会用到的 “ 芝士点 ”。大家可以浏览的看一遍,也不用死记硬背,知道在那里就好了,以后有用到了,再回来瞅瞅。
拜了个拜!迪迦。。。