Array的属性和要领

属性 length

length 属性可获得数组的长度,即数组中值的个数。数组的长度是比数组最大索引值多一的数。

let arr = [1, 2, 3, 4]
arr.length      //  4;

假如给 length 属性赋值,指定的数组长度小于原数组长度,会收缩数组。

let arr = [1, 2, 3, 4]
arr.length = 3;
arr             // [1, 2, 3]

length 设为 0,能够清空数组。

let arr = [1, 2, 3, 4]
arr.length = 0;
arr              // []

要领

静态要领

1. Array.isArray()

Array.isArray() 要领返回一个布尔值,示意参数是不是为数组。它能够填补 typeof 运算符的不足。

let arr = [1, 2, 3];

typeof arr           // "object"
Array.isArray(arr)   // true

2. Array.from()

Array.from() 要领用于将两类对象转为真正的数组:类数组对象和可遍历(iterable)的对象(包括 ES6 新增的数据构造 Set 和 Map)。返回值是新数组。

let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 };

// ES5的写法
var arr1 = [].slice.call(arrayLike);   // ['a', 'b', 'c']

// ES6的写法
let arr2 = Array.from(arrayLike);      // ['a', 'b', 'c']

只如果布置了 Iterator 接口的数据构造,Array.from 都能将其转为数组。

Array.from('hello')    // ['h', 'e', 'l', 'l', 'o']

let namesSet = new Set(['a', 'b'])
Array.from(namesSet)   // ['a', 'b']

任何有 length 属性的对象,即类数组对象,都能够经由过程 Array.from() 要领转为数组。

Array.from({ length: 3 });    // [ undefined, undefined, undefined ]

Array.from() 还能够接收第二个参数,作用相似于数组的 map 要领,用来对每一个元素举行处置惩罚,将处置惩罚后的值放入返回的数组。

Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x);

Array.from([1, 2, 3], (x) => x * x)   // [1, 4, 9]

Array.from() 的第三个参数,用来绑定 this

运用

掏出一组 DOM 节点的文本内容。

let spans = document.querySelectorAll('span.name');

// map()
let names1 = Array.prototype.map.call(spans, s => s.textContent);

// Array.from()
let names2 = Array.from(spans, s => s.textContent)

将数组中布尔值为 false 的成员转为 0

Array.from([1, , 2, , 3], (n) => n || 0)   // [1, 0, 2, 0, 3]

返回种种数据的范例。

function typesOf () {
  return Array.from(arguments, value => typeof value)
}
typesOf(null, [], NaN)   // ['object', 'object', 'number']

将字符串转为数组,然后返回字符串的长度。因为它能正确处置惩罚种种 Unicode 字符,能够防止 JS 将大于 \uFFFFUnicode 字符,算作两个字符的 bug。

function countSymbols(string) {
  return Array.from(string).length;
}

3. Array.of()

Array.of() 要领用于将一组值,转换为数组。

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

Array.of() 老是返回参数值构成的数组。假如没有参数,就返回一个空数组。

Array.of()            // []
Array.of(undefined)   // [undefined]
Array.of(1)           // [1]

Array.of() 要领能够用下面的代码模仿完成。

function ArrayOf(){
  return [].slice.call(arguments);
}

实例要领

1. valueOf(),toString()

valueOf() 要领是一个一切对象都具有的要领,示意对该对象求值,差别对象的valueOf() 要领不尽一致。数组的 valueOf 要领是 Array 组织函数的原型上的要领,掩盖了 ObjectvalueOf() 要领,返回数组本身。

let arr = [1, 2, 3];
arr.valueOf()    // [1, 2, 3]

toString() 要领也是对象的通用要领。数组的 toString 要领是 Array 组织函数的原型上的要领,掩盖了 ObjecttoString() 要领,返回数组的字符串情势。相当于挪用 join() 要领,将数组转换为字符串,用逗号衔接。

let arr = [1, 2, 3];
arr.toString()     // "1,2,3"

let arr = [1, 2, 3, [4, 5, 6]];
arr.toString()     // "1,2,3,4,5,6"

