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的字符.
---1
{}的引入, 让码点大于\uFFFF的字符能被正确表示.
code
str.charPointAt(index)String.fromCodePoint(unicode)能正确的操作大于\uFFFF码点的字符.

字符串遍历器接口

for ...of循环遍历, 相较传统的for循环, 能识别码点大于\uFFFF的字符.
forof

几个扩展的方法

  • normalize(): 将字符的不同表示方法统一为同样的形式, Unicode正规化.
  • includes(): 是否找到了参数字符串
  • startsWith(): 是否以参数字符串开头
  • endsWith(): 是否以参数字符串结尾
  • repeat(): 将源字符串重复n次后返回
  • padStart(): 用参数补全字符串开头到指定长度
  • padEnd(): 用参数补全字符串结尾到指定长度
  • String.raw``:转义模板字符串中的\, 并把所有变量替换为运算结果
    method

正则扩展

regexp
new RegExp(/xyz/, 'i')是ES6新加的正则构造函数的参数书写情况. 字符串的正则方法match() replace() search() split()在ES6中, 在语言内部全部调用RegExp的实例方法, 从而把与正则相关的方法都定义在RegExp对象上.

u修饰符和y修饰符

regexpu
u修饰符用来正确处理大于\uFFFF的Unicode字符. 使用了u修饰符, .点字符\S等预定义模式行为将改变. u也能区分{}所表示的Unicode码或量词. 有一些非规范的字符表示方法也需要加u修饰符来是吧.

regexpsticky
y修饰符表示粘连,它和g一样是全局匹配, 但是它隐含了头部匹配的标志^. 每一次的匹配都会从头部开始, 对于不能保证头部开始的匹配都会返回null.

添加的属性

stickyflags

数值扩展

Number方法扩展

number
数值增加了二进制八进制的表示方法, 是否为有限值的判定方法, 是否为NaN值的判定方法, 字符串parse为数值的方法移植, 是否为整数的判定方法, 极小常量EPSILON的增加, 是否为安全整数的判断方法.

Math对象扩展

math_1
Math.trunc()去除数的小数点部分, Math.sign()判断数正负零, Math.cbrt()计算数的立方根, Math.clz32()整数的32位二进制形式, Math.imul()两个32位带符号整数相乘.

Math_2
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对象.

----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);
}

在严格模式下, 只保留内层函数的调用帧的尾调用优化.

数组扩展

扩展运算符

arrayspread

值得注意的是, 扩展运算可以正确的识别32位的Unicode字符, 而且实现了Iterator接口对象, 可以把类数组转化为真正的数组.

Array.from()与Array.of()

arrayfromof

Array.from()可以把所有有length的类数组转换为真正的数组, Array.of()可以把一组值转化为数组.

实例方法copyWithin(),find(),findIndex(),fill(),entries(),keys(),values(),includes()

arraymethod

对象扩展

增强的对象字面量

对象字面量扩展了以下部分,支持设置构造函数的原型链,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属性

function-name

存(setter)取(getter)函数的name属性是在该方法的属性的描述对象的getset属性上的.

Object.is()

is

Object.is()的行为和严格相等===运算符行为基本一致,除了+-0NaN.

Object.assign()

object.assign

Object.assign用于把源对象的可枚举非继承来的自身属性浅拷贝到目标对象. 同名属性会被后面的属性覆盖. 如果只有一个参数,该方法会直接返回该参数, 如果该参数不是对象会转成对象再返回. undefinednull不能出现在target的位置. 在源对象位置, 参数也会先转化为对象, 不能完成转换时, 复制的时候会被跳过, 字符串会以数组的形式拷贝入目标对象.

assign-str-arr

str的值是有拷贝进入的,但是被随之而来的arr的值覆盖了.

枚举和遍历

enumerable

目前有四个操作会忽略enumerablefalse的属性. for...in循环, Object.keys(), JSON.stringify(), Object.assign().

遍历对象属性的5种方式:

--

对象方法扩展

Object.setPrototypeOf()和Object.getPrototypeOf()

setPrototype

Object.keys(), Object.values(), Object.entries()

object-methods

对象的扩展运算符

-----

扩展运算符....

Null传导运算符

//只是一个提案
let demo = {name: "demo", getName() {return this.name}};
demo?.name