在JavaScript中,怎样推断数组是数组?

假如你没有注重过这个题目,那末这个题目应当会让你以为疑心,推断数据范例这么基本的题目能有什么坑呢?

少年,你不能太无邪了,我们旦夕面临的这门言语,然则JavaScript呀,任何你以为已屡见不鲜的东西都可以霎时转化成一个大坑,使人百思不得其解。

然则恰是由于一样的缘由,我们可以在进修和运用JavaScript这门言语的时刻提出和议论一些这门言语独占的,异常风趣的题目。比方我们本日要议论的,在JavaScript当中怎样推断一个数组是数组。

JavaScript有五种要领可以肯定一个值究竟是什么范例,分别是typeof运算符,constructor法,instanceof运算符,Object.prototype.toString要领以及Array.isArray法.

1.用typeof运算符来推断

typeof是javascript原生供应的推断数据范例的运算符,它会返回一个示意参数的数据范例的字符串,比方:

const s = 'hello';
console.log(typeof(s))//String

以下是我在MDN的文档中找到的一张包括typeof运算法的针对差别参数的输出结果的表格:

《在JavaScript中,怎样推断数组是数组?》

从这张表格可以看出,数组被归到了Any other object当中,所以typeof返回的结果应当是Object,并没有方法辨别数组,对象,null等原型链上都有Object的数据范例。

const a = null;
const b = {};
const c= [];
console.log(typeof(a)); //Object
console.log(typeof(b)); //Object
console.log(typeof(c)); //Object

运转上面的代码就会发明,在参数为数组,对象或许null时,typeof返回的结果都是object,可以运用这类要领并不能识别出数组,因而,在JavaScript项目顶用typeof来推断一个位置范例的数据是不是为数组,是异常不靠谱的。

2.用instanceof推断

既然typeof没法用于推断数组是不是为数组,那末用instance运算符来推断是不是可行呢?要回答这个题目,我们起首得相识instanceof运算法是干吗用的。

instanceof运算符可以用来推断某个组织函数的prototype属性所指向的对象是不是存在于别的一个要检测对象的原型链上。在运用的时刻语法以下:

object instanceof constructor

用我的明白来讲,就是要推断一个Object是不是是数组(这里不是口误,在JavaScript当中,数组实际上也是一种对象),假如这个Object的原型链上可以找到Array组织函数的话,那末这个Object应当及就是一个数组,假如这个Object的原型链上只能找到Object组织函数的话,那末它就不是一个数组。

const a = [];
const b = {};
console.log(a instanceof Array);//true
console.log(a instanceof Object);//true,在数组的原型链上也能找到Object组织函数
console.log(b instanceof Array);//false

由上面的几行代码可以看出,运用instanceof运算符可以区分数组和对象,可以推断数组是数组。

3.用constructor推断

实例化的数组具有一个constructor属性,这个属性指向天生这个数组的要领。

const a = [];
console.log(a.constructor);//function Array(){ [native code] }

以上的代码申明,数组是有一个叫Array的函数实例化的。
假如被推断的对象是其他的数据范例的话,结果以下:

const o = {};
console.log(o.constructor);//function Object(){ [native code] }
const r = /^[0-9]$/;
console.log(r.constructor);//function RegExp() { [native code] }
const n = null;
console.log(n.constructor);//报错

看到这里,你可以会以为这也是一种靠谱的推断数组的要领,我们可以用以下的体式格局来推断:

const a = [];
console.log(a.constructor == Array);//true

然则,很遗憾的关照你,constructor属性是可以改写的,假如你一不小心作死改了constructor属性的话,那末运用这类要领就没法推断出数组的真是身份了,写到这里,我不禁想起了无间道的那段经典对白,梁朝伟:“对不起,我是警员。”刘德华:“谁知道呢?”。

//定义一个数组
const a = [];
//作死将constructor属性改成了别的
a.contrtuctor = Object;
console.log(a.constructor == Array);//false (哭脸)
console.log(a.constructor == Object);//true (哭脸)
console.log(a instanceof Array);//true (instanceof火眼金睛)