2. push(),pop()

push() 要领用于在数组的末尾增加一个或多个元素,并返回增加新元素后的数组长度。

该要领会直接转变原数组。

let arr = [];

arr.push(1)           // 1
arr.push('a')         // 2
arr.push(true, {})    // 4
arr                   // [1, 'a', true, {}]

pop() 要领用于删除数组的末了一个元素,一次只能删一项。并返回被删除的该元素。

该要领会直接转变原数组。

let arr = ['a', 'b', 'c'];

arr.pop()    // 'c'
arr          // ['a', 'b']

对空数组运用 pop() 要领,不会报错,而是返回 undefined

[].pop()     // undefined

push()pop() 连系运用,就构成了“后进先出”的栈构造(stack)。

let arr = [];
arr.push(1, 2);
arr.push(3);
arr.pop();   // 3 是末了进入数组的,然则最早脱离数组。
arr          // [1, 2]

3. shift(),unshift()

shift() 要领用于删除数组的第一个元素,一次只能删一项。并返回被删除的该元素。

该要领会直接转变原数组。

let arr = ['a', 'b', 'c'];

arr.shift()   // 'a'
arr           // ['b', 'c']

push()shift() 连系运用,就构成了“先进先出”的行列构造(queue)。

let arr = [];
arr.push(1, 2);
arr.push(3);
arr.shift();   // 1 是最早进入数组的,也最早脱离数组。
arr            // [2, 3]

unshift() 要领用于在数组的第一个位置增加一个或多个元素,并返回增加新元素后的数组长度。

该要领会直接转变原数组。

let arr = ['a', 'b', 'c'];

arr.unshift('x');      // 4
arr.unshift('y', 'z')  // 6
arr                    // ["y", "z", "x", "a", "b", "c"]

4. join()

join() 要领以指定参数作为分开符,将一切数构成员衔接为一个字符串返回。假如不供应参数,默许用逗号分开。

该要领不转变原数组。

let arr = [1, 2, 3, 4];

arr.join(' ')     // '1 2 3 4'
arr.join(' | ')   // "1 | 2 | 3 | 4"
arr.join('~')     // '1~2~3~4'
arr.join()        // "1,2,3,4"

假如数构成员是 undefinednull空位 ,会被转成空字符串。

[undefined, null].join('#')   // '#'
['a',, 'b'].join('-')         // 'a--b'

经由过程 call 要领,这个要领也能够用于字符串或类数组对象。

Array.prototype.join.call('hello', '-')    // "h-e-l-l-o"

let obj = { 0: 'a', 1: 'b', length: 2 };
Array.prototype.join.call(obj, '-')        // 'a-b'

5. concat()

concat() 要领用于多个数组的兼并。它将新数组的成员,增加到原数构成员的背面,然后返回一个新数组。参数设置异常天真,能够是数组变量,也能够是字符串或数组字面量。

该要领不转变原数组。


['hello'].concat(['world'], ['!'])  // ["hello", "world", "!"]
[].concat({a: 1}, {b: 2})           // [{ a: 1 }, { b: 2 }]
[1, 2, 3].concat(4, 5, 6)           // [1, 2, 3, 4, 5, 6]

let arr = [2,3];
[1].concat(arr)                     // [1, 2, 3]

concat() 要领是“浅拷贝”,拷贝的是对象的援用。

let obj = { a: 1 };
let newArray = [].concat(obj);
newArray[0].a                    // 1
obj.a = 2                        // 2
newArray[0].a                    // 2

6. reverse()

reverse() 要领用于倒置分列数组元素,返回转变后的数组。

该要领会直接转变原数组。

let arr = ['a', 'b', 'c'];

arr.reverse()     // ["c", "b", "a"]
arr               // ["c", "b", "a"]

7. slice()

slice(start, end) 要领用于提取目标数组中选中的部份作为一个新的数组返回。

该要领不转变原数组。

参数

a. slice(start, end),从下标 start 最先截取到下标 end 的元素,包括 start 不包括 end

