对象和数组的扩展方法

1. 对象的扩展方法

1.1 Object.is()

ES5 比较两个值是否相等,只有两个运算符:相等运算符(==)和严格相等运算符(===)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0JavaScript 缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等。 ES6 提出“Same-value equality”(同值相等)算法,用来解决这个问题。Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致

console.log(Object.is('foo', 'foo'));
console.log(Object.is(NaN, NaN))
// true

console.log(Object.is({}, {}));
console.log(Object.is(+0, -0));
// false

不同之处只有两个:一是+0不等于-0,二是NaN等于自身

+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

1.2 Object.assign()

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target

let target = { a: 1 };
let source1 = { b: 2 };
let source2 = { c: 3 };

Object.assign(target, source1, source2);
console.log(target) // { a:1, b:2, c:3 }

Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。

注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性

let target = { a: 1, b: 1 };
let source1 = { b: 2, c: 2 };
let source2 = { c: 3 };

Object.assign(target, source1, source2);
console.log(target) // { a:1, b:2, c:3 }

如果只有一个参数,Object.assign会直接返回该参数

let obj = {a: 1};
Object.assign(obj) === obj // true

如果该参数不是对象,则会先转成对象,然后返回

typeof Object.assign(2) // "object"

由于undefinednull无法转成对象,所以如果它们作为参数,就会报错

Object.assign(undefined) // 报错
Object.assign(null) // 报错

注意:Object.assign可以用来处理数组,但是会把数组视为对象

Object.assign([1,2,3], [4,5]);
// [4,5,3]
// 把数组视为属性名为 0、1、2 的对象,因此源数组的 0 号属性 4 覆盖目标数组的 0 号属性 1

1.3 Object.keys()

ES5 引入了Object.keys方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名

var obj = { foo: 'bar', baz: 42 };
console.log(Object.keys(obj))
// ["foo", "baz"]

ES8引入了跟Object.keys配套的Object.valuesObject.entries,作为遍历一个对象的补充手段,供for...of循环使用

let { keys, values, entries } = Object;
let obj = { a: 1, b: 2, c: 3 };

for (let key of keys(obj)) {
  console.log(key); // 'a', 'b', 'c'
}

for (let value of values(obj)) {
  console.log(value); // 1, 2, 3
}

for (let [key, value] of entries(obj)) {
  console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}

1.4 Object.values()

Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值

let obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]

1.5 Object.entries

Object.entries方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组

const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]

除了返回值不一样,该方法的行为与Object.values基本一致


2. 数组 的扩展

2.1 Array.from()

Array.from方法用于将类数组转为真正的数组

// NodeList对象
let ps = document.querySelectorAll('p');
Array.from(ps).forEach(function (p) {
  console.log(p);
});

// arguments对象
function foo() {
  var args = Array.from(arguments);
  // ...
}

参数:

  • 第一个参数:一个类数组对象,用于转为真正的数组
  • 第二个参数:类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。
  • 第三个参数:如果map函数里面用到了this关键字,还可以传入Array.from的第三个参数,用来绑定this

2.2 Array.of()

Array.of方法用于将一组值,转换为数组。

这个方法的主要目的,是弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异

//Array
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]

Array.of(3, 11, 8) // [3, 11, 8]
Array.of(3) // [3]
Array.of(3).length // 1

2.3 数组实例的 copyWithin()

数组实例的copyWithin方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改原数组

它接受三个参数。

  • target(必需):从该位置开始替换数据。
  • start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示倒数。
  • end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数

这三个参数都应该是数值,如果不是,会自动转为数值

[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]

2.4 数组实例的 find()findIndex()

数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined

[1, 4, -5, 10].find(n => n < 0)
// -5

[1, 5, 10, 15].find(function(value, index, arr) {
  return value > 9;
}) // 10
// find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组

findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1

[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;
}) 
// 2

这两个方法都可以接受第二个参数,用来绑定回调函数的this对象

2.5 数组实例的 fill()

fill方法使用给定值,填充一个数组。

fill方法用于空数组的初始化非常方便。数组中已有的元素,会被全部抹去

['a', 'b', 'c'].fill(7)
// [7, 7, 7]

new Array(3).fill(7)
// [7, 7, 7]

fill方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置

2.6 for...of

es6引入的作为遍历所有数据结构的统一的方法。

一个数据结构只要部署了Symbol.iterator属性,就被视为具有 iterator 接口,就可以用for...of循环遍历它的成员。也就是说,for...of循环内部调用的是数据结构的Symbol.iterator方法

2.7 数组实例的 entries()keys()values()

entries()keys()values()——用于遍历数组。它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历

for (let index of ['a', 'b'].keys()) {
  console.log(index);
}
// 0
// 1

for (let elem of ['a', 'b'].values()) {
  console.log(elem);
}
// 'a'
// 'b'

for (let [index, elem] of ['a', 'b'].entries()) {
  console.log(index, elem);
}
// 0  "a"
// 1  "b"

2.8 数组实例的 includes()

方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似。ES2016引入了该方法

[1, 2, 3].includes(2)     // true
[1, 2, 3].includes(4)     // false
[1, 2, NaN].includes(NaN) // true

该方法的第二个参数表示搜索的起始位置,默认为0。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为-4,但数组长度为3),则会重置为从0开始。

没有该方法之前,我们通常使用数组的indexOf方法,检查是否包含某个值。

indexOf方法有两个缺点,一是不够语义化,它的含义是找到参数值的第一个出现位置,所以要去比较是否不等于-1,表达起来不够直观。二是,它内部使用严格相等运算符(===)进行判断,这会导致对NaN的误判

2.9 数组的空位

数组的空位指,数组的某一个位置没有任何值。

注意,空位不是undefined,一个位置的值等于undefined,依然是有值的。空位是没有任何值,in运算符可以说明这一点

0 in [undefined, undefined, undefined] // true
0 in [, , ,] // false
2.9.1 ES5 对空位的处理,已经很不一致了,大多数情况下会忽略空位。
  • forEach(), filter(), reduce(), every()some()都会跳过空位。
  • map()会跳过空位,但会保留这个值
  • join()toString()会将空位视为undefined,而undefinednull会被处理成空字符串。

ES6 则是明确将空位转为undefined

2.9.2 Array.from方法会将数组的空位,转为undefined,也就是说,这个方法不会忽略空位。
Array.from(['a',,'b'])
// [ "a", undefined, "b" ]
2.9.3 扩展运算符(...)也会将空位转为undefined
[...['a',,'b']]
// [ "a", undefined, "b" ]
2.9.4 copyWithin()会连空位一起拷贝
[,'a','b',,].copyWithin(2,0) // [,"a",,"a"]
2.9.5 fill()会将空位视为正常的数组位置
new Array(3).fill('a') // ["a","a","a"]
2.9.6 for...of循环也会遍历空位
let arr = [, ,];
for (let i of arr) {
  console.log(1);
}
// 1
// 1

上面代码中,数组arr有两个空位,for...of并没有忽略它们。如果改成map方法遍历,空位是会跳过的

2.9.7 entries()keys()values()find()findIndex()会将空位处理成undefined
// entries()
[...[,'a'].entries()] // [[0,undefined], [1,"a"]]

// keys()
[...[,'a'].keys()] // [0,1]

// values()
[...[,'a'].values()] // [undefined,"a"]

// find()
[,'a'].find(x => true) // undefined

// findIndex()
[,'a'].findIndex(x => true) // 0

由于空位的处理规则非常不统一,所以建议避免出现空位

你可能感兴趣的:(对象和数组的扩展方法)