可以看出,constructor属性被修正以后,就没法用这个要领推断数组是数组了,除非你能保证不会发作constructor属性被改写的状况,否则用这类要领来推断数组也是不靠谱的。

4.用Object的toString要领推断

另一个卓有成效的要领就是运用Object.prototype.toString要领来推断,每个继续自Object的对象都具有toString的要领。

假如一个对象的toString要领没有被重写过的话,那末toString要领将会返回”[object type]”,个中的type代表的是对象的范例,依据type的值,我们就可以推断这个疑似数组的对象究竟是不是是数组了。

你可以会纠结,为何不是直接挪用数组,或则字符串自身的的toString要领呢?我们试一试就知道了。

const a = ['Hello','Howard'];
const b = {0:'Hello',1:'Howard'};
const c = 'Hello Howard';
a.toString();//"Hello,Howard"
b.toString();//"[object Object]"
c.toString();//"Hello,Howard"

从上面的代码可以看出,除了对象以外,其他的数据范例的toString返回的都是内容的字符创,只要对象的toString要领会返回对象的范例。所以要推断除了对象以外的数据的数据范例,我们须要“借用”对象的toString要领,所以我们须要运用call或许apply要领来转变toString要领的实行上下文。

const a = ['Hello','Howard'];
const b = {0:'Hello',1:'Howard'};
const c = 'Hello Howard';
Object.prototype.toString.call(a);//"[object Array]"
Object.prototype.toString.call(b);//"[object Object]"
Object.prototype.toString.call(c);//"[object String]"

运用apply要领也能到达一样的结果:

const a = ['Hello','Howard'];
const b = {0:'Hello',1:'Howard'};
const c = 'Hello Howard';
Object.prototype.toString.apply(a);//"[object Array]"
Object.prototype.toString.apply(b);//"[object Object]"
Object.prototype.toString.apply(c);//"[object String]"

总结一下,我们就可以用写一个要领来推断数组是不是为数组:

const isArray = (something)=>{
    return Object.prototype.toString.call(something) === '[object Array]';
}

cosnt a = [];
const b = {};
isArray(a);//true
isArray(b);//false

然则,假如你非要在建立这个要领之前这么来一下,转变了Object原型链上的toString要领,那我至心帮不了你了…

//重写了toString要领
Object.prototype.toString = () => {
    alert('你吃过了么?');
}
//挪用String要领
const a = [];
Object.prototype.toString.call(a);//弹框问你吃过饭没有

固然了,只要在浏览器当中才看到alert弹框,这个我就不诠释了。

5.用Array对象的isArray要领推断

为何把这类要领放在末了讲呢?由于它是我现在遇到过的最靠谱的推断数组的要领了,当参数为数组的时刻,isArray要领返回true,当参数不为数组的时刻,isArray要领返回false。

const a = [];
const b = {};
Array.isArray(a);//true
Array.isArray(b);//false

我试着在挪用这个要领之前重写了Object.prototype.toString要领:

Object.prototype.toString = ()=>{
    console.log('Hello Howard');
}
const a = [];
Array.isArray(a);//true

并不影响推断的结果。
我又试着修正了constructor对象:

const a = [];
const b = {};
a.constructor = b.constructor;
Array.isArray(a);//true

OK,照样不影响推断的结果。

可见,它与instance运算符推断的要领以及Object.prototype.toString法并不相同,一些列的修正并没有影响到推断的结果。

你可以放心大胆的运用Array.isArray去推断一个对象是不是是数组。
除非你不小心重写了Array.isArray要领自身。。

主要补充:有读者朋侪在批评中提示我,Array.isArray是ES5规范中增添的要领,部份比较老的浏览器可以会有兼容题目,所以为了加强健壮性,发起照样给Array.isArray要领举行推断,加强兼容性,从新封装的要领以下:

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

作者:方浩,转载请说明出处!!!
文章源链接:https://segmentfault.com/a/11…

我的微信民众号:webcoding ,迎接扫码关注
《在JavaScript中,怎样推断数组是数组?》

    原文作者:霍华德
    原文地址: https://segmentfault.com/a/1190000006150186
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