ES6特性 字符串,正则,数值,函数,数组,对象的扩展
字符串扩展
模板字符串
模板字符串提供了结构化字符串的语法糖。这和Perl,Python等语言的字符串插值相似。允许添加一个可选的标签来初始化字符串结构,但是要避免注入攻击,也要避免插入高级的数据结构。
//创建字符串模板最基本的语法结构
`In JavaScript '\n' is a line-feed.`
//多行字符串
`In JavaScript this is
not legal.`
//字符串插值
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
//构造一个HTTP请求前缀就常常需要插入替换变量组合的模式
POST`http://foo.org/bar?a=${a}&b=${b}
Content-Type: application/json
X-Credentials: ${credentials}
{"foo": ${foo},
"bar": ${bar}}`(myOnReadyStateChangeHandler);
unicode表示法相关扩展
这方面的扩展主要是针对需要用两个双字节表示的字符, unicode码大于\uFFFF
的字符.
{}
的引入, 让码点大于\uFFFF
的字符能被正确表示.
str.charPointAt(index)
和String.fromCodePoint(unicode)
能正确的操作大于\uFFFF
码点的字符.
字符串遍历器接口
for ...of
循环遍历, 相较传统的for循环, 能识别码点大于\uFFFF
的字符.
几个扩展的方法
- normalize(): 将字符的不同表示方法统一为同样的形式, Unicode正规化.
- includes(): 是否找到了参数字符串
- startsWith(): 是否以参数字符串开头
- endsWith(): 是否以参数字符串结尾
- repeat(): 将源字符串重复n次后返回
- padStart(): 用参数补全字符串开头到指定长度
- padEnd(): 用参数补全字符串结尾到指定长度
- String.raw``:转义模板字符串中的
\
, 并把所有变量替换为运算结果
正则扩展
new RegExp(/xyz/, 'i')
是ES6新加的正则构造函数的参数书写情况. 字符串的正则方法match()
replace()
search()
split()
在ES6中, 在语言内部全部调用RegExp
的实例方法, 从而把与正则相关的方法都定义在RegExp
对象上.
u修饰符和y修饰符
u
修饰符用来正确处理大于\uFFFF
的Unicode字符. 使用了u
修饰符, .
点字符\S
等预定义模式行为将改变. u
也能区分{}
所表示的Unicode码或量词. 有一些非规范的字符表示方法也需要加u
修饰符来是吧.
y
修饰符表示粘连,它和g
一样是全局匹配, 但是它隐含了头部匹配的标志^
. 每一次的匹配都会从头部开始, 对于不能保证头部开始的匹配都会返回null
.
添加的属性
数值扩展
Number方法扩展
数值增加了二进制八进制的表示方法, 是否为有限值的判定方法, 是否为NaN
值的判定方法, 字符串parse为数值的方法移植, 是否为整数的判定方法, 极小常量EPSILON
的增加, 是否为安全整数的判断方法.
Math对象扩展
Math.trunc()
去除数的小数点部分, Math.sign()
判断数正负零, Math.cbrt()
计算数的立方根, Math.clz32()
整数的32位二进制形式, Math.imul()
两个32位带符号整数相乘.
Math.fround()
返回一个数的单精度浮点数形式, Math.hypot()
方法返回所有参数的平方和的平方根, 对数方法, 双曲函数方法, **
指数运算符.
函数扩展
引子 箭头函数
箭头函数是一个函数的缩写,使用=>
语法. 这在语法上同C#, Java8和CoffeeScript相关语法相似. 他们都支持代码块和表达式作为函数主体, 同时把表达式的值作为函数的返回值. 和普通函数不同的是, 箭头函数的this指向它定义生效时所在的作用域的this.
//表达式函数体
let odds = evens.map(v => v + 1);
let nums = evens.map((v, i) => v + i);
let pairs = evens.map(v => (even: v, odd: v + 1));
//this词法
let bob = {
_name: "vilic",
_friends: ["emi"],
printFriends() {
this._friends.forEach(f => console.log(this._name + " knows " + f))
}
}
如果箭头函数中只有一个作为返回值的表达式,并且是对象时, 需要在对象外加括号() => ({x: 0, y: 0})
.
后续可能可以通过::
语法绑定箭头函数的this对象.
函数参数扩展
let p = 2;
function Point(x = 0, y = p + 2) {
this.x = x;
this.y = y;
}
let p = new Point();
//p = {x: 0, y: 4}
参数默认值不是传值,每次都会重新计算默认值表达式. 有默认值的参数务必写在尾部, 没有默认值参数的后面.
对于函数的length属性, 第一个有默认值的参数及其后的所有参数都不会计入length属性个数中, 函数参数默认值会使length属性失真.
函数设置了默认参数, 会在函数声明的初始化阶段形成一个临时的作用域,初始化结束时这个作用域会消失.
和解构结合使用:
function fetch (url, {body = '', method = 'GET', headers = {}} = {}) {
let str = `url: ${url}
body: ${body}
method: ${method}
headers: ${headers}
`;
console.log(str);
}
fetch('https://emi.life', {body: '', method: 'POST'})
fetch('https://emi.life')
let pushNumber = (arr, ...numbers) => {
numbers.forEach(function(item) {
arr.push(item);
});
return arr;
}
let arr = [];
pushNumber(arr, 1, 2, 3);
函数参数使用...rest
语法传入多余的参数, 这样使用时可以传入任意不确定数目的参数并且存入rest
数组中. rest参数之后不能再有其他参数, 并且从rest参数不计入函数的length属性中.
只要函数参数使用了默认值, 解构赋值, 或者扩展运算符, 函数内部就不能显示的设定为严格模式.
函数参数最后一个允许有尾逗号.
name属性
let foo = function () {}
// foo.name "foo"
let bar = function baz() {}
//bar.name "baz"
(new Function).name
// "anonymous"
function demo() {}
demo.bind({}).name
//"bound demo"
(function () {}).bind({}).name
//"bound "
function qa () {}
Object.defineProperty(qa, "name", {value: "vilic"});
qa.name
//"vilic"
尾调用
function foo(x) {
//只要函数最后一步执行的操作是调用另一个函数都算
return bar(x);
}
在严格模式下, 只保留内层函数的调用帧的尾调用优化.
数组扩展
扩展运算符
值得注意的是, 扩展运算可以正确的识别32位的Unicode字符, 而且实现了Iterator接口对象, 可以把类数组转化为真正的数组.
Array.from()与Array.of()
Array.from()
可以把所有有length
的类数组转换为真正的数组, Array.of()
可以把一组值转化为数组.
实例方法copyWithin(),find(),findIndex(),fill(),entries(),keys(),values(),includes()
对象扩展
增强的对象字面量
对象字面量扩展了以下部分,支持设置构造函数的原型链,foo: foo
赋值语句简化,方法定义简化,使用超级调用,用表达式计算属性名。这些,让对象字面量和类声明更加紧密,并且让基于对象的设计得到一些相同的便利。
var obj = {
//__proto__
__proto__: theProtoObj,
//简洁写法的属性名总是字符串,即使你用了关键字也不会导致语法解析报错
//'handler: handler'简化
handler,
//方法简化
toString() {
//超级调用
return 'd' + super.toString();
},
//计算(动态)属性名
//表达式需要放在方括号内
//也可以用这种方式定义方法名
['prop' + (() => 42)()]: 42
};
属性和方法的简化写法
let name = "emi";
let demo = {
name,
age: "21",
getName: function () {console.log(this.name)},
getAge () {console.log(this.age)}
};
//这种简写模式在函数返回对象或者模块返回时用处很大
function hiThere() {
let hi = "hi";
let there = "there";
return {x, y}
}
属性名表达式
let name = "demoName";
let demo = {
//属性名表达式不能用于简写形式
[name]: "vilic",
["get" + "name"] () {console.log(demo[name])}
};
demo.name
//undifined
demo[name]; demo.demoName; demo['demoName']
//vilic
demo.getName()
//vilic
方法的name属性
存(setter
)取(getter
)函数的name
属性是在该方法的属性的描述对象的get
和set
属性上的.
Object.is()
Object.is()
的行为和严格相等===
运算符行为基本一致,除了+-0
和NaN
.
Object.assign()
Object.assign
用于把源对象的可枚举非继承来的自身属性浅拷贝到目标对象. 同名属性会被后面的属性覆盖. 如果只有一个参数,该方法会直接返回该参数, 如果该参数不是对象会转成对象再返回. undefined
和null
不能出现在target
的位置. 在源对象位置, 参数也会先转化为对象, 不能完成转换时, 复制的时候会被跳过, 字符串会以数组的形式拷贝入目标对象.
str的值是有拷贝进入的,但是被随之而来的arr的值覆盖了.
枚举和遍历
目前有四个操作会忽略enumerable
为false
的属性. for...in
循环, Object.keys()
, JSON.stringify()
, Object.assign()
.
遍历对象属性的5种方式:
对象方法扩展
Object.setPrototypeOf()和Object.getPrototypeOf()
Object.keys(), Object.values(), Object.entries()
对象的扩展运算符
扩展运算符...
.
Null传导运算符
//只是一个提案
let demo = {name: "demo", getName() {return this.name}};
demo?.name