javascript 伪数组转数组

272 阅读2分钟

伪数组

JavaScript 语言中伪数组具备两个特征:

  • 属性名必须是数字的字符串
  • 具有 length 属性

伪数组不具备数组独有的 pushpop等方法,但是我们可以通过下标 args[index] 这种方式获取指定索引位置的值,虽然很简单,这也是将伪数组转化为真正数组的机理。

如何将伪数组转成真数组

  • 先来了解一下 slice 方法得内部实现
Array.prototype.slice = (start, end) => {
  let O = ToObject(this)
  let A = new Array()
  let lenVal = O.length
  let len = ToUnit32(lenVal)
  let relativeStart = ToInteger(start)
  let k, final, relativeEnd
  if (relativeStart < 0) {
    k = max(len + relativeStart, 0)
  } else {
    k = min(relativeStart, len)
  }
  if (end === undefined) {
    relativeEnd = len
  } else {
    relativeEnd = ToInteger(end)
  }
  if (relativeEnd < 0) {
    final = max(len + relativeEnd, 0)
  } else {
    final = min(relativeEnd, len)
  }
  let n = 0
  while (k < final) {
    let Pk = ToString(k)
    let kPresent = O.hasOwnProperty(Pk)
    if (kPresent) {
      let kValue = O[Pk]
      Object.defineProperty(A, ToString(n), {
        value: kValue,
        writable: true,
        enumerable: true,
        configurable: true
      })
    }
    k++
    n++
  }
  return A
}

slice 方法不要求 this 必须是数组,因此类数组对象也可以调用该方法,在本例中入参 startend 均为undefined,实际上是根据 类数组对象 的 length 属性,从 0length-1 去把类数组对象对应的值取出来,放到前面声明的数组 A里,最终再 return A

也可以简化一下 slice 的内部实现,例如

Array.prototype.slice = function(start, end) {
  var result = new Array()
  start = start || 0
  end = end || this.length
  for (var i = start; i < end; i++) {
    result.push(this[i])
  }
  return result
}
  • 方法一: 使用 slice 方法,配合 call或者apply
const lis = document.getElementsByTagName('li')

[].slice.call(lis)
[].slice.apply(lis)
Array.prototype.slice.call(lis)
Array.prototype.slice.apply(lis)
  • 方法二:使用 slice 方法,配合 bind
const lis = document.getElementsByTagName('li')

const switchArrayFunc = Function.prototype.call.bind(Array.prototype.slice)

switchArrayFunc(lis)

方法二和方法一的原理都一样,都是伪数组去调用 slice

  • 方法三:...解构赋值
const lis = document.getElementsByTagName('li')

[...lis]
  • 方法四:Array.form()
const lis = document.getElementsByTagName('li')

Array.from(lis)
  • 方法五:万变不离其中 for 循环
const lis = document.getElementsByTagName('li')

const array = []
for(let i = 0; i < lis.length; i++) {
  array[i] = lis[i]
}