原生如何检测变量是不是是一个数组的几种方法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原生如何检测变量是不是是一个数组的几种方法相关的知识,希望对你有一定的参考价值。
参考技术A javascript中检测对象的方法1.typeof操作符
这种方法对于一些常用的类型来说那算是毫无压力,比如Function、String、Number、Undefined等,但是要是检测Array的对象就不起作用了。
代码如下:
alert(typeof null); // "object"
alert(typeof function ()
return 1;
); // "function"
alert(typeof '梦龙小站'); // "string"
alert(typeof 1); // "number"
alert(typeof a); // "undefined"
alert(typeof undefined); // "undefined"
alert(typeof []); // "object"
2.instanceof操作符
这个操作符和JavaScript中面向对象有点关系,了解这个就先得了解JavaScript中的面向对象。因为这个操作符是检测对象的原型链是否指向构造函数的prototype对象的。
var arr = [1,2,3,1];
alert(arr instanceof Array); // true
3.对象的constructor属性
除了instanceof,每个对象还有constructor的属性,利用它似乎也能进行Array的判断。
代码如下:
var arr = [1,2,3,1];
alert(arr.constructor === Array); // true
第2种和第3种方法貌似无懈可击,但是实际上还是有些漏洞的,当你在多个frame中来回穿梭的时候,这两种方法就亚历山大了。由于每个iframe都有一套自己的执行环境,跨frame实例化的对象彼此是不共享原型链的,因此导致上述检测代码失效!
代码如下:
var iframe = document.createElement('iframe'); //创建iframe
document.body.appendChild(iframe); //添加到body中
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // 声明数组[1,2,3]
alert(arr instanceof Array); // false
alert(arr.constructor === Array); // false
检测数组类型方法
以上那些方法看上去无懈可击,但是终究会有些问题,接下来向大家提供一些比较不错的方法,可以说是无懈可击了。
1.Object.prototype.toString
Object.prototype.toString的行为:首先,取得对象的一个内部属性[[Class]],然后依据这个属性,返回一个类似于"[object
Array]"的字符串作为结果(看过ECMA标准的应该都知道,[[]]用来表示语言内部用到的、外部不可直接访问的属性,称为“内部属性”)。利用这
个方法,再配合call,我们可以取得任何对象的内部属性[[Class]],然后把类型检测转化为字符串比较,以达到我们的目的。
代码如下:
function isArrayFn (o)
return Object.prototype.toString.call(o) === '[object Array]';
var arr = [1,2,3,1];
alert(isArrayFn(arr));// true
call改变toString的this引用为待检测的对象,返回此对象的字符串表示,然后对比此字符串是否是'[object
Array]',以判断其是否是Array的实例。为什么不直接o.toString()?嗯,虽然Array继承自Object,也会有
toString方法,但是这个方法有可能会被改写而达不到我们的要求,而Object.prototype则是老虎的屁股,很少有人敢去碰它的,所以能一定程度保证其“纯洁性”:)
JavaScript 标准文档中定义: [[Class]] 的值只可能是下面字符串中的一个: Arguments,
Array, Boolean, Date, Error, Function, JSON, Math, Number, Object,
RegExp, String.
这种方法在识别内置对象时往往十分有用,但对于自定义对象请不要使用这种方法。
2.Array.isArray()
ECMAScript5将Array.isArray()正式引入JavaScript,目的就是准确地检测一个值是否为数组。IE9+、
Firefox 4+、Safari 5+、Opera 10.5+和Chrome都实现了这个方法。但是在IE8之前的版本是不支持的。
3.较好参考
综合上面的几种方法,有一个当前的判断数组的最佳写法:
代码如下:
var arr = [1,2,3,1];
var arr2 = [ abac : 1, abc : 2 ];
function isArrayFn(value)
if (typeof Array.isArray === "function")
return Array.isArray(value);
else
return Object.prototype.toString.call(value) === "[object Array]";
alert(isArrayFn(arr));// true
alert(isArrayFn(arr2));// true
如何检测变量是不是为数组
【中文标题】如何检测变量是不是为数组【英文标题】:How to detect if a variable is an array如何检测变量是否为数组 【发布时间】:2010-11-06 16:53:06 【问题描述】:确定 JavaScript 中的变量是否为数组的最佳事实上的标准跨浏览器方法是什么?
在网上搜索有很多不同的建议,有的不错,有的无效。
例如,下面是一个基本的方法:
function isArray(obj)
return (obj && obj.length);
但是,请注意如果数组为空,或者 obj 实际上不是数组但实现了长度属性等会发生什么。
那么就实际工作、跨浏览器和仍然高效执行而言,哪种实现是最好的?
【问题讨论】:
这不会在字符串上返回 true 吗? 给出的示例并不是要回答问题本身,只是说明如何解决问题的示例-在特殊情况下通常会失败(例如这个,因此“但是,请注意...”)。 @James:在大多数浏览器中(IE 除外),字符串是类似数组的(即可以通过数字索引访问) 不能'相信这很难做到...... How do you check if a variable is an array in JavaScript? 的可能重复项 【参考方案1】:为什么不直接使用
Array.isArray(variable)
这是执行此操作的标准方法(感谢 Karl)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
【讨论】:
这适用于 Node.js 和浏览器,不仅仅是 CouchDB:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…【参考方案2】:ECMAScript 第 5 版的到来为我们提供了测试变量是否为数组的最可靠的方法,Array.isArray():
Array.isArray([]); // true
虽然此处接受的答案适用于大多数浏览器的框架和窗口,但不适用于 Internet Explorer 7 及更低版本,因为从不同窗口调用数组的 Object.prototype.toString
将返回[object Object]
,不是[object Array]
。 IE 9 似乎也回归到了这种行为(请参阅下面的更新修复)。
如果您想要一个适用于所有浏览器的解决方案,您可以使用:
(function ()
var toString = Object.prototype.toString,
strArray = Array.toString(),
jscript = /*@cc_on @_jscript_version @*/ +0;
// jscript will be 0 for browsers other than IE
if (!jscript)
Array.isArray = Array.isArray || function (obj)
return toString.call(obj) == "[object Array]";
else
Array.isArray = function (obj)
return "constructor" in obj && String(obj.constructor) == strArray;
)();
它并非完全牢不可破,但只有努力破坏它的人才能将其破坏。它可以解决 IE7 及更低版本和 IE9 中的问题。 The bug still exists in IE 10 PP2,但它可能会在发布前修复。
PS,如果您不确定解决方案,那么我建议您根据自己的内心内容对其进行测试和/或阅读博客文章。如果您不习惯使用条件编译,还有其他潜在的解决方案。
【讨论】:
The accepted answer 在 IE8+ 中可以正常工作,但在 IE6,7 中不行 @Pumbaa80:你是对的 :-) IE8 解决了它自己的 Object.prototype.toString 的问题,但是测试了一个在 IE8 文档模式下创建的数组,该数组被传递给 IE7 或更低版本的文档模式,问题依旧。我只测试了这种情况,而不是相反。我已编辑将此修复程序仅应用于 IE7 及更低版本。 WAAAAAAA,我讨厌 IE。我完全忘记了不同的“文档模式”或“分裂模式”,就像我要称呼它们的那样。 虽然想法很棒而且看起来不错,但在带有弹出窗口的 IE9 中这对我不起作用。它为开瓶器创建的数组返回 false... 有 IE9 兼容的解决方案吗? (问题似乎是 IE9 实现了 Array.isArray 本身,它在给定的情况下返回 false,而它不应该返回。 @Steffen:很有趣,所以isArray
的本机实现不会从其他文档模式中创建的数组返回true?当我有时间时,我将不得不对此进行研究,但我认为最好的办法是在 Connect 上提交一个错误,以便可以在 IE 10 中修复它。【参考方案3】:
将Array.isArray(obj)
替换为obj.constructor==Array
样本:
Array('44','55').constructor==Array
return true (IE8 / Chrome)
'55'.constructor==Array
return false (IE8/Chrome)
【讨论】:
你为什么要用一个可怕的函数替换正确的函数?【参考方案4】:一旦你确定它是一个数组,你打算如何处理它?
例如,如果您打算枚举包含的值,如果它看起来像一个数组,或者如果它是一个用作哈希表的对象,那么下面的代码会得到你想要的(当闭包函数返回“未定义”以外的任何内容时,此代码将停止。请注意,它不会迭代 COM 容器或枚举;这留给读者作为练习):
function iteratei( o, closure )
if( o != null && o.hasOwnProperty )
for( var ix in seq )
var ret = closure.call( this, ix, o[ix] );
if( undefined !== ret )
return ret;
return undefined;
(注意:“o != null”测试 null 和 undefined)
使用示例:
// Find first element who's value equals "what" in an array
var b = iteratei( ["who", "what", "when" "where"],
function( ix, v )
return v == "what" ? true : undefined;
);
// Iterate over only this objects' properties, not the prototypes'
function iterateiOwnProperties( o, closure )
return iteratei( o, function(ix,v)
if( o.hasOwnProperty(ix) )
return closure.call( this, ix, o[ix] );
)
【讨论】:
虽然答案可能很有趣,但它与问题没有任何关系(顺便说一句:通过for..in
遍历数组是不好的[tm])
@Christoph - 当然可以。必须有一些理由来决定某个东西是否是一个数组:因为你想对这些值做一些事情。最典型的事情(至少在我的代码中)是映射、过滤、搜索或以其他方式转换数组中的数据。上面的函数正是这样做的:如果传递的东西有可以迭代的元素,那么它就会迭代它们。如果不是,那么它什么也不做,并且无害地返回 undefined。
@Christoph - 为什么用 for..in bad[tm] 迭代数组?你还会如何迭代数组和/或哈希表(对象)?
@James: for..in
迭代对象的可枚举属性;你不应该将它与数组一起使用,因为:(1)它很慢; (二)不能保证维持秩序; (3) 它将包含在对象或其任何原型中设置的任何用户定义的属性,因为 ES3 不包含任何设置 DontEnum 属性的方法;可能还有其他问题让我忘记了
@Christoph - 另一方面,对于稀疏数组,使用 for(;;) 将无法正常工作,并且它不会迭代对象属性。由于您提到的原因,#3 被认为是 Object 的错误形式。另一方面,就性能而言,您是正确的:for..in 在 1M 元素数组上比 for(;;) 慢约 36 倍。哇。不幸的是,不适用于我们的主要用例,即迭代对象属性(哈希表)。【参考方案5】:
Crockford 在“The Good Parts”的第 106 页有两个答案。第一个检查构造函数,但会在不同的框架或窗口中给出假阴性。这是第二个:
if (my_value && typeof my_value === 'object' &&
typeof my_value.length === 'number' &&
!(my_value.propertyIsEnumerable('length'))
// my_value is truly an array!
Crockford 指出此版本会将arguments
数组识别为数组,即使它没有任何数组方法。
他对这个问题的有趣讨论从第 105 页开始。
还有更多有趣的讨论(发布好的部分)here,其中包括此提案:
var isArray = function (o)
return (o instanceof Array) ||
(Object.prototype.toString.apply(o) === '[object Array]');
;
所有的讨论让我永远不想知道某个东西是否是一个数组。
【讨论】:
这将在 IE 中中断字符串对象并排除字符串原语,这些原语在 IE 中是类似数组的;如果你想要实际的数组,检查 [[Class]] 会更好;如果你想要类似数组的对象,检查太严格了 @Christoph——我通过编辑添加了更多内容。有趣的话题。【参考方案6】:JS中对象的类型检查是通过instanceof
完成的,即
obj instanceof Array
如果对象跨越帧边界,这将不起作用,因为每个帧都有自己的Array
对象。您可以通过检查对象的内部 [[Class]] 属性来解决此问题。要获取它,请使用Object.prototype.toString()
(ECMA-262 保证可以使用它):
Object.prototype.toString.call(obj) === '[object Array]'
这两种方法都只适用于实际数组,而不适用于类似数组的对象,如 arguments
对象或节点列表。由于所有类似数组的对象都必须有一个数字 length
属性,我会像这样检查这些:
typeof obj !== 'undefined' && obj !== null && typeof obj.length === 'number'
请注意,字符串将通过此检查,这可能会导致问题,因为 IE 不允许通过索引访问字符串的字符。因此,您可能希望将 typeof obj !== 'undefined'
更改为 typeof obj === 'object'
以排除类型与 'object'
不同的原语和宿主对象。这仍然会让字符串对象通过,必须手动排除。
在大多数情况下,您真正想知道的是您是否可以通过数字索引遍历对象。因此,检查对象是否具有名为 0
的属性可能是个好主意,这可以通过以下检查之一来完成:
typeof obj[0] !== 'undefined' // false negative for `obj[0] = undefined`
obj.hasOwnProperty('0') // exclude array-likes with inherited entries
'0' in Object(obj) // include array-likes with inherited entries
转换为对象对于类似数组的原语(即字符串)正常工作是必要的。
这是对 JS 数组进行稳健检查的代码:
function isArray(obj)
return Object.prototype.toString.call(obj) === '[object Array]';
和可迭代(即非空)类数组对象:
function isNonEmptyArrayLike(obj)
try // don't bother with `typeof` - just access `length` and `catch`
return obj.length > 0 && '0' in Object(obj);
catch(e)
return false;
【讨论】:
对 js 数组检查的最新技术的伟大总结。 从 MS JS 5.6 (IE6?) 开始,“instanceof”运算符在针对 COM 对象 (ActiveXObject) 运行时会泄漏大量内存。尚未检查 JS 5.7 或 JS 5.8,但这可能仍然适用。 @James:有趣——我不知道这个泄漏;无论如何,有一个简单的解决方法:在 IE 中,只有原生 JS 对象有hasOwnProperty
方法,所以只需在 instanceof
前面加上 obj.hasOwnProperty &&
;另外,这仍然是IE7的问题吗?我通过任务管理器进行的简单测试表明,在最小化浏览器后内存被回收......
@Christoph - 不确定 IE7,但 IIRC 这不在 JS 5.7 或 5.8 的错误修复列表中。我们将底层 JS 引擎托管在服务端的服务中,因此最小化 UI 是不适用的。
@TravisJ:见ECMA-262 5.1, section 15.2.4.2;内部类名按照惯例是大写的 - 请参阅section 8.6.2【参考方案7】:
没有足够的引用相等的构造函数。有时他们对构造函数有不同的引用。所以我使用它们的字符串表示。
function isArray(o)
return o.constructor.toString() === [].constructor.toString();
【讨论】:
被constructor:toString:function() return "function Array() [native code] ";
愚弄【参考方案8】:
在w3school 上有一个例子应该很标准。
为了检查一个变量是否是一个数组,他们使用类似于这个的东西
function arrayCheck(obj)
return obj && (obj.constructor==Array);
在 Chrome、Firefox、Safari、ie7 上测试
【讨论】:
使用constructor
进行类型检查太脆弱了;改用建议的替代方法之一
你为什么这么认为?关于脆?
@Kamarey: constructor
是原型对象的常规 DontEnum 属性;只要没有人做任何愚蠢的事情,对于内置类型来说这可能不是问题,但对于用户定义的类型来说,这很容易;我的建议:总是使用instanceof
,它检查原型链并且不依赖可以任意覆盖的属性
谢谢,在这里找到另一种解释:thinkweb2.com/projects/prototype/…
这不可靠,因为 Array 对象本身可以被自定义对象覆盖。【参考方案9】:
从大师 John Resig 和 jquery 那里窃取数据:
function isArray(array)
if ( toString.call(array) === "[object Array]")
return true;
else if ( typeof array.length === "number" )
return true;
return false;
【讨论】:
第二个测试对于字符串也会返回 true:typeof "abc".length === "number" // true 另外,我猜你永远不应该硬编码类型名称,比如“数字”。尝试将其与实际数字进行比较,例如 typeof(obj) == typeof(42) @mtod:为什么不应该对类型名称进行硬编码?毕竟typeof
的返回值是标准化的?【参考方案10】:
可以在PHPJS site 上找到该功能的最佳研究和讨论版本之一。您可以链接到软件包,也可以转到function directly。我强烈推荐该站点以在 JavaScript 中构建良好的 PHP 函数等效项。
【讨论】:
【参考方案11】:jQuery 实现了一个 isArray 函数,这表明最好的方法是
function isArray( obj )
return toString.call(obj) === "[object Array]";
(sn-p 取自 jQuery v1.3.2 - 稍作调整以脱离上下文)
【讨论】:
他们在 IE 上返回 false (#2968)。 (来自jquery源) jQuery源码中的那条注释似乎是指isFunction函数,而不是isArray 你应该使用Object.prototype.toString()
- 这不太可能打破【参考方案12】:
如果你想要跨浏览器,你想要jQuery.isArray。
【讨论】:
以上是关于原生如何检测变量是不是是一个数组的几种方法的主要内容,如果未能解决你的问题,请参考以下文章