ES6,你可能不知道的知识点和原理

1.spread/rest

运算符...通常被称为spread或者rest(展开或收集运算符)。可以将数组(实际上是任何iterable)展开成独立的值

它还有另一种可以看成反向的行为,把一系列值收集到一起成为数组

scss 复制代码
function foo(x,...z){
    console.log(x,z)
}
foo(1,2,3,4,5) //1 2 [3,4,5]

...z基本上就是在说:将剩下的参数(除了命名参数x)收集到一起组成一个名为z的数组。如果没有命名参数,自然就会收集所有的参数。

他最好的一点是弃用了arguments类数组,因为下面的args就是一个真正的数组

scss 复制代码
function foo(...args){
    args.shift()
}
function foo(...vals=[1,2,3]){}这是很诱人但是是不合法的

2.默认值表达式

函数默认值可以不只是31这样的简单值,他们可以是任意合法表达式,甚至是函数调用

scss 复制代码
function bar(val){
    console.log('bar called');
    return y + val
}

function foo(x = y + 3,z = bar(x)){
    console.log(x,z);
}

var y = 5
foo() //'bar calles'
    //8 13
foo(10) //'bar calles'
    //10,15
y = 6
foo(undefined,10) //9,10

可以看到,默认值表达式是惰性求值,这意味着他们只在需要的时候运行--也就是是在参数省略或者为undefined的时候运行。

这里有一个微妙的细节,函数声明中参数是在他们自己的作用域中的,即foo()括号里面作用域,而不是在函数体作用域。这意味着默认值表达式中的标识符首先匹配到形式参数作用域,再到外层作用域(不会到函数体作用域中寻找)

ini 复制代码
var w = 1,z = 2
function foo(x = w + 1,y = x + 1,z = z + 1){
    console.log(x,y,z);
}

foo()

这段代码中,首先对参数进行rhs查询,w+1表达式会先在形式参数作用域寻找w,没有找到,因为在外层作用域中找到w。x+1会在形式参数作用域中找到x,而这里x已经被初始化了,因此对y的赋值工作可以正常运行。但是,z+1中的z会发现这是一个没有被初始化的参数变量,所以他永远不会从外层作用域中寻找z。在ES6中引入了TDZ,变量在未初始化的状态下访问会抛出TDZReferenceError报错。

3.解构与对象属性赋值模式

对于对象解构赋值有一个很巧妙但是极其重要的细节需要理解

ini 复制代码
var x = 10,y = 20
var o = {a:x,b:y}
console.log(o.a,o.b); //10 20

在{a:x,b:y}中,我们知道a是对象属性,而x是要赋给他的值。换句话说,这是target:souce。

但在解构中这是相反的,解构的语法模式是souce:target

javascript 复制代码
var aa = 10,bb = 20
var o = {x:aa,y:bb}
var {x:AA,y:BB} = o
console.log(AA,BB);//10 20
console.log(x,y); //ReferenceError

同时,解构可以捕获子对象/类的值本身

css 复制代码
({a:x,a:y,a:[z]}) = {a:[1]} //解构的时候不用var或者let、const声明的话要用括号包起来

x.push(2)
y[0] = 10

x //[10,2]
y //[10,2]
z //1

很明显,解构实际上是浅拷贝,x和y指向同一个对象的地址

解构赋值表达式 对象或者数组解构的赋值表达式的完成值是所有右侧对象/数组的值

less 复制代码
var o = {a:1,b:2,c:3}
var a,b,c,p
p = {a,b,c} = o //实际上相当于p = o
a //1
b //2
c //3
p === o //ture

通过持有对象/数组的值作为完成值,可以将解构赋值表达式组成链

css 复制代码
let o = {a:1,b:2,c:3}
({a} = {b,c} = o)

4.对象字面量扩展

在ES6中,,关联到对象字面量属性上的函数也有简洁的方法

老方法

css 复制代码
var o = {
    x:function(){},
    y:function(){}
}

在ES6中可以

javascript 复制代码
var o = {
    x(){},
    y(){}
}

//实际上代码是
var o = {
    x:function(){},
    y:function(){}
}

可以看出来,简洁的代码实际上是一个匿名函数,这里的一个小小区别是:x:function(){}中的x只是对象的一个属性名称,是函数的标识符,可以通过o.x来调用函数,但是实际上这个函数是匿名函数,因此无法在这个函数内部使用递归或者事件绑定

5.标签模板字面量

typescript 复制代码
function foo(string,...value) {
    console.log(string);
    console.log(value);
}

let a = 'hello'
foo`${a} world!` //['', ' world!'] 
                //[ 'hello' ]

从本质上来说,这是一类不需要()的特殊函数调用。标签部分,即foo这部分,是一个要调用的函数值,他可以是任意结果为函数的表达式,甚至可以是一个结果为另一个函数的函数调用。

第一个参数名为string,是一个由所有普通字符串(插入表达式之间的部分)组成的数组,空格也算在内。

为了方便起见,第二个参数我们也收集成数组,value数组的参数是已经求值的在字符串字面值插入表达式的结果

6.原始字符串

在前面的代码中,标签函数的第一个参数还包括一些额外数据:所有字符串的原始未处理版本

typescript 复制代码
function foo(string,...value) {
    console.log(string);
    console.log(string.raw);
}
foo`hello\nworld`
//[ 'hello
//world' ]
//[ 'hello\nworld' ]

即原始版本可以理解为保留了原始的转义码\n,而处理过的版本将它当做是一个单独的换行符

相关推荐
王解40 分钟前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
老码沉思录40 分钟前
写给初学者的React Native 全栈开发实战班
javascript·react native·react.js
我不当帕鲁谁当帕鲁44 分钟前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂1 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
毋若成4 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽4 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新5 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html
秦jh_6 小时前
【Linux】多线程(概念,控制)
linux·运维·前端
蜗牛快跑2136 小时前
面向对象编程 vs 函数式编程
前端·函数式编程·面向对象编程