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,而处理过的版本将它当做是一个单独的换行符

相关推荐
恋猫de小郭13 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅20 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606121 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了21 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅21 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅21 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅1 天前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment1 天前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅1 天前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊1 天前
jwt介绍
前端