Array

数组操作技巧

直接操作 length 对数组进行截取操作

截取

var numbers = [1, 2, 3, 4, 5];
numbers.length = 3;
numbers // [1, 2, 3]

清空

var numbers = [1, 2, 3, 4, 5];
numbers.length = 0;

显示增加长度

var numbers = [1, 2, 3, 4, 5];
numbers.length = 10;
console.log(Object.keys(numbers)); // ['0', '1', '2', '5']
console.log(numbers.length); // 10

原型扩展

扩展 Array 的原型,向其添加新方法,比如

/*
  如果JavaScript本身不提供 first() 方法,
  添加一个返回数组的第一个元素的新方法。
*/
if(!Array.prototype.first) {
  Array.prototype.first = function() {
    return this[0];
  }
}

通过 Set 对数组去重

使用 ES6 的 Set 和 ...rest 操作符剔除重复的值。

const unique = arr => [...new Set(arr)];
unique([1,2,1,2,3,5,4,5,3,4,4,4,4]) // [1, 2, 3, 5, 4]

通过随机函数打乱数组顺序

使用 Math.random() 生成一个随机数,然后通过 sort 函数进行随机排序

[1,2,3,4,5].sort(() => Math.random() - 0.5)

获取数组随机元素

这里注意,得先定义数组,因为在取数组随机元素的时候,需要拿到数组引用获取其长度

let arr = [1,2,3,4,5]
let a = arr[Math.floor(Math.random() * arr.length)]

数组连接

数组连接的方法有很多, 以下是一些方案:

// es6 rest
let arr3 = [...arr1, ...arr2]
// push
arr1.push(...arr2)
// concat
let arr3 = arr1.concat(arr2)

据测算, push方式是最快的, rest稍慢些但差距不大, concat最慢, 详情可参考文章:

关于数组拷贝

数组也是一种引用类型,所以可以对其进行深拷贝和浅拷贝。

使用展开操作符(…)

ES6已经有了用于数组解构赋值的 rest 元素,和实现的数组字面展开的操作符,这样进行的是浅拷贝。

const array = [
  "a",
  "c",
  "d", {
    four: 4
  },
];
const newArray = [...array]
console.log(newArray) // ["a", "c", "d", { four: 4 }]
console.log(newArray === array) // false
console.log(newArray[3] === array[3]) // true

JSON.parse(JSON.stringify(array))

可以使用 JSON.parse(JSON.stringify(object)) 对数组进行深拷贝。

const deepClone = (obj) => JSON.parse(JSON.stringify(obj))
// 循环引用对象
let arr = [{
  a: {
    b: 0,
    c: {
      d: 1
    }
  },
  e: 5
}]
let cloneArr = deepClone(arr)
console.log(cloneArr)
console.log(cloneArr === arr) // false
console.log(cloneArr[0] === arr[0]) // false

slice

普通赋值运算,只是两个指针指向同一块内存地址:

let arr = ["Strawberry", "Mango"]
let arr2 = arr
arr2 === arr // true

使用 slice 方法可实现数组的浅拷贝:

let arr = ["Strawberry", "Mango"]
let shallowCopy = arr.slice() // 浅拷贝
shallowCopy === arr // false

从其他类型的数据生成数组

使用 rest 生成数组

[...'foo'] // ["f", "o", "o"]

String => Array

Array.from('foo'); // ["f", "o", "o"]

Set => Array

let s = new Set(['foo', 'bar']);
Array.from(s); // ["foo", "bar"]

Map => Array

let m = new Map([[1, 2], [2, 4], [4, 8]]);
Array.from(m);
// [[1, 2], [2, 4], [4, 8]]

从参数直接生成数组

const toArray = (...args) => Array.from(args)
toArray(1, 2, 3); // [1, 2, 3]
// or
Array(1, 5, 6) // [1, 5, 6]

一些鲜为人知的事实

Array.prototype 是一个数组

Array.isArray(Array.prototype) // true
Array.isArray(Object.prototype) // false

Array.isArray 优于 instanceof

Array.isArray 能检测 iframes

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // [1,2,3]
Array.isArray(arr);  // true
arr instanceof Array; // false

length 是 Array 的实例属性

length 是 Array 的实例属性。返回或设置一个数组中的元素个数。该值是一个无符号 32-bit 整数,并且总是大于数组最高项的下标。

所以,可以通过以下方法创建数组:

Array.from({length: 5}, (v, i) => i); // [0, 1, 2, 3, 4]

Array.length 属性的属性特性:

属性特性 默认值
writable true
enumerable false
configurable false
  • Writable :如果设置为false,该属性值将不能被修改。
  • Configurable :如果设置为false,删除或更改任何属性都将会失败。
  • Enumerable :如果设置为 true ,属性可以通过迭代器 forfor...in 进行迭代。
let arr = [0,2]
Object.getOwnPropertyDescriptor(arr, 'length')
// {value: 2, writable: true, enumerable: false, configurable: false}

const 并不能冷冻数组中的元素

由于 数组 是一种引用类型的数据,所以 const 只能确保其指向的起始内存空间不变,但却可以对数组中的元素进行增删操作。

const arr = [0,2]
arr.push(1) // arr: [0, 2, 1]
arr = 1 // Uncaught TypeError: Assignment to constant variable.

深入理解 Array

数组代码片段

数组速查手册

MIT Licensed | Copyright © 2018-present 滇ICP备16006294号

Design by Quanzaiyu | Power by VuePress