let arr = ['a', 'b', 'c'];
arr.slice(1, 2)     // ["b"]
arr.slice(2, 6)     // ["c"]

b. slice(start),只需 start 一个参数示意从包括 start 的下标最先截取背面一切的元素。

let arr = ['a', 'b', 'c'];
arr.slice(1)    // ["b", "c"]

c. slice(),没有参数,则相当于从下标 0 最先截取背面一切的元素,实际上即是返回一个原数组的拷贝。

let arr = ['a', 'b', 'c'];
arr.slice(0)    // ["a", "b", "c"]
arr.slice()     // ["a", "b", "c"]

d. slice(-start, -end),参数能够用负数。示意倒数盘算的位置。-1 示意倒数盘算的第一个位置,顺次向前类推。

let arr = ['a', 'b', 'c'];
arr.slice(-2)         // ["b", "c"]
arr.slice(-2, -1)     // ["b"]

e. 假如第一个参数大于即是数组长度,或许第二个参数小于第一个参数,则返回空数组。

let arr = ['a', 'b', 'c'];
arr.slice(4)           // []
arr.slice(2, 1)        // []

slice() 要领的一个主要运用,是经由过程 call 要领,将类数组对象转为真正的数组。

Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 })  // ['a', 'b']

Array.prototype.slice.call(document.querySelectorAll("div"));
Array.prototype.slice.call(arguments);

8. splice()

splice() 要领是一个多功能要领,依据参数的差别能够插进去、删除、替代元素,返回值是被删除的元素构成的数组。

该要领会直接转变原数组。

arr.splice(start, count, addElement1, addElement2, ...);

参数

a. arr.splice(start) 1个参数是拆分,等同于将原数组在指定位置拆分红两个数组。删除下标以后的悉数值。包括 start

let arr = ['a', 'b', 'c', 'd', 'e', 'f'];
arr.splice(3)     // ['d', 'e', 'f']
arr               // ['a', 'b', 'c']

b. arr.splice(start, count) 2个参数是删除,第二个参数是删除的个数,相当于从 start 最先,删除第二个参数指定的元素个数。

let arr = ['a', 'b', 'c', 'd', 'e', 'f'];
arr.splice(4, 2)    // ["e", "f"] 下标 4 最先删除 2 项
arr                 // ["a", "b", "c", "d"]

c. arr.splice(start, count, ...) 更多参数是替代,示意从 start 最先,删除 count 项,然后将背面的参数作为新元素插进去原数组中,返回值是被删除的元素。

let arr = ['a', 'b', 'c', 'd', 'e', 'f'];
arr.splice(4, 2, 1, 2)   // ["e", "f"]
arr                     // ["a", "b", "c", "d", 1, 2]

d. arr.splice(start, 0, ...) 第二个参数为0时,示意插进去,从 start 最先,删除 0 项,并在 start 之前增加新元素。返回空数组。

let arr = ['a', 'b', 'c', 'd'];
arr.splice(2, 0, 1, 2)  // []
arr                     // ["a", "b", 1, 2, "c", "d"]

e. arr.splice(-start, ...) 肇端位置 start 假如是负数,就示意从倒数位置最先举行相干操纵。

let arr = ['a', 'b', 'c', 'd'];
arr.splice(-2, 2)     // ["c", "d"]

9. sort()

sort() 要领对数构成员举行排序,默许根据字符递次排序,会将数字隐式转换为字符串排序。直接返回转变后的原数组。

该要领会直接转变原数组。

let arr = ['d', 'c', 'b', 'a'];
arr.sort()    // ["a", "b", "c", "d"]
arr           // ["a", "b", "c", "d"]

会将数字隐式转换为字符串排序。

let arr=[2,3,45,12,78,67,155]
arr.sort()    // [12, 155, 2, 3, 45, 67, 78]

自定义排序,能够传入一个函数作为参数。

let arr=[2,3,45,12,78,67,155]
arr.sort(function(a,b){ return a-b })   //  [2, 3, 12, 45, 67, 78, 155]

