对象可以分为:
普通对象:拥有JS对象所有默认的内部行为
奇异对象:内部行为在某些方面有别于默认行为
标准对象:在ES6中被定义的对象,如Array\Date等,可以包含前两类对象
内置对象:在脚本开始运行时有JS运行环境提供的对象所有的标准对象都是内置对象
基于上面这几类对象,补充几个提高效率的对象扩展功能:
1. 对象字面量语法的扩展
- 属性简写
ES6之前我们会习惯于这样来定义一个变量
function createPerson(name, age) {
return {
name: name,
age: age
}
}
如果函数传递的参数和对象的属性名相同,ES6中可以支持(属性初始化器的)简写,省略冒号及后面的值
// 1、会在周边作用域查找同名变量,找到就把这个变量的值赋值给对象字面量中的同名属性
function createPerson(name, age) {
return {
name,
age
}
}
- 方法简写
// 方法简写与ES5这种老的写法的区别在于:简写可以使用super,super指向的是当前对象的原型对象,后面补充super相关知识、Object.setPrototypeOf() 方法设置一个指定的对象的原型相关知识待补充
var person = {
name: "emoji",
sayName: function() {
console.log(this.name);
}
}
var person = {
name: "emoji",
sayName() {
console.log(this.name);
}
}
- 如果对象字面量中存在重复的,会以最后一个为主
- ES6对自有属性的枚举顺序也有规定
所有的数字类型键,按升序排列
所有的字符串类型键、所有的符号类型键,按被添加到对象的顺序排列 - ES6支持通过Object.setPrototypeof(需要被修改原型的对象,将会成为前者原型的对象)来修改任意指定对象的原型、
let person = {
getGreeting(){
return "hello";
}
}
let dog = {
getGreeting() {
return "woof";
}
}
// 原型为person
let friend = Object.create(person);
console.log(friend.getGreeting); // hello
// 获取原型进行比对
console.log(Object.getPrototypeOf(friend) === person); // true
// 将原型修改为dog
Object.setPrototypeOf(friend, dog);
console.log(friend.getGreeting); // woof
console.log(Object.getPrototypeOf(friend) === dog); // true
- 调用原型上的方法
Object.getPrototypeOf(this).call(this);
可以使用super:指向当前对象的原型的指针,相当于Object.getPrototypeOf(this),用来调用对象原型上的方法,所调用的方法会被设置好其内部的this绑定,以自动使用该this值来进行工作。
Object.getPrototypeOf(this).call(this);
2. 数组扩展
- Array.of()
和Array构造函数的区别:创建的时候传递的是整数参数时,Array.of会创建包含这个参数的数组,而Array会创建这个整数长度的数组
let arr = Array.of(3);
console.log(arr); // [3]
let arr = Array(3);
console.log(3); // [,,]
- Array.from()
可迭代的对象都可以使用Array.from来生成数组
Array.from('emoji'); // ["e","m","o","j","i"]
Array.from(new Set([1,2,3])); // [1,2,3]
Array.from(new Map([[1],[2]])); // [[1],[2]]
// Array.from接收第二个参数,类似于map对每个元素进行处理
Array.from([1,2,3], x => x + x); // [2,4,6]
==> 等同于Array.from(arr).map(x=>x+x);
==> Array.prototype.map.call(arr, x=>x.textContent);
// 数组去重合并
function combine(){
let arr = [].concat.apply([], arguments); //没有去重复的新数组
return Array.from(new Set(arr));
}
var m = [1, 2, 2], n = [2,3,3];
console.log(combine(m,n)); // [1,2,3]
技巧:
Array.from({length:2}, () => 'jack');
第一个参数可以指定第二个参数运行的次数。想让他运行几次都可以直接指定。
- 复制
// 将3号位复制到0号位
[1,2,3,4,5].copyWithin(0,3,4);
// -2相当于3号位,-1相当于4号位
[1,2,3,4,5].copyWithin(0,-2,-1);
// 将3号位复制到0号位
[].copyWithin.call({length:5, 3:1}, 0, 3)
- find() & findIndex()
// 和indexOf()的区别
1. 如果是对象数组的话 indexOf()是找不到的,除非删除的元素本身就是他其中的。比如v-for循环中的点击删除item。
2. indexOf找不到NaN
[NaN].indexOf(NaN); // -1
[NaN].findIndex(y => object.is(NaN, y));
find和findIndex都可以绑定第二个参数。改变回调中的this指向。
function f(v) {
return v > this.age;
}
let person = {name:"kimi", age:27};
[10,12,28,15].find(f, person);
- fill()
填充数组时,会把已经有的都覆盖掉
[1,2,3].fill(6); // [6,6,6]
可以指定从第几位到第几位开始填充
[1,2,3].fill(7,1,2); // [1,7,3]
如果填充的是对象或者数组时,是同一个内存地址的对象,不是深拷贝
let arr = new Array(3).fill({name:"mike"})
arr[0].name = "ben"; // [{name:"ben"},{name:"ben"},{name:"ben"}]
let arr = new Array(3).fill([]);
arr[0].push(5); // [[5],[5],[5]]
- entries(), keys(), values()
返回的都是一个遍历器对象,分别是键、值、键值对的遍历器
可以使用for of来遍历
for (let [index, ele] of ['a', 'b'].entries()) {
console.log(index, ele)
}
// 0 "a"
// 1 "b"
includes()
可以查出NaN
[1,2,NaN].includes(NaN) // true
第二个参数是从哪个位置开始查找,负数代表倒序查找
[1,2,3].includes(3,3) // false
[1,2,3].includes(3,-1) // true
flat(), flatMap()
[1,2,[3,[4,5]]].flat() // [1,2,3,[4,5]] 默认展开拉平一层
[1,2,[3,[4,5]]].flat(2) // [1,2,3,4,5] 可以传入参数指定拉平几层
[1,[2,[3,[4]]]].flat(Infinity) // [1,2,3,4] 指定Infinity不管多少层都可以拉平为一维数组
[1,2,,4].flat() // [1,2,4] 如果有空位则跳过空位
flatMap()
相当于先map再flat下,只能展开一层
[1,2,3].flatMap(v => [v, v*2]) // [1,2,2,4,3,6] 第二个参数可以用来绑定this
- 数组的空位
es5中
forEach(), filter(), reduce(), every(), some() 都会跳过空位
map() 会跳过空位,但会保留这个值
join()、toString() 会将空位视为undefined,而undefined和null会被处理成空字符串
es6中
将空位全部转为undefined
from , ... 会把空位转换成undefined
copyWithin(), fill(), for...of 都会把空位看成正常的位置
entries(), keys(), values(), find(), findIndex()会将空位处理成undefined