引入
系统学习ES6各种特性,了解背后的原理。
笔记
1.字符串的扩展
1.1 Unicode表示法
JavaScript允许使用\uxxxx形式表示一个字符,但此方式仅限于\u0000~\uFFFF之间的字符。
如使用\u20BB7则会被视为\u20BB+'7',所以部分汉字需要两个字符(4个字节)才能表示
在ES6中可以使用\u{16进制数值}表示汉字,如\u{20BB7}解释为"𠮷"
1.2 codePointAt()
用4个字节表示的一个汉字在使用时会遇到长度问题。
let s = "𠮷"; //注意不是吉祥的吉,是\u{20BB7} 或者0xD842 0xDFB7 十进制为 55362 57271
s.length; // 2
s.charAt(0); // ' '
s.charAt(1); // ' '
s.charCodeAt(0); // 55362
s.charCodeAt(1); // 57271
ES6中提供了codePointAt()方法,能够正确处理4字节长度字符和2字节字符
(可以用来判断字符是否为4字节 或者说 32Bit)
但是,传入的参数依然是2字节字符所在的位置
let s = "𠮷a"
s.codePointAt(0); // 134071 𠮷对应的值
s.codePointAt(1); // 57271 𠮷后2字节对应的值
s.codePointAt(2); // 97 a对应的值
对于含有4字节字符的字符串,可以使用for...of遍历,能正确识别4字节字符
而传统的for循环无法识别4字节字符
1.3 fromCodePoint()
原来的String.fromCharCode()也不能识别32位数值,超出16位的部分会溢出而舍去
使用String.fromCodePoint()可以识别
String.fromCodePoint(0x20BB7); // '𠮷'
String.fromCharCode(0x20BB7); // 'ஷ'
1.4 includes()、startsWith()、endsWith()
传统上只有indexOf()方法能用来确定字符串是否包含于另一个字符串(返回bool)
ES6提供了新的方法(返回bool):
includes()、startsWith()、endsWith()
方法用途顾名思义,而且都有两个参数:字符串、开始搜索的位置
(endsWith中表示在前n个字符中搜索,其他两个表示从第n个字符之后开始搜索)
1.5 repeat()
返回字符串重复n次后的新字符串
"123".repeat(2.9); // "123123" 对于小数会取整数部分、负数则会报错
"123".repeat(-0.1); // "" 0则为空
"123".repeat("2"); // "123123" 字符串会被转为数字
1.6 padStart()、padEnd()
用于补全字符串长度,分为头部补全和尾部补全
"x".padStart(5, "ab"); //"ababx"
"xxx".padEnd(2, "ab"); // "xxx" 原字符串超过要补全到的长度时,返回原字符串
"xxx".padStart(10, "0123456789"); // "0123456xxx" 补全字符串过长时会截掉超出部分
//省略第二个参数时用空格补全
1.7 模板字符串
ES6中引入了模板字符串: 用反引号`来包围字符串
可以实现字符串中嵌入变量(使用${}包裹表达式来嵌入)、定义多行文本字符串
let word = "稀土掘金";
console.log(`!!!
juejin.cn: ${word}
!!!`)
/*
!!!
juejin.cn: 稀土掘金
!!!
*/
2.正则的扩展
2.1 RegExp构造函数
ES5中常用
var regex = new RegExp('xyz', 'i'); //使用字符串和模式两个参数
// 等价于
var regex = new RegExp(/xyz/i); //使用正则表达式为参数
// 等价于
var regex = /xyz/i; //最简单的构造函数
var regex = new RegExp(/xyz/, 'i'); //报错,ES5中不允许混合使用
但ES6中若使用了第二参数会覆盖第一个参数正则表达式的模式
new RegExp(/abc/ig, 'i').flags; // 'i'
2.2 正则的使用方法
字符串对象中共有4个方法可以使用正则表达式:
match()replace()search()split()
2.3 u修饰符
ES6为了解决4字节字符匹配的问题,增加了u修饰符,意为“Unicode模式”
同时正则表达式中的.在u模式下才会匹配4字节字符
使用ES6规则\u{}表示字符的正则表达式中,必须使用u模式才能正确转化为字符
3. 数值的扩展
3.1 二进制八进制
二进制使用0b开头,八进制使用0o开头
可以使用Number方法将二进制、八进制字符串转为十进制数值如Number('0b111')
3.2 isFinite()、isNaN()
ES6在Number对象上添加了两个方法,前者检查数值是否为有限的,后者检查是否为NaN
3.3 parseInt()、parseFloat()
用于将字符串转化为整数、浮点数
ES6将这两个全局的方法移植到了Number对象上,旨在使语言逐渐模块化
3.4 isInteger()
判断一个值是否为整数,注意js中整数和浮点数用相同的储存方式,所以3, 3.0都判断为整数
3.5 Math对象的扩展
Math.trunc():去除一个数(非数值会先Number方法转为数字)的小数部分,返回整数部分。对于无法截取的内容返回NaN。Math.sign():判断一个数值(非数值会先转换)的符号(-1,+1,+0,-0,NaN)
3.6 指数运算符
ES6新增了指数运算符(**)
2 ** 3; // 8
let a = 2;
a **= 3;
a; // 8
4.函数的扩展
4.1 函数参数的默认值
ES5中不能直接为函数设置默认值,只能用变通的方式
ES6中允许为函数设置默认值
function add(x=1,y=1){return x+y};
add(3); //4
- 参数变量是默认声明的,注意不能再次使用
let或const声明 - 若需要使用默认参数时,每次使用都会重新计算表达式赋值(惰性求值)
- 默认参数需要为尾参数,否则无法使用其默认值(除非显示地传入
undefined) - 函数的
length属性表示函数预期传入多少个参数 = 总参数的数量 - 默认参数的数量 - 函数默认值会在调用函数时形成一个作用域(在为默认参数赋值时的参数之间有一个作用域)
- 可以设置默认参数默认值为
undefined表示这个参数可以省略
4.2 rest参数
ES6中引入了函数的rest参数,形式为...变量名
可以将传入的一个或多个参数接收为一个数组
rest参数只能作为最后一个参数
function sum(...values){
let res = 0;
for (let v of values){
res+=v;
}
return res
}
4.3 name属性
函数有name属性
对于有具体函数名的变量,name属性返回具体的函数名
对于匿名函数,ES5中返回'',ES6中返回变量名
Function构造函数返回的函数实例,name属性为"anonymous"
bind返回的函数,name属性会带上bound前缀
4.4 箭头函数
ES6规定可以使用=>定义函数
但是注意几个地方:
- 箭头函数体内的
this对象就是定义时所在的对象,而不是使用时所在的对象
这说明箭头函数中的this在定义时就被固定了,不会像function内一样发生改变。
这种特性非常有利于封装回调函数。
而且箭头函数没有自己的this,会默认绑定最外层的this
const obj = {
a: function() { console.log(this) },
b: {
c: () => {console.log(this)},
d: function() { console.log(this) }
}
}
obj.a() //function函数打出的是obj
obj.b.c() //浏览器中箭头函数打出的是window对象
obj.b.d() //function函数打出的是obj.b
- 箭头函数不能当做构造函数(即不可以使用new命令)
- 不可以使用
arguments对象(函数体内不存在该对象),可以用rest参数代替 - 不可以使用
yield命令,因此不能用作Generator函数
let f = () => 5;
f = x => x+1; //单个参数时括号可以省略
f = (x,y)=>x+y; // 单个语句时 {}和return可以省略
f = (x,y)=>{ // 不省略的情况
return x+y;
}
f = ()=> ({x:1,y:2}); // 直接返回对象时,为了避免和代码块混淆,外部加上圆括号
let valsToArr = (...vals)=>vals; //使用rest参数,注意要加括号
箭头函数的嵌套
箭头函数内还可以再使用箭头函数
let insert = val=> ({into: arr=> ({after: afterVal=>{
// 可以使用嵌套过程中传入的变量
arr.splice(arr.indexOf(afterVal)+1, 0, val); //在afterVal之后插入val
return arr;
}})});
insert(2).into([1,3]).after(2); //[1,2,3]
部署管道机制(前一个函数的输出为后一个函数的输入)
const pipeline = (...funcs)=> val=> funcs.reduce((a,b)=>b(a),val); //返回函数组成的流水线
const plus1 = a=>a+1;
const mult2 = a=>2*a;
const addThenMult = pipeline(plus1, mult2);
addThenMult(5); //12