用javascript简单构建一个类数组对象

149 阅读3分钟

最近在重写web核心库文件(基于React),预期新框架开发模式上贴近小程序原生架构(开发性一致),组件操作便利性贴近JQUERY。

JQUERY有一个非常方便的特性即元素查找,能够返回一个JQUERY封装的对象,是一个类数组对象,可以批量处理查找到的所有元素及定义一系列的方法,新框架中需要用到这样的元素查找能力。

什么是类数组对象

看下面的列子

function test(){
  console.log(arguments[0])  // a
  console.log(arguments[1])  // b
  console.log(arguments.length)  // 2
  console.log(argument)
}

test('a', 'b')

arguments既是一个类数组,再看一个JQUERY的例子

上例是JQUERY元素查找的结果,总结一下什么是类数组

一个类数组对象:

  • 具有:指向对象元素的数字索引下标以及 length 属性告诉我们对象的元素个数
  • 默认不具有:诸如 push 、 forEach 以及 indexOf 等数组对象具有的方法

这里说明默认不具有Array的方法,当然可以通过一些操作使其能够使用Array的方法

如何构建类数组

let obj = {}
obj[0] = '...'
obj[1] = '...'
obj.length = 2

这就是一个很基础的类数组,是不是很简单,打印一下

接下来让他与jquery更接近一点

let obj = {}
obj[0] = '...'
obj[1] = '...'
obj.length = 2
obj.splice = function(){}

上面这个打印就与jquery基本一致了,它不是一个数组,但又具有数组的一些特性。

其实上面的打印是一个console.log的bug,设置了splice的对象,打印效果和数组是一样一样的,但其实它仍是对象

接下来我们为该对象绑定一些数组方法及自定义方法

let obj = {}
obj[0] = '加油,'
obj[1] = '川建国,'
obj.length = 2
obj.forEach = [].forEach
obj.push = [].push
obj.join = function(){
  let str = ''
  this.forEach(item=>{
    str+=item
  })
  return str
}
obj.push('注意安全')
let mystr = obj.join() // 加油,川建国,注意安全

join是自定义方法,forEach/push是借用了Array的原生方法。

通过上例发现能够很简单的构建一个类数组对象,只是平时很少会用到,类数组的好处是可以很方便的处理集合数据,能够自由的为该对象指定array方法及自定义方法。

定义原型链方法

上面例子中都是显示指定方法,打印的时候总是不那么完美,观察jqurey的例子,扩展方法都是定义在 原型链上,因此我们也要定义原型链方法,以求达到完美

prototype和__proto__

下面一段文字摘自这里,个人觉得很清晰的概述了这两者的不同,因此我们需要使用__proto__(es6版本)来定义原型链方法

prototype是函数才有的属性

具体原因,可以看看阮一峰大神的这篇文章Javascript继承机制的设计思想,里面介绍了prototype的设计由来。

__proto__是每个对象都有的属性

它不是一个规范属性,虽然一些浏览器目前仍然支持它。__proto__属性已在ES6中标准化,现在更推荐使用Object.getPrototypeOf/Reflect.getPrototypeOf和Object.setPrototypeOf/Reflect.setPrototypeOf

let obj = {}
obj[0] = '加油,'
obj[1] = '川建国,'
obj.length = 2

// 开始定义原型链方法  
Object.setPrototypeOf(obj, {
  splice: [].splice,
  push: [].push,
  forEach: [].forEach,
  join: function(){
    let str = ''
    this.forEach(item=>{
      str+=item
    })
    return str
  }
})

console.log(obj)

完工!