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

相关推荐
daols88几秒前
vxe-table 自定义数字行主键,解决默认字符串主键与后端类型不匹配问题
前端·javascript·vue.js·vxe-table
啥都不懂的小小白几秒前
Vue 小白入门|Pinia 核心用法全解
javascript·vue.js·ecmascript
skywalk81633 分钟前
g4f提供的模型调用:python JavaScript和curl
前端·javascript·vue.js·g4f
R-sz10 分钟前
前端直接将页面 HTML 报表导出为 Word 文档,html转word
前端·html·word
恋恋风尘hhh10 分钟前
Web 前端安全机制分析:以瑞数(RisShu)为例
前端·安全
未名编程22 分钟前
React Native WebView 加载远程页面显示错误内容的深层原因及解决方案
javascript·react native·react.js
yzpyzp25 分钟前
可以不用React或者Vue这些前端框架,直接用javascript写项目吗
javascript·react.js·前端框架
freewlt26 分钟前
前端安全新范式:2026年防护实战
前端·安全
包子源27 分钟前
React-PDF 详解:API 要点与在线简历项目中的落地
前端·react.js·pdf
Bigger32 分钟前
第九章:我是如何剖析 Claude Code 的 CLI 里的安全沙盒与指令拦截机制的
前端·claude·源码阅读