sort 的参数函数本身接收两个参数 ab,示意举行比较的两个数构成员。假如该函数的返回值 >0,那末 b 排在 a 的前面;=0,位置稳定;<0a 排到 b 的前面。

[{ name: "张三", age: 30 },
  { name: "李四", age: 24 },
  { name: "王五", age: 22 }
].sort(function (o1, o2) {
  console.log(o1.age, o2.age);
  return o1.age - o2.age;
})

// 30 24
// 30 22
// 24 22

// [
//   { name: "李四", age: 22 },
//   { name: "王五", age: 24 },
//   { name: "张三", age: 30 }
// ]

由上述例子能够看出 sort() 自定义排序参数传入的道理,第一次 30 和 24 比拟,24 在前,30 在后,排序效果为 (24,30,22);第二次 30 和 22 比拟,22 在前,30 在后,排序效果为 (24,22,30);第三次用来肯定调换了位置的 30 和 22 中的排序在前的 22 和前一个 24 比拟哪一个更小,终究排序效果为 (22,24,30)

由此能够看出排序的道理,假如位置稳定,则顺次向后做比较;一旦位置发生变化,则分列在前的元素会与上一个元素做比较,顺次向前直到位置稳定为止,再接着从发生变化的位置最先顺次向后做比较。

运用:能够让一个数组随机乱序。

var arr = [1,2,3,4,5,6,7,8,9,10];
arr.sort(function(){
    return Math.random() - 0.5;
})

10. map()

map() 要领将数组的一切成员顺次传入参数函数,然后把每一次的实行效果构成一个新数组返回。

该要领不转变原数组。

let numbers = [1, 2, 3];
numbers.map(function (n) {
  return n + 1;
});        // [2, 3, 4]
numbers    // [1, 2, 3]

map() 要领接收一个函数作为参数。该函数挪用时,map要领向它传入三个参数:第一个为当前进入函数的数组元素,第二个为当前元素的下标,第三个为原始数组。只需第一个是必须的。

[1, 2, 3].map(function(elem, index, arr) {
  return elem * index;
});            // [0, 2, 6]

假如数组有空位,map() 要领的回调函数在这个位置不会实行,会跳过数组的空位。但不会跳过 undefinednull

let f = function (n) { return 'a' };

[1, undefined, 2].map(f)   // ["a", "a", "a"]
[1, null, 2].map(f)        // ["a", "a", "a"]
[1, , 2].map(f)            // ["a", , "a"]

map() 要领还能够接收第二个参数,用来绑定回调函数内部的 this 变量

let arr = ['a', 'b', 'c'];

[1, 2].map(function (e) {
  return this[e];
}, arr)        // ['b', 'c']

11. forEach()

forEach() 要领与 map() 要领很相似,也是对数组的一切成员顺次实行参数函数。然则,forEach() 要领不返回值,只用来操纵数据。这就是说,假如数组遍历的目标是为了获得返回值,那末运用 map() 要领,不然运用 forEach() 要领。

forEach() 的用法与 map() 要领一致,参数是一个函数,该函数一样接收三个参数:当前元素、当前下标、全部数组。一样也会跳过数组的空位。但不会跳过 undefinednull

var log = function (n) { console.log(n + 1); };

[1, undefined, 2].forEach(log)   // 2   // NaN  // 3
[1, null, 2].forEach(log)        // 2   // 1    // 3
[1, , 2].forEach(log)           // 2    // 3

forEach() 要领也能够接收第二个参数,绑定参数函数的 this 变量。

let out = [];

[1, 2, 3].forEach(function(elem) {
  this.push(elem * elem);
}, out);

out     // [1, 4, 9]

注重,forEach() 要领没法中缀实行,老是会将一切成员遍历完。假如愿望相符某种前提时,就中缀遍历,要运用 for 轮回。

let arr = [1, 2, 3];

for (let i = 0; i < arr.length; i++) {
  if (arr[i] === 2) break;
  console.log(arr[i]);
}
// 1

12. filter()

