你好,我是一个伪数组

时间:2014-7-15 作者:剧中人

数组在JS里是一种神奇的存在,就像你所知道的一样,typeof([1,2])的结果是"object"

说到这里就不得不提到JS里的五种基本数据类型(不考虑function):undefined、null、boolean、number、string。和第六种复杂的数据类型object。object本质是一组由键值构成的对象,我们所熟知的dom节点、数组、正则都隶属于object。

尝试做件事情

在富javascript应用里,js管理数据是相当常见的,一般存储数据时会使用这种方式(以用户列表为例)

var users = [
  {'id' : 1001, 'name' : 'Jack', 'age' : 23},
  {'id' : 1002, 'name' : 'Joys', 'age' : 18},
  {'id' : 1003, 'name' : 'Gate', 'age' : 34}
];

为了是创建的用户信息更符合业务需求,于是乎我们很容易写出下面这个类

//用户类
function USERS(){
  this.users = [];
}
USERS.prototype['add'] = function(item){
  //对item执行校验,过滤等操作
  //……
  this.users.push(item)
};

这种数据模型已经可以很高效的工作了,但是站在使用者的视角来看(见下一个code),操作用户信息时的深度是不是还能再降低一点呢?能不能让实例化后的对象,就是数据本身,而非将数据挂载到users属性下呢?

//实例化一个对象
var myUserList = new USERS();
myUserList.add({'id' : 1001, 'name' : 'Jack', 'age' : 23});
//读取第一条用户信息
console.log(myUserList.users[0]);

伪数组开始啦

终于扯到伪数组啦。要做到实例化后的对象,最直观地以数组的形式呈现,这就涉及到如何把对象伪装成数组。

这里提到的伪数组是指。对象具有length属性,且值为数字(包含字符类型的数字),以及从零开始的有序下标。如下面这个变量arr,一个赤裸裸的对象,却是一个最标准的伪数组。

var arr = {
  '0' : '000',
  '1' : '111',
  '2' : '222',
  'length' : 3,
  'name' : 'an object looks like array',
  'type' : 'object'
}
$.each(arr,function(key,value){
  console.log(key,value)
});
 /**
  * 打印结果,并不包括length、name、type属性
  *  0,000
  *  1,111
  *  2,222
  **/

看到这里应该就豁然开朗了,只要严格遵循length与下标在数组中的逻辑,就可以轻松地构建出一个伪数组,那如何在类的定义时就构建为伪数组,小剧来改写一下USERS类。

//用户类
function USERS(){
  //初始化长度
  length = 0;
}
//修改原型对象为数组
USERS.prototype = [];
USERS.prototype['add'] = function(item){
  //对item执行校验,过滤等操作
  //……
  //借用数组原型链上的push方法,完成对增加操作
  Array.prototype.push.call(this, item); 
};

此时类的使用者看到的就是下面这样纸,区别仅仅在于读取用户信息时不需要再借助子属性。回想下通过选择器实例化的jquery对象,再看下这样一个对象,是不是有种豁然开朗的感觉。

//实例化一个对象
var myUserList = new USERS();
myUserList.add({'id' : 1001, 'name' : 'Jack', 'age' : 23});
//读取第一条用户信息
console.log(myUserList[0]);

可能到了这儿,你感觉利用伪数组降低对象结构深度的意义不大,但对于类的使用者来说,可以用尽可能少的学习成本,来使用尽可能多的经过深度定制的数据类型。


PS:最近又在造轮子,模仿jquery的API在写一个类库lorry.js,其中最核心的构造函数,就涉及到了对伪数组的实现,深深感到了JS的精妙与猥琐,与君共品。

PPS:经过一段时间的学习,了解到我这里提到的伪数组,有一个很专业很形象的名词,称之为类数组对象,作为数组在JS中的一种补充,的确用处很广。——2014-12-09。