解开那一层面纱,js类数组的小秘密(上篇)

前言:

在开发或者面试中,我们经常会遇到或者被问到关于“类数组”的问题,什么是类数组?什么是类数组对象?js里面哪些可以称为类数组?类数组又有哪些特点?怎么把类数组转成js数组?那么既然这个问题被反复问到,以及在我们的编码过程中难免会遇到类数组,那我们应该怎么去操作类数组呢,类数组又隐含着多少知识点呢下面我们开始探讨下,可能自己收集的不是那么全面,并且有什么不对的地方也希望被指出,一起学习一起进步

1. 想想js里面哪些可以称为类数组?

首先我也列出来(部分):字符串,arguments, document.getElementByClassName获取到的元素集合等...

接下来是几张上面列出来的类数组的在控制台打印出来的截图:

image
image
image

在上面几张截图里面都是被可以被称为类数组几种类型,那他们有什么共同特点呢,什么样的才能被称为类数组

2.类数组的定义 (ArrayLike)

其实在网上找了很多资料也没有找到,关于js里面类数组的官方定义,但是这不代表我们就不能定义一种具有特定结构的数据类型的叫法或者昵称

根据网上以及自己理解,总结下来满足具有以下两点特性的结构类型我们称之为“类数组”或者有些叫法也叫“伪数组”,what is this in English? ArrayLike.

  • 拥有length属性,其它属性(索引)为非负整数
  • 不具有数组所具有的方法(非必须)

上面的定义是非官方的,但是很具有参考性,一般情况下在网络上的资料以及我们在使用或者判定过程中都是遵循这样的一些约定俗成的定义。

再回头看上面的截图可以看出上面列出的几种数据类型,都是满足上面的条件。

3.如何判断给定的类型是否是类数组(类数组对象)?

我们可以根据关于类数组的定义来判断一个给定的类型是不是类数组


function isArrayLike(arrlike) {
      return typeof arrlike !== "undefined" && arrlike.length > 0;
}

这是我自己编写的判断逻辑,来我们看看著名的类库“鲁大师”(lodash)是怎么做的,

var MAX_SAFE_INTEGER = 9007199254740991;

function isLength(value) {
      return typeof value == 'number' &&
        value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
}

function isArrayLike(value) {
    return value != null && isLength(value.length) && !isFunction(value);
}

比较一下,比我自己写的要严谨,虽然在我们的业务场景下不会遇到这么大的值,但是终究还是严谨。
上面是判断类数组,下面在提供一下判断类数组对象的方法,同样来自于“鲁大师”

function isObjectLike(value) {
      return value != null && typeof value == 'object';
}

function isArrayLikeObject(value) {
      return isObjectLike(value) && isArrayLike(value);
}

其实就是在原来类数组的判断上加了关于对象的判断。

4.类数组转成数组

顾名思义,之所以我称之为类数组,肯定是有一定原因的不仅是“长得像”(有人还说我长得像雨神, 然后我就喜欢听雨神的歌了),
首先我们看一下类数组的遍历和数组的遍历比较:

let arr = ["a", "b", "c"],
    arrLike = {
        0: "a",
        1: "b",
        2: "c",
        length: 3
    },
    newArr = [],
    newArrLikeArr = [];

for (let i = 0, j = arr.length; i < j; i++ ) {
    newArr.push(arr[i]);
}
console.log(newArr); // ["a", "b", "c"]

for (let i = 0, j = arrLike.length; i < j; i++ ) {
    newArrLikeArr.push(arrLike[i]);
}
console.log(newArrLikeArr); // ["a", "b", "c"]

可以看出除了变量的,命名不一样的以外,好像别的什么都一样,果然是“长得像”,既然长得这么像,但是类数组看起来好像是很单薄的,因为他身上只有属性,没有像数组一样可以通过一些方法来操作里面的属性以及值(这时我们把数组的索引值以及元素当做键值对),其实从上面的对比我们可大胆的猜一下,如果数组的方法内部是通过取length值以及对象取值的形式arr["1"]来做操作的,是不是我们就可以让类数组去调用数组上面的方法来达到操作自身的目的呢?
既然上面都是我们的猜测,那我们看下数组方面的方法内部实现,是不是如我们所想,虽然我们看不到数组原生方法的源码,但是我们可以从开源的polyfill上面找到我们要的答案:

  Array.prototype.find = function (predicate, thisValue) {
        var arr = Object(this);
        if (typeof predicate !== 'function') {
            throw new TypeError();
        }
        for(var i=0; i < arr.length; i++) {
            if (i in arr) {  
                var elem = arr[i];
                if (predicate.call(thisValue, elem, i, arr)) {
                    return elem; 
                }
            }
        }
        return undefined;
   }

正如我们所想,看上面代码,如果我们操作的是类数组对象,同样能达到相同的效果。
那么我们就可以让类数组对象借用数组上面的方法了,下面这段代码是不是很熟悉呢:

function Foo() {
     var args = [].slice.call(arguments);
      .... // something do
}

es6之前我们做一个函数柯里化或者写一些不定参数的函数或者根据参数个数来实现面向对象编程里面的重载方法的时候,会经常用到这样的写法。当然在es6出来以后,我们有了一种更为简单的方获取参数:

function foo(...arguments) {
        console.log(arguments);
}
foo(1, 2, 3); // [1, 2, 3]

出了上面非常常用的一种方法来实现类数组对象转为数组的方式,我们还有另外一种:

Array.prototype.splice.call({
        length: 2, 
        0: "a", 
        1: "b"
}, 0); // ["a", "b"]

上面只是了类数组怎么转为数组,既然上面已经讨论了,类数组与数组如此的“长得像”,那么有些情况下,我们在操作类数组的时候,是不是不用先转为数组,而是直接借用数组的方法来操作类数组对象呢。答案是肯定的,那么是不是数组上面所有的方法,类数组对象都可以借用的?或者我们在编码过程中怎么去实现一个类数组对象?jQuery的类数组对象是怎么构造的呢?又和我们平时创建的类数组对象有什么不同呢?带着这些疑问我们一起继续探讨“js类数组更深层的秘密”。
请移步 解开那一层面纱,js类数组的小秘密(下篇)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容