一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第28天,点击查看活动详情。
ES6新特性③
rest参数
ES6引入rest参数,用户获取函数的实参,用来代替arguments
1. 先来看看ES5获取实参列表的方式
function date() {
console.log(arguments);
}
date('A', 'B', 'C');
Arguments(3),arguments接收完是以伪数组形式保存的,不能用数组有关的方法
2. ES6的rest参数
格式: ...标识符
这个rest参数接收完实参是以数组形式保存的
也就是说rest参数可以使用filter、some、every、map等数组方法
function fn(...args) {
console.log(args);
}
fn('A','B','C');
3. rest参数必须要放到参数最后
很简单,如果不把rest参数放最后,那么在rest参数后面的参数都失效啦
function fn2(a, b, ...abc) {
console.log(a);
console.log(b);
console.log(abc);
}
fn2(1, 2, 3, 4, 5, 6); // 1,2 Array(4)
spread扩展运算符
... 是扩展运算符, 它能将 数组 转换为逗号分割的 参数序列
声明一个数组
const tfboys = ['易烊千玺', '王源', '王俊凯'];
声明一个函数
function fn() {
console.log(arguments);
}
fn(tfboys);
fn(...tfboys);
当tfboys整体做为一个数组传入时,arguments的长度为1
利用扩展运算符将tfboys这个数组,转换为了'易烊千玺', '王源', '王俊凯'这样一个参数序列,等同于fn('易烊千玺', '王源', '王俊凯'); arguments的长度为3
扩展运算符运用
1.将伪数组转为真正的数组
const divs = document.querySelectorAll('div');
console.log(divs); // NodeList(3)
const divArr = [...divs];
console.log(divArr); // [div,div,div]
这里能也能把伪数组arguments转换成数组,但是呢,因为rest参数的存在,就没必要对它动手了
2.数组的克隆
const dzq = ['G', 'E', 'M'];
const jyz = [...dzq];
console.log(jyz); // ['G', 'E', 'M']
这个拷贝是浅拷贝,如果拷贝对象中有引用类型的数据,那么只会拷贝引用数据的值,也就是地址,不会拷贝对象
3.数组的合并
const arr1 = ['AA', 'BB'];
const arr2 = ['CC', 'DD'];
以前合并数组我们是这么写的:
const arr3 = arr1.concat(arr2);
现在可以这么写:
const arr4 = [...arr1, ...arr2];
console.log(arr4); // ['AA', 'BB','CC', 'DD']
Symbol的基本使用
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。
(string,number,boolean,undefined,null,object,Symbol)
Symbol特点:
- Symbol的值是唯一的,用来解决命名冲突问题
- Symbol的值不能与其他数据进行运算
- Symbol定义的对象属性不能使用 for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
Symbol 值通过Symbol()函数生成。
这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。
凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。也就是说,由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。
//创建Symbol
let s = Symbol();
console.log(s, typeof s); // Symbol(),'symbol'
let s2 = Symbol('ONE PIECE');
let s3 = Symbol('ONE PIECE');
Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
console.log(s2 === s3); // false
注意,Symbol函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的
//Symbol.for创建
let s4 = Symbol.for('ONE PIECE');
let s5 = Symbol.for('ONE PIECE');
console.log(s4 === s5); //true
//不能与其他数据类型运算
// let result = s + 100; //报错
// let result = s > 100; //报错
// let result = s + s; //报错
Symbol创建对象属性
Symbol的其中一个使用场景就是给 对象中添加方法 up、down
let game = {
name: '合金弹头',
fn1: function () {},
fn2: function () {}
};
game.fn1 = function () {}
我们感觉好像可以这么给对象里面添加方法,但是会有一定的风险,因为你不知道对象里边到底有没有这个方法fn1,想快速完成这事还是有点麻烦,如果对象的结构简单,我们很快就能找出来,如果结构复杂,可能要花很长时间,才能决定下一步该怎么命名
所以我们就能借助Symbol来完成这种事情,就变得非常简单高效且安全
//声明一个对象
let methods = {
fn1: Symbol(),
fn2: Symbol()
};
game[methods.fn1] = function () {
console.log("射击");
}
game[methods.fn2] = function () {
console.log("蹲下");
}
//原本我就有fn1方法和fn2方法,利用上面那种方式,又安全地向里面加了两个方法
console.log(game);
一些注意事项
注意,Symbol 值作为对象属性名时,不能用点运算符。
const mySymbol = Symbol();
const a = {};
a.mySymbol = 'Hello!';
a[mySymbol] // undefined
a['mySymbol'] // "Hello!"
上面代码中,因为点运算符后面总是字符串,所以不会读取mySymbol作为标识名所指代的那个值,导致a的属性名实际上是一个字符串,而不是一个 Symbol 值。
👉 同理,在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。👈
let s = Symbol();
let obj = {
[s]: function (arg) { ... }
};
obj[s](123);
上面代码中,如果s不放在方括号中,该属性的键名就是字符串s,而不是s所代表的那个 Symbol 值。
采用ES6的对象写法,上面代码的obj对象可以写得更简洁一些
let obj = {
[s](arg) { ... }
};