前言
今天给大家介绍ES6中的对象、数组、函数(方法)新增的一些特性。废话不多说,进入正题!
1.对象
属性和函数的简洁表示法
//属性简洁表示
let name = "liusiyuan";
let age = 20;
const user = {name,age};
console.log(user);//{name:"liusiyuan",age:20}
//等同于
const user = {name:name,age:age};
//方法名简洁表示
let user2 = {
sayHi(){
return "Hello!";
}
};
console.log(user2.sayHi());//Hello!
//等同于
let uoser2 = {
sayHi:function(){
return "Hello!";
}
};
属性名表达式
let a = "say";
let b = "Hi";
let user = {
[a+b](){//可以用变量名进行拼凑
return "dashuaibi";
}
};
console.log(user.sayHi());//输出"dashuaibi"
注意点:属性简洁表示法和属性名表达式不能一起使用,否则会报错!
let sayHi = "sayHi";
let user = {
[sayHi]
};//SyntaxError: Unexpected token }
//正确用法
let a = "get";
let b = "Name";
let c = "id";
let user = {
[c]:"1",
[a+b](){
return "liusiyuan";
}
};//{id:1,getName:f[a+b]()}
扩展运算符
(…)用于取出参数对象中的所有可遍历属性拷贝(浅拷贝)到当前对象中
let object = {name:"liusiyuan"};
let object2 = {...object};
console.log(object2);//{name:"liusiyuan"}
//合并二个对象
let object = {name:"liusiyuan"};
let object2 = {age:20};
let user = {...object,...object2,weight:100};
console.log(user);//{name:"liusiyuan",age:20,weight:100}
注意点
当自定义属性和扩展运算符对象里的属性相同时(方法名相同时也是一样):当自定义属性在后面时,则覆盖掉扩展运算符对象里相同属性名的值。
let object = {name:"liusiyuan"};
let user = {...object,name:"lsy",age:20};//自定义属性在后面
console.log(user);//{name:"lsy",age:20}
自定义属性在前面,且属性名相同时,则使用扩展运算符的属性作为默认值。
let object = {name:"liusiyuan"};
let user = {name:"lsy",age:20,...object};//自定义属性在后面
console.log(user);//{name:"liusiyuan",age:20}
新方法
- assign(target,source_1,…):将源对象中所有可枚举(可访问)属性拷贝到目标对象中。
- is(value1,value2):比较两个值是否相等,和(===)基本类似。
1.1:assign()
let target = {name:"liusiyuan"};
let object = {age:20};
let object2 = {weight:100};
Object.assign(target,object,object2);//第一个参数为目标对象,后面所有的参数都为源对象。
console.log(target);//{name:"liusiyuan",age:20,weight:100}
注意点
- 当目标对象和源对象存在相同属性名(方法名)时,又或者源对象存在相同属性名时,后面的会覆盖前面的属性。
- 如果只有一个参数,那么会将参数转成对象后返回。如果为对象,那么直接返回该对象。
let target = {name:"liusiyuan"};
let object = {name:"六十元",age:20};
let object2 = {weight:100};
Object.assign(target,object,object2);
console.log(target);//{name:"六十元",age:20,weight:100}
//只有一个参数时
let a = Object.assing("3");
console.log(a);//String{"123"}
typeof(a);//"object"
null和undefined不能转化为对象,所以会报错。(不是第一个参数时,会跳过,不报错。)
//当null、undefined为目标对象时
Object.assign(null,object);
Object.assign(undefined,object);//TypeError: Cannot convert undefined or null to object
//为源对象时
Object.assign(target,null,undefined,object2);//{name:"六十元",weight:100}
Object.assign(target,null,object,object2);//{name:"六十元",age:20,weight:100}
特别需要注意的是assign方法的拷贝是浅拷贝。这一点和(…)一样。
let object = {name:"lsy"};
let object2 = {age:20};
Object.assign(object,object2);
console.log(object);//{name:"lsy",age:20}
object.age = 25;
console.log(object2);{age:20}
console.log(object);//{name:"lsy",age:20}
通过上面这段代码,大家可能还不太清楚什么是浅拷贝。那么请看下面这段代码。
let object = {name:"lsy"};
let object2 = {age:{age1:20}};
Object.assign(object,object2);
console.log(object);//{name:"lsy",age:{age1:20}}
object.age.age1 = 25;
console.log(object2);//{age:{age1:25}}
console.log(object);//{name:"lsy",age:25}
可以看见我们在object2对象age属性中又声明了一个对象,对象里有个age1的属性。在assign方法进行拷贝时,它只拷贝了一层的属性(也就是浅拷贝)。age属性中的age1属性并没有拷贝到。那么就可以认定为object中的age属性的age1属性还是object2对象中age属性的age1属性的引用地址。
通俗的讲就是**object对象中的age属性里的age1属性的引用地址还是object2对象中age1属性的引用地址。**所以当我们修改了object对象中的age1属性的值,object2对象中的age1属性值也会改变。
我们怎么解决这种问题呢?当然,有浅拷贝,就有深拷贝。下面给大家介绍一种简单粗暴的一种深拷贝方法。
let object = {name:"lsy"};
let object2 = {age:{age1:20}};
Object.assign(object,JSON.parse(JSON.stringify(object2)));
console.log(object);//{name:"lsy",age:{age1:20}}
object.age.age1 = 25;
console.log(object2);//{age:{age1:20}}
console.log(object);//{name:"lsy",age:25}
这种方法,对于正则表达式类型和函数类型等就无法进行深拷贝了。
数组的处理
Object.assign([23,32],["六十元","大帅比",666]);//["六十元","大帅比",666]
首先会将[23,32]数组转换成对象{0:23,1:32},接着将[“六十元”]也转换成对象{0:“六十元”,1:“大帅比”,2:666}。这时就出现了属性同名的情况,上面也说过,当属性同名时,后面的属性会覆盖前面的属性。所以结果为[“六十元”,“大帅比”,666]。
1.1:is():比较两个值是否相等,和(===)基本类似。
Object.is(32,32);//true
Object.is("sdf","sdf");//true
Object.is([0],[0]);//false
let object = {name:"666"};
let object2 = object;
Object.is(object,object2);//true
与===的区别
Object.is(+0,-0);//false
+0 === -0; //true
Object.is(NaN,NaN);//true
NaN === NaN; //false
2.数组
Array.of():将所有值作为元素行成数组
let array = Array.of(1,'5',false);//[1,'5',false]
Array.from():将类数组对象或者所有可迭代的对象转换为数组。
参数:Array.from(arrayLike,[, mapFn[,thisArg]])
- arrayLike:转换的对象
- mapFn:对每个元素进行处理,转换后的数组是处理过的元素。可选
- thisArg:指定执行mapFn函数时的this对象。可选
let array = Array.from([1,2]);//[1,2]
array = Array.from([1,,3]);//[1,undefined,3]
//两个参数时
let array2 = Array.from([1,5,3,6,8],item => item - 1);//[0,4,2,5,7]
//三个参数时
let map = {
add(number){
return number+2;
}
};
let array3 = Array.from([1,5,3,6,8],function (item){
return this.add(item);//这里一定要使用return返回元素,不然数组的值都会变成undefined
},map);//[3,7,5,8,10]
//转换Map
let myMap = new Map();
myMap.set(1,"666");
myMap.set('2',"555");
let mapArray = Array.from(myMap);//[[1,"666"],["2","555"]]
//转换Set
let mySet = new Set();
mySet.add(1);
mySet.add("666");
mySet.add({name:"六十元"});
let setArray = Array.from(mySet);//[1,"666",{name:"六十元"}]
//转换字符串
let string = "lsy";
let strArray = Array.from(string);//["l","s","y"]
类数组对象
该对象必须含有length属性,且属性名必须是数值或者是可转换为数值的字符。
let arrayObj = {
0:1,
1:2,
2:"3",
length:3
}
let array = Array.from(arrayObj);//[1,2,"3"]
//没有length属性时,返回空数组
arrayObj = {
0:1,
1:2,
2:"3"
}
array = Array.from(arrayObj);//[]
//只要有一个属性名不为数值且转换不了数值时,返回长度length的元素值为undefined的数组
arrayObj = {
a:1,
b:2,
3:5,
c:"3",
length:3
}
array = Array.from(arrayObj);//[undefined,undefined,undefined]
扩展的方法
2.1:查找
- find():查询数组中符号条件的元素,如包含多个符号条件的元素,只返回第一个元素。
- findIndex():查询数组中符号条件的元素索引,如包含多个符号条件的元素索引,只返回第一个元素索引。
- includes(value,index):查询数组中是否包含此值。返回布尔值
注意点:当数组有空位时,会处理为undefined。
let array = Array.of(23,43,12,53);
console.log(array.find(item => item > 25));//43
console.log(array.findIndex(item => item == 12));//2
console.log(array.includes(43));//true
//查询该数组中是否有非数字NaN
console.log(array.includes(NaN));//false
console.log(array.includes(12,3));//false
2.2:填充
-
fill(value,start,end):将一定范围索引的元素内容填充为指定的单个值。
参数value:填充的值 参数start:填充范围的起始位置,默认为数组开头(可选) 参数end:填充范围的结束位置-1,默认为数组末尾(可选)
let array = Array.of(1,45,23,53);
console.log(array.fill(3,1,2));//[1,3,23,53]
//此时array里面的数组为[1,3,23,53]
console.log(array.fill(5,1,3));//[1,5,5,53]
//此时array里面的数组为[1,5,5,53]
console.log(array.fill(3));//[3,3,3,3]
//此时array里面的数组为[3,3,3,3]
-
copyWithin():将一定范围索引的元素修改为此数组另一指定范围索引的元素。
参数target:被修改的起始位置 参数start:要复制的数据起始位置,默认为数组开头(可选) 参数end:要复制的数据结束位置-1,默认为数组末尾(可选)
let array = Array.of(23,53,32,54);
console.log(array.copyWithin(1,2));//[23,32,54,54]
//此时array里面的数组为[23,32,54,54]
console.log(array.copyWithin(1));//[23,23,32,54]
//此时array里面的数组为[23,23,32,54]
console.log(array.copyWithin(0,2,3));//[32,23,32,54]
//此时array里面的数组为[32,23,32,54]
2.3:遍历
- entries():遍历键值对
let array = Array.of(32,"六十元",66);
for(let [key,value] of array.entries()){
console.log(key, value);
}
// 0 32
// 1 "六十元"
// 2 66
//不使用for-of
let arrEntries = array.entries();
console.log(arrEntries.next().value);// [0, 32]
console.log(arrEntries.next().value);// [1, "六十元"]
console.log(arrEntries.next().value);// [2, 66]
//数组空位,自动处理为undefined
array = Array.from([,23]);
console.log(array.entries().next().value);//[0,undefined]
- keys():遍历键名
let array = Array.of(1,3,52);
for(let key of array.keys()){
console.log(key);
}
//0
//1
//2
- values():遍历键值
let array = Array.of(1,3,52);
for(let value of array.values()){
console.log(value);
}
//1
//3
//52
2.4:嵌套数组转一维数组
- flat(n):拉平嵌套数组,默认为一层,n参数代表拉平的层数,Infinity表示不管多少层,全部转为一维数组。
console.log([1,[2,[3,[5],64]]].flat());//[1,2,[3,[5],64]]
console.log([1,[2,[3,[5],64]]].flat(2));//[1,2,3,[5],64]]
console.log([1,[2,[3,[5],64]]].flat(Infinity));//[1,2,3,5,64]
- flatMap():先对数组中的每个元素进行处理,然后在执行flat方法转为一维数组。只能用于一维数组。
console.log([1,3,52,42,64].flatMap(item => item+2));//[3, 5, 54, 44, 66]
//二维数组使用flatMap()
console.log([1,3,52,[42],64].flatMap(item => item+2));//[3, 5, 54, "422", 66]
2.5:数组缓冲区
是指在内存中的一段地址,定型数组的基础,实际字节数在创建时确定,之后只可修改其中的数据,不可修改大小。可通过构造函数进行创建。
let array = new ArrayBuffer(10);
console.log(array.byteLength);//数组字节长度为10
2.5.1视图
视图是用来操作内存的接口。
视图可以操作数组缓冲区或者缓冲区字节的子集,并按照其中一种数值数据类型来读取或写入数据。
DataView是一种常用的数组缓冲区视图,其支持所有8种数值数据类型。
let array = new ArrayBuffer(10);
let dataView = new DataView(array);
dataView.setInt8(0,1);
dataView.setInt16(1,82);
console.log(dataView.getInt8(0));
console.log(dataView.getInt16(1));
//可以通过偏移量(参数2)和长度(参数3)来指定DadaView可操作的字节范围
dataView = new DataView(array,0,4);//dataView可访问的范围有0-4(长度减一)
dataView.setInt8(3,123);
dataView.setInt32(4,12);//RangeError: Offset is outside the bounds of the DataView
2.5.2:定型数组
数组缓冲区中特定类型的视图。
可以强制使用特定的数据类型,而不是使用DataView来操作数组缓冲区。
可接受参数包括定型数组、类数组对象、可迭代对象、数组。
//通过数组缓冲区生成
let arrayBuf = new ArrayBuffer(10);
let arrView = new Int8Array(arrayBuf);
//通过构造函数生成
let view = new Int32Array(10);
//不传参的话,默认为0,这种情况下数组缓冲区不会在内存中分配空间,所以不能用来操作数据
let view = new Int32Array(0);
console.log(view.byteLength);//0
console.log(view.length);//0
view.set(0,12);//TypeError: invalid_argument
注意点:length属性是不可修改的,一但创建数组缓冲区,length属性就是只读的。在非严格模式下,修改会直接跳过,但在严格模式下会报错。
let arrayBuf = new ArrayBuffer(10);
let arrView = new Int12Array(arrayBuf);
console.log(arrView.length);//10
arrView.length = 15;//15
console.log(arrView.length);//10
定型数组也可用entries()、keys()、values()进行迭代。
let view = new Int16Array([123, 23]);
for(let [k, v] of view.entries()){
console.log(k, v);
}
//0 123
//1 23
定型数组中新增的方法
- set():用于将其他数组复制到定型数组。
- subarray():用于提取定型数组中的一部分行成新的定型数组。
let view = new Int16Array([123, 23]);
console.log(view);//123,23
view.set([32,54]);
console.log(view);//32,54
view.set([23,53,32]);//RangeError: offset is out of bounds
//subarray()
//参数1:可选,提取开始位置
//参数2:可选,提前结束位置-1.
console.log(view.subarray());//[32,54]
console.log(view.subarray(1));//[54]
console.log(view.subarray(0,2));//[32,54]
结束语
今天ES6的对象、数组就介绍到这里了。下面还会持续更新ES6中的其他内容。谢谢大家的观看!
参考文档:菜鸟教程