在 Javascript 中,如何判断一个变量是否是数组?

最好的方式是用 ES5 提供的 Array.isArray() 方法(毕竟原生的才是最屌的):

var a = [0, 1, 2];
console.log(Array.isArray(a)); // true

但是鉴于低版本 IE 不支持 ES5,如需兼容,需要想想别的办法。

typeof

我们都知道,数组是特殊的对象,所以数组的 typeof 结果也是 object,而因为 null 的结果也是 object,所以如需用 typeof 运算符来判断数组,需要这么写:

var a = [0, 1, 2];
// 是 object 同时排除 null、排除纯对象
console.log(typeof a === 'object' && a !== null && Object.prototype.toString.call(a) !== '[object Object]');  // true

instanceof

来回忆下 instanceof 运算符的使用方式。a instanceof b,如果返回 true,表示 a 是 b 的一个实例。那么如果 a instanceof Array 返回 true,是不是就说明 a 是 数组类型呢?跟 instanceof 师出同门的还有 constructor,是否同样可以判断呢?

var a = [0, 1, 2];
console.log(a instanceof Array);  // true 就是数组?
console.log(a.constructor === Array); // true 数组?

答案是否定的,需要注意嵌套 frame 的情况。

index.htm 代码:

<iframe src='a.htm'></iframe>
<script>
    window.onload = function() {
      var a = window.frames[0].a;
      console.log(a instanceof Array);  // false
      console.log(a.constructor === Array);  // false
    };
</script>

a.htm 代码:

<script>
  window.a = [1, 2, 3];
</script>

我们看到 index.htm 代码中,变量 a 确实是一个数组,但是 a instanceof Array 的结果却是 false。

这是因为每个 frame 都有一套自己的执行环境,跨 frame 实例化的对象彼此不共享原型链。如果打印 a instanceof window.frames[0].Array,那么结果就是 true 了。

特性嗅探?

var a = [0, 1, 2];

if (a.sort) {
  // 是数组
}

也不靠谱,万一某个对象正好有值为 sort 的 key 呢?

var a = {sort: 'me'};

if (a.sort) {
  // 数组?
  // 其实我真的不是数组
}

正确的姿势是使用 Object.prototype.toString() 判断:

var a = [0, 1, 2];
console.log(Object.prototype.toString.call(a) === '[object Array]'); // true

事实上,这也是一些类库进行数组(甚至其他类型)判断的主流方式。

比如在 jQuery 中进行数组判断的相关代码(PS:摘自 jQuery 1.10.1,最近版本的 jQuery 只保留了 Array.isArray(),没有对不支持 ES5 的浏览器做兼容):

isArray: Array.isArray || function( obj ) {
    return jQuery.type(obj) === "array";
},

type: function( obj ) {
    if ( obj == null ) {
        return String( obj );
    }
    return typeof obj === "object" || typeof obj === "function" ?
        class2type[ core_toString.call(obj) ] || "object" :
        typeof obj;
},

jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
    class2type[ "[object " + name + "]" ] = name.toLowerCase();
});

代码很清晰,如支持原生的 Array.isArray(),则直接判断,不支持的话调用 toString() 进行判断。同时可以看到很多其他类型变量的判断也是基于 toString() 方法。当然这里说的 toString() 均是 Object 原型链上的 toString() 方法。

console.log(Object.prototype.toString.call(10));  // [object Number]
console.log(Object.prototype.toString.call('hello')); // [object String]
console.log(Object.prototype.toString.call(true));  // [object Boolean]
console.log(Object.prototype.toString.call([]));  // [object Array]
console.log(Object.prototype.toString.call({}));  // [object Object]
console.log(Object.prototype.toString.call(function(){}));  // [object Function]
console.log(Object.prototype.toString.call(/a/g));  // [object RegExp]
console.log(Object.prototype.toString.call(null));  // [object Null]
console.log(Object.prototype.toString.call(undefined)); // [object Undefined]
console.log(Object.prototype.toString.call(new Date())); // [object Date]

Object.prototype.toString() 为何能返回这样类型的字符串?

ECMA-262:

Object.prototype.toString( ) When the toString method is called, the following steps are taken:
1. Get the [[Class]] property of this object.
2. Compute a string value by concatenating the three strings “[object “, Result (1), and “]”.
3. Return Result (2) 

上面的规范定义了 Object.prototype.toString 的行为:首先,取得对象的一个内部属性[[Class]],然后依据这个属性,返回一个类似于 "[object Array]" 的字符串作为结果([[]]用来表示语言内部用到的、外部不可直接访问的属性,称为 "内部属性")。利用这个方法,再配合 call,我们可以取得任何对象的内部属性 [[Class]],然后把类型检测转化为字符串比较,以达到我们的目的。还是先来看看在 ECMA 标准中 Array 的描述吧:

new Array([ item0[, item1 [,…]]])
The [[Class]] property of the newly constructed object is set to “Array”.

所以 Javascript 中判断数组的函数可以这样写:

function isArray(a) {
  Array.isArray ? Array.isArray(a) : Object.prototype.toString.call(a) === '[object Array]';
}

Read More:

Javascript中判断数组的正确姿势的更多相关文章

  1. javascript中的数组扩展(一)

     javascript中的数组扩展(一) 随着学习的深入,发现需要学习的关于数组的内容也越来越多,后面将会慢慢归纳,有的是对前面的强化,有些则是关于前面的补充. 一.数组的本质    数组是按照次序排 ...

  2. JavaScript中判断为整数的多种方式

    之前记录过JavaScript中判断为数字类型的多种方式,这篇看看如何判断为整数类型(Integer). JavaScript中不区分整数和浮点数,所有数字内部都采用64位浮点格式表示,和Java的d ...

  3. JavaScript中判断整字类型最简洁的实现方法

    这篇文章主要介绍了JavaScript中判断整字类型最简洁的实现方法,本文给出多个判断整数的方法,最后总结出一个最短.最简洁的实现方法,需要的朋友可以参考下 我们知道JavaScript提供了type ...

  4. JavaScript中的数组和字符串

    知识内容: 1.JavaScript中的数组 2.JavaScript中的字符串 一.JavaScript中的数组 1.JavaScript中的数组是什么 数组指的是数据的有序列表,每种语言基本上都有 ...

  5. JavaScript中判断变量类型最简洁的实现方法以及自动类型转换(#################################)

    这篇文章主要介绍了JavaScript中判断整字类型最简洁的实现方法,本文给出多个判断整数的方法,最后总结出一个最短.最简洁的实现方法,需要的朋友可以参考下 我们知道JavaScript提供了type ...

  6. JavaScript中的数组创建

    JavaScript中的数组创建 数组是一个包含了对象或原始类型的有序集合.很难想象一个不使用数组的程序会是什么样. 以下是几种操作数组的方式: 初始化数组并设置初始值 通过索引访问数组元素 添加新元 ...

  7. JavaScript中Array(数组) 对象

    JavaScript中Array 对象 JavaScript中创建数组有两种方式 (一)使用直接量表示法: var arr4 = []; //创建一个空数组var arr5 = [20]; // 创建 ...

  8. 前端开发:Javascript中的数组,常用方法解析

    前端开发:Javascript中的数组,常用方法解析 前言 Array是Javascript构成的一个重要的部分,它可以用来存储字符串.对象.函数.Number,它是非常强大的.因此深入了解Array ...

  9. JavaScript中的数组详解

    JavaScript中的数组 一.数组的定义 数组是值的有序集合,或者说数组都是数据的有序列表. 二.创建数组 [字面量形式] 1.空数组 var arr=[]; 2.带有元素的数组 var arr= ...

随机推荐

  1. 微信网站设置右上角发送、分享的内容——.net版本

    一.首先了解本文要解决的问题: 公司前一段开发了移动网站,老板喜欢通过微信看,然后把看到的东西通过右上角的按钮分享出来,但老板发现分享出来的东西,没有指定的图片,没有描述:所以我就得老老实实干活了.. ...

  2. 十五天精通WCF——第十三天 用WCF来玩Rest

    在我们玩wcf的时候,都会潜意识的觉得wcf就是通过soap协议交换消息的,并且可以在basic,tcp,msmq等等绑定中任意切换, 牛逼的一塌糊涂,但是呢,如果说哪一天wcf不再使用soap协议, ...

  3. spring listener监听器

    1.Listener的定义与作用 监听器Listener就是在application,session,request三个对象创建.销毁或者往其中添加修改删除属性时自动执行代码的功能组件. Listen ...

  4. 安装Mysql 5.7.1

    现在安装MySQL变成了一件非常人性化的事情,因为有了MySQL-installer这个工具,它可以帮助我们全程安装MySQL.     下面我来简单介绍一下如何使用,以供新手学习:     .首先下 ...

  5. win7下硬盘安装ubuntu

    首先还是分区,在计算机上右键--管理--磁盘管理.装Ubuntu分配的硬盘大小最好是(20G以上)不要太小,这里请注意,Ubuntu和Windows文件系统完全不同,所以我们划好要给Ubuntu的分区 ...

  6. 使用dwr时动态生成table的一个小技巧

    这篇随笔是我在07年写的,因为当时用了自己建设的blog,后来停止使用了,今天看到备份数据库还在,恢复出来放到这里.留着记录用. 我在使用DWR时,试了很多次都无法在动态生成的table中的一个或多个 ...

  7. Jade模板引擎(一)之Attributes

    目录: Attributes Boolean Attributes Style Attributes Class Attributes &Attributes Attributes jade中 ...

  8. cocos2d-x之 利用富文本控件解析xhml标签(文字标签,图片标签,换行标签,标签属性)

    执行后效果: 前端使用: 后台SuperRichText解析code void SuperRichText::renderNode(tinyxml2::XMLNode *node){ while (n ...

  9. Ubuntu下安装Pyenv不成功,求指教

    虚拟机:VMware12.0 操作系统:Ubuntu16.04 LTS (新安装系统) 已经按照网上的步骤: 1.安装git: $sudo apt-get install git 2.安装依赖包: $ ...

  10. System V IPC(1)-消息队列

    一.概述                                                    System V三种IPC:消息队列,信号量,共享内存.这三种IPC最先出现在AT&am ...