filter() 要领用于过滤数构成员,满足前提的成员构成一个新数组返回。它的参数是一个函数,一切数构成员顺次实行该函数,返回效果为 true 的成员构成一个新数组返回。

该要领不转变原数组。

[1, 2, 3, 4, 5].filter(function (elem) {
  return (elem > 3);
})         // [4, 5]

let arr = [0, 1, 'a', false];
arr.filter(Boolean)     // [1, "a"]

filter() 要领的参数函数能够接收三个参数:当前元素、当前下标、全部数组。

[1, 2, 3, 4, 5].filter(function (elem, index, arr) {
  return index % 2 === 0;
});       // [1, 3, 5]

filter() 要领还能够接收第二个参数,用来绑定参数函数内部的 this 变量。

let obj = { MAX: 3 };
let myFilter = function (item) {
  if (item > this.MAX) return true;
};

let arr = [2, 8, 3, 4, 1, 3, 2, 9];
arr.filter(myFilter, obj)    // [8, 4, 9]

13. some(),every()

这两个要领相似“断言”(assert),返回一个布尔值,示意推断数构成员是不是相符某种前提。

它们接收一个函数作为参数,一切数构成员顺次实行该函数。该函数接收三个参数:当前元素、当前下标和全部数组。然后返回一个布尔值。

some() 要领是只需一个成员的返回值是 true,则全部 some() 要领的返回值就是 true,不然返回 false

let arr = [1, 2, 3, 4, 5];
arr.some(function (elem, index, arr) {
  return elem >= 3;
});          // true

every() 要领是一切成员的返回值都是 true,全部every() 要领才返回 true,不然返回 false

let arr = [1, 2, 3, 4, 5];
arr.every(function (elem, index, arr) {
  return elem >= 3;
});          // false

注重,关于空数组,some() 要领返回 falseevery() 要领返回 true,回调函数都不会实行。

function isEven(x) { return x % 2 === 0 }

[].some(isEven)       // false
[].every(isEven)      // true

some()every() 要领还能够接收第二个参数,用来绑定参数函数内部的 this 变量。

14. reduce(),reduceRight()

reduce() 要领和 reduceRight() 要领顺次处置惩罚数组的每一个成员,终究累计为一个值。它们的差别是,reduce 是从左到右处置惩罚(从第一个元素到末了一个元素),reduceRight 则是从右到左(从末了一个元素到第一个元素),其他完整一样。

[1, 2, 3, 4, 5].reduce(function (a, b) {
  console.log(a, b);
  return a + b;
})        //  15
// 1 2
// 3 3
// 6 4
// 10 5

reduce() 要领和 reduceRight() 要领的第一个参数都是一个函数。该函数接收以下四个参数。前两个是必须的,后两个是可选的。

  • 积累变量,顺次为上一轮的返回值,初始值默许为数组的第一个元素,可经由过程参数传入指定的初始变量。
  • 当前变量,默许为数组的第二个元素,当积累变量有指定初始值时,当前变量为第一个元素。
  • 当前变量的下标,默许为 1,当积累变量有指定初始值时,下标为 0。
  • 原数组

reduce() 要领和 reduceRight() 要领的第二个参数是对积累变量指定初值。

[1, 2, 3, 4, 5].reduce(function (a, b) {
  return a + b;
}, 10);       // 25

指定积累变量相当于设定了默许值,关于处置惩罚空数组特别有效。

function add(prev, cur) { return prev + cur; }
[].reduce(add)        // 报错
[].reduce(add, 1)     // 1  永久返回初始值,不会实行函数

reduceRight() 是从右到左顺次实行函数。

 function subtract(prev, cur) { return prev - cur; }
 
 [3, 2, 1].reduce(subtract)         // 0
 [3, 2, 1].reduceRight(subtract)    // -4

运用 因为这两个要领会遍历数组,所以实际上还能够用来做一些遍历相干的操纵。

找出字符长度最长的数构成员。

function findLongest(entries) {
  return entries.reduce(function (longest, entry) {
    return entry.length > longest.length ? entry : longest;
  }, '');
}

findLongest(['aaa', 'bb', 'c'])     // "aaa"

将二维数组转化为一维

[[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {
    return a.concat(b);
},[])          // [0, 1, 2, 3, 4, 5]

数组去重

let arr = [1,2,1,2,3,5,4,5,3,4,4,4,4];
let result = arr.sort().reduce((init, current)=>{
    if(init.length===0 || init[init.length-1]!==current){
        init.push(current);
    }
    return init;
}, [])         //[1,2,3,4,5]

按属性对object分类

let people = [
  { name: 'Alice', age: 21 },
  { name: 'Max', age: 20 },
  { name: 'Jane', age: 20 }
];

function groupBy(objectArray, property) {
  return objectArray.reduce(function (acc, obj) {
    let key = obj[property];
    if (!acc[key]) {
      acc[key] = [];
    }
    acc[key].push(obj);
    return acc;
  }, {});
}

groupBy(people, 'age');
// { 
//   20: [
//     { name: 'Max', age: 20 }, 
//     { name: 'Jane', age: 20 }
//   ], 
//   21: [{ name: 'Alice', age: 21 }] 
// }

参考链接:Array.prototype.reduce()

15. indexOf(),lastIndexOf()

indexOf() 要领返回参数在数组中第一次涌现的位置,假如没有涌现则返回-1。

let arr = ['a', 'b', 'c'];
arr.indexOf('b')    // 1
arr.indexOf('y')    // -1

indexOf() 要领还能够接收第二个参数,示意搜刮的最先位置。

['a', 'b', 'c'].indexOf('a', 1)    // -1

lastIndexOf() 要领返回参数在数组中末了一次涌现的位置,假如没有涌现则返回-1。

let arr = [2, 5, 9, 2];
arr.lastIndexOf(2)     // 3
arr.lastIndexOf(7)     // -1

注重,这两个要领不能用来搜刮 NaN 的位置,即它们没法肯定数构成员是不是包括 NaN。这是因为这两个要领内部,运用严厉相称运算符(===)举行比较,而 NaN 是唯一一个不即是本身的值。

[NaN].indexOf(NaN)        // -1
[NaN].lastIndexOf(NaN)    // -1

16. copyWithin()

copyWithin() 要领,在当前数组内部,将指定位置的成员复制到其他位置(会掩盖原有成员),然后返回当前数组。包括 start 不包括 end

该要领会直接转变原数组。

Array.prototype.copyWithin(target, start, end)

接收三个参数:

  • target(必须):从该位置最先替代数据。假如为负值,示意倒数。
  • start(可选):从该位置最先读取数据,默许为 0。假如为负值,示意倒数。
  • end(可选):到该位置前住手读取数据,默许即是数组长度。假如为负值,示意倒数。
[1, 2, 3, 4, 5].copyWithin(0, 3)   // [4, 5, 3, 4, 5]

上面代码示意将从下标 3 到数组完毕的元素(4 和 5),复制到从下标 0 最先的位置,效果掩盖了本来的 1 和 2。

[1, 2, 3, 4, 5].copyWithin(0, 3, 4)      // [4, 2, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(0, -2, -1)    // [4, 2, 3, 4, 5]
[].copyWithin.call({length: 5, 3: 1}, 0, 3)  // {0: 1, 3: 1, length: 5}

17. find(),findIndex()

find() 要领用于找出第一个相符前提的数组元素。它的参数是一个回调函数,一切数组元素顺次实行该回调函数,直到找出第一个返回值为 true 的元素,然后返回该元素。假如没有相符前提的元素,则返回 undefined

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

find() 要领的回调函数能够接收三个参数,顺次为当前元素、当前下标和原数组。

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

findIndex() 要领的用法与 find() 要领异常相似,返回第一个相符前提的数组元素的位置,假如一切元素都不相符前提,则返回 -1。

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

这两个要领都能够接收第二个参数,用来绑定回调函数的 this 对象。

function f(v){ return v > this.age; }
let person = {name: 'John', age: 20};
[10, 12, 26, 15].find(f, person);      // 26

别的,这两个要领都能够能够借助 Object.is() 要领辨认数组的 NaN,填补了 indexOf() 要领的不足。

[NaN].indexOf(NaN)       // -1

[NaN].findIndex(y => Object.is(NaN, y))   // 0

18. fill()

fill() 要领运用给定值,添补一个数组。

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

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

fill() 要领还能够接收第二个和第三个参数,用于指定添补的肇端位置和完毕位置。

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

注重,假如添补的范例为对象,那末被赋值的是同一个内存地址的对象,而不是深拷贝对象。

let arr = new Array(3).fill({name: "Mike"});
arr[0].name = "Ben";
arr    // [{name: "Ben"}, {name: "Ben"}, {name: "Ben"}]

let arr = new Array(3).fill([]);
arr[0].push(5);
arr    // [[5], [5], [5]]

19. includes()

includes() 要领返回一个布尔值,示意某个数组是不是包括给定的值,与字符串的includes() 要领相似。

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

该要领的第二个参数示意搜刮的肇端位置,默许为0。假如第二个参数为负数,则示意倒数的位置,假如这时候它大于数组长度(比方第二个参数为-4,但数组长度为3),则会重置为从0最先。

[1, 2, 3].includes(3, 3);    // false
[1, 2, 3].includes(3, -1);   // true

没有该要领之前,我们一般运用数组的 indexOf() 要领,搜检是不是包括某个值。

if (arr.indexOf(el) !== -1) {
  // ...
}

indexOf() 要领内部运用严厉相称运算符(===)举行推断,这会致使对 NaN 的误判。includes() 运用的是不一样的推断算法,就没有这个题目。

[NaN].indexOf(NaN)     // -1
[NaN].includes(NaN)    // true

20. flat(),flatMap()

flat() 用于将多维数组变成一维数组。返回一个新数组。

该要领不转变原数组。

[1, 2, [3, 4]].flat()   // [1, 2, 3, 4]

flat() 默许只会“拉平”一层,假如想要“拉平”多层的嵌套数组,能够将 flat() 要领的参数写成一个整数,示意想要拉平的层数,默许为 1。

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

假如不论有若干层嵌套,都要转成一维数组,能够用 Infinity 关键字作为参数。

[1, [2, [3]]].flat(Infinity)   // [1, 2, 3]

假如原数组有空位,flat() 要领会跳过空位。

[1, 2, , 4, 5].flat()          // [1, 2, 4, 5]

flatMap() 要领对原数组的每一个元素实行一个函数(相当于实行Array.prototype.map()),然后对返回值构成的数组实行 flat() 要领。返回新数组。

该要领不转变原数组。

[2, 3, 4].flatMap((x) => [x, x * 2])   // [2, 4, 3, 6, 4, 8]
//  相当于 [[2, 4], [3, 6], [4, 8]].flat()

flatMap() 只能睁开一层数组。

[1, 2, 3, 4].flatMap(x => [[x * 2]])   // [[2], [4], [6], [8]]
//  相当于 [[[2]], [[4]], [[6]], [[8]]].flat()

flatMap() 要领的参数是一个遍历函数,该函数能够接收三个参数,分别是当前数组元素、当前数组元素的下标(从零最先)、原数组。

flatMap() 要领还能够有第二个参数,用来绑定遍历函数内里的 this

arr.flatMap(function callback(currentValue[, index[, array]]) {
  // ...
}[, thisArg])

链式运用

上面这些数组要领当中,有不少返回的照样数组,所以能够链式运用。

var users = [
  {name: 'tom', email: 'tom@example.com'},
  {name: 'peter', email: 'peter@example.com'}
];

users
.map(function (user) {
  return user.email;
})
.filter(function (email) {
  return /^t/.test(email);
})
.forEach(function (email) {
  console.log(email);
});
// "tom@example.com"

参考链接:
Array对象
数组的扩大

    原文作者:Dora36
    原文地址: https://segmentfault.com/a/1190000018059136
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