`

Javascript数组类型检测:编写更强壮的isArray函数

阅读更多
在日常开发中,我们经常需要判断某个对象是否是数组类型的,在js中检测对象类型的常见的方法有几种:

1、typeof操作符。对于Function、String、Number、Undefined这几种类型的对象来说,不会有什么问题,但是针对Array的对象就没什么用途了:

alert(typeof null); // "object"
alert(typeof []); // "object"

2、instanceof操作符。此操作符检测对象的原型链是否指向构造函数的prototype对象,恩,听起来不错,应该可以解决我们的数组检测问题:

var arr = []; 
alert(arr instanceof Array); // true 

3、对象的constructor属性。除了instanceof,我们还可以利用每个对象都具有constructor的属性来判断其类型,于是乎我们可以这样做:

var arr = []; 
alert(arr.constructor == Array); // true

貌似后两个解决方案是无懈可击的,但真的是这样么?天有不测风云,当你在多个frame中来回穿梭的时候,令人沮丧的问题出现了:

var iframe = document.createElement('iframe'); 
document.body.appendChild(iframe); 
xArray = window.frames[window.frames.length-1].Array; 
var arr = new xArray(1,2,3); // [1,2,3] 
// 哎呀! 
arr instanceof Array; // false 
// 哎呀呀! 
arr.constructor === Array; // false

由于每个iframe都有一套自己的执行环境,跨frame实例化的对象彼此是不共享原型链的,因此导致上述检测代码失效!怎么办怎么办??嗯,javascript是动态语言,或许万金油“鸭式辨型”(duck type)可以助我们一臂之力“如果它走起路来像鸭子,叫起来也像鸭子,那就当他是鸭子吧”,同理,可以检测某些数组对象特有的能力来做判断,这个法子已经有人用了,比如Prototype框架,来看看它实现的Object.isArray方法:

isArray: function(object) { 
return object != null && typeof object == "object" &&
 'splice' in object && 'join' in object; 
}

isArray:”object,你有splice、join这两个数组特有的方法吗?”
object:“嗯,没错我有!”
isArray:“好吧,那你就是个数组了,哪怕你是冒充的,囧……”

var trickster = { splice: 1, join: 2 }; 
Object.isArray(trickster); // 假冒成功,耶

没错,这个解决方案给人的感觉有点别扭,任何一个具有'splice'和'join'属性的对象都能通过这个检测!怎么办怎么办怎么办??别着急,仔细想想,其实我们需要的是一个能取得对象实际类型,而且又能跨frame使用的方法即可。这不,细心的老外在翻阅ECMA262标准的时候发现了这个(btw,我也看了,怎么就没发现这个用途呢,囧):

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]"的字符串作为结果(看过ECMA标准的应该都知道,[[]]用来表示语言内部用到的、外部不可直接访问的属性,称为“内部属性”)。利用这个方法,再配合call,我们可以取得任何对象的内部属性[[Class]],然后把类型检测转化为字符串比较,以达到我们的目的。还是先来看看在ECMA标准中Array的描述吧:

ECMA-262 写道

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


于是乎,可以改写之前的isArray函数以利用这个特性,如下:

function isArray(o) {
  return Object.prototype.toString.call(o) === '[object Array]'; 
}


call改变toString的this引用为待检测的对象,返回此对象的字符串表示,然后对比此字符串是否是'[object Array]',以判断其是否是Array的实例。也许你要问了,为什么不直接o.toString()?嗯,虽然Array继承自Object,也会有toString方法,但是这个方法有可能会被改写而达不到我们的要求,而Object.prototype则是老虎的屁股,很少有人敢去碰它的,所以能一定程度保证其“纯洁性”:)

与前面几个方案不同,这个方法很好的解决了跨frame对象构建的问题,经过测试,各大浏览器兼容性也很好,可以放心使用。一个好消息是,很多框架,比如jQuery、Base2等等,都计划借鉴此方法以实现某些特殊的,比如数组、正则表达式等对象的类型判定,不用我们自己写了。
分享到:
评论
7 楼 yiminghe 2009-09-25  
Ext3 已经换成

isArray : function(v){
            return toString.apply(v) === '[object Array]';
        }



这种方法是现在确定最好的方法了

6 楼 02221021 2009-09-25  
汗,那似乎要加上七八个才最好.

还有ext的那个方法,似乎下面这样就挂了

var a = {
length: 1,
splice : function(){}
}


不如这样,加上判断'length'属性不可枚举.

function isArray(v){
return v && !v.propertyIsEnumerable('length') && typeof v.length == 'number' && typeof v.splice == 'function' ;
}

5 楼 kimmking 2009-09-25  
一个的偶然性太大:

extjs的:
return v && typeof v.length == 'number' && typeof v.splice == 'function';
4 楼 02221021 2009-09-24  
有个疑问
'splice' in object && 'join' in object
这里为什么要判断2个呢, 判断任意一个不就行了?

3 楼 toafu 2009-09-24  
dojo.isArray
2 楼 mingyuan0824 2009-04-09  
收藏了 
1 楼 鹤惊昆仑 2009-01-19  
确实,从frame上取到的数组对象从简单的类型判断上看起来就是不像数组了(IE、ff、chrome都有这现象),这个曾经迷惑我们项目组很多人,我们以为是IE的bug。从这点看dojo.isArray方法也是有缺陷的。

相关推荐

    JavaScript数组用法详解

    "JavaScript数组用法详解" JavaScript 数组是一种非常重要的数据结构,它是一种可以存储多个元素的集合。 JavaScript 数组的元素可以是任何类型,包括数字、字符串、对象、函数等。数组的长度可以动态地变化,可以...

    浅析JavaScript中的array数组类型系统_.docx

    首先,创建JavaScript数组有两种主要方式:字面量语法和`Array()`构造函数。字面量语法是最简洁的,只需在方括号中用逗号分隔值即可创建数组。例如: ```javascript var empty = []; // 空数组 var primes = [2, 3, ...

    Head First JavaScript(17年第1版).zip

    1 JavaScript速览:进入JavaScript的世界 阅读 2 编写代码:更进一步 3 函数简介:养成函数思维 4 让数据排排坐:数组 5 理解对象:对象镇之旅 6 与网页交互:了解DOM 7 类型、相等、转换等:系统...

    Javascript基础笔记

    + 对象类型:包括数组、对象、函数等。 * 数据类型检测:使用 typeof 运算符检测变量的数据类型。 * 数据类型转换:包括转换为字符串类型、数字类型、布尔类型等。 运算符 *比較运算符:包括 ==、!=、===、!== 等...

    Javascript数组Array方法解读

    首先,需要了解的是,JavaScript数组的所有方法都定义在Array.prototype上,这意味着所有数组的实例都可以使用这些方法。Array.prototype本身也是一个数组,它包含了数组的原型方法。 1. concat方法 concat方法用于...

    Effective JavaScript 编写高质量JavaScript代码的68个有效方法1

    《Effective JavaScript:编写高质量JavaScript代码的68个有效方法》是David Herman撰写的一本JavaScript编程指南,该书基于作者在Ecma的JavaScript标准化委员会的工作经验,深入探讨了JavaScript的内部工作机制、...

    javascript指南和函数式编程

    3. **数组和集合**:学习JavaScript中的数组操作,如map、filter、reduce等高阶函数的运用,以及Set和Map等ES6新增集合类型的使用。 4. **函数**:理解闭包、作用域和this的关键概念,学习箭头函数的语法和特性。 5....

    浅谈Javascript数组(推举)_.docx

    首先,创建JavaScript数组有两种主要方式:数组构造函数和数组字面量。例如: ```javascript var arr = new Array(20); // 创建一个长度为20的数组,但不包含任何元素 var arr1 = ["小伞", 1, true, undefined, [2, ...

    JavaScript中的数组特性介绍.docx

    JavaScript数组的一个显著特点是其成员可以是任何类型。这意味着同一个数组可以包含数字、字符串、对象甚至是其他数组。例如: ```javascript var o = [42, "Sample Text", {x:88}]; ``` 在这个例子中,数组`o`...

    21天学通JavaScript课后习题答案

    3. 函数:函数是JavaScript中可重用的代码块,可以接受参数并返回值。理解函数声明、函数表达式、箭头函数的区别及其用法,对于编写高效代码至关重要。 4. 对象与属性:JavaScript的对象是由键值对组成的,可以用来...

    JavaScript对象与数组参考大全

    本资料《JavaScript对象与数组参考大全》将深入探讨这两个重要的数据结构,帮助开发者更好地理解和运用它们。 对象在JavaScript中是一种复杂的数据结构,它们是键值对的集合,键可以是字符串或者符号,而值可以是...

    JavaScript对象与数组参考大全JavaScript语法结构

    二、JavaScript数组 1. 数组定义:数组是有序的数据集合,使用方括号 `[]` 定义,元素之间用逗号 `,` 分隔,如:`[element1, element2, ...]`。 2. 长度:数组的长度可通过 `.length` 属性获取,如 `array.length`。...

    javascript 函数式编程

    1. **模块化和可复用的代码**:通过将函数作为值,可以创建可重用的函数库,比如用于排序数组的自定义比较函数: ```javascript var myarray = [6, 7, 9, 1, -1]; myarray.sort(function(a, b) { return a - b; })...

    JavaScript 算法题

    编写一个函数,将数组 `arrs` 中的所有数字乘以 5,并返回新的数组。 **示例**: ```javascript let arrs = ['a', 'c', 6, 'e', 5, 3, 'd']; console.log(multiplyByFive(arrs)); // 输出 [30, 25, 15] ``` **实现...

    javascript中的数据类型检测方法详解.docx

    总的来说,理解和熟练运用这些数据类型检测方法,能够帮助开发者编写更可靠的JavaScript代码,避免因类型错误导致的程序异常。在进行类型检查时,应根据具体情况选择合适的方法,以确保代码的稳定性和可维护性。

    Unity3D教程:Array数组类的使用(二)1

    在实际项目中,根据需求选择合适的数组类型是非常重要的。 总的来说,理解并熟练使用Unity3D中的Array数组类对于编写高效、灵活的游戏脚本至关重要。无论是存储游戏对象、管理玩家分数还是处理其他游戏逻辑,数组都...

    JavaScript程序设计课件:Array对象.pptx

    Array对象可以用来创建各种类型的数组,无论是空数组、预设长度的数组还是包含特定元素的数组。以下是对Array对象的详细说明: 1. 创建Array对象: - 空数组:`var arr1 = new Array();` 或 `var arr1 = [];` - ...

    javascript数组去重方法分析

    这种方法基于`indexOf()`函数来检测数组中的元素是否已经存在。`indexOf()`返回指定元素在数组中首次出现的位置,如果未找到则返回-1。以下是具体步骤: 1. 创建一个新的空数组`new_arr`,用于存放去重后的元素。 2...

    javascript常用函数 javascript 常用库

    3. Underscore.js:与Lodash类似,提供了一套实用的函数集合,帮助开发者编写更简洁的代码。 4. Moment.js:处理日期和时间的强大库,提供了丰富的API来解析、验证、操作和显示日期。 5. Axios:一个基于Promise的...

Global site tag (gtag.js) - Google Analytics