当前位置: 首页 > 科技观察

如何判断一个数组是否是JavaScript中的数组?(alpha)

时间:2023-03-14 15:47:01 科技观察

如果你还没有关注过这个问题,那么这个标题应该让你一头雾水。这么基础的判断数据类型的问题,能有什么坑呢?小子,你不能太天真了,我们没日没夜地面对这门语言,但是JavaScript,任何你认为已经习以为常的东西,都可能瞬间变成一个大坑,让人百思不得其解。但也正是出于同样的原因,我们在学习和使用JavaScript时,可以提出和讨论一些这种语言独有的、非常有趣的问题。比如我们今天要讨论的是JavaScript中如何判断一个数组是否为数组。JavaScript有五种方法来判断一个值的类型,分别是typeof操作符、constructor方法、instanceof操作符、Object.prototype.toString方法和Array.isArray方法。1.使用typeof算法判断typeof是否为javascript原生提供的判断数据类型的运算符,会返回一个字符串表示参数的数据类型,例如:consts='hello';console.log(typeof(s))//String下面是我在MDN上的文档中找到的一张包含typeof算法针对不同参数的输出结果的表:从这张表可以看出数组被归类为Anyotherobject,所以返回的结果通过typeof应该是Object,没办法区分原型链上的array、object、null等是Object的数据类型。const=null;constb={};constc=[];console.log(typeof(a));//Objectconsole.log(typeof(b));//Objectconsole.log(typeof(c));//当Object运行上面的代码,你会发现当参数是数组、对象或null时,typeof返回的结果是object。可以用这个方法来识别数组,所以在JavaScript项目中用typeof来判断一个位置数据的类型是否是数组是很不靠谱的。2.通过instanceof判断既然不能用typeof来判断一个数组是否是数组,那么用instance运算符来判断是否可行呢?要回答这个问题,首先要了解instanceof算法是干什么用的。instanceof操作符可以用来判断某个构造函数的prototype属性指向的对象是否存在于另一个待检测对象的原型链上。使用时的语法如下:objectinstanceofconstructor我的理解是判断一个Object是否是数组(这不是口误,在JavaScript中,数组其实就是一个对象),如果对象可以在原型链上找到如果使用Array构造函数,那么Object应该是一个数组。如果在Object的原型链上只能找到Object的构造函数,那么它就不是数组。consta=[];constb={};console.log(ainstanceofArray);//trueconsole.log(ainstanceofObject);//true,在数组console.log(binstanceofArray)的原型链上也可以找到Object构造函数;//false从上面几行代码可以看出,可以通过instanceof操作符来区分数组和对象,可以判断数组是数组。3.使用constructor判断实例化的数组有constructor属性,指向生成数组的方法。consta=[];console.log(a.constructor);//functionArray(){[nativecode]}上面的代码表明数组是由一个名为Array的函数实例化的。如果判断的对象是其他数据类型,结果如下:consto={};console.log(o.constructor);//functionObject(){[nativecode]}constr=/^[0-9]$/;console.log(r.constructor);//functionRegExp(){[nativecode]}constn=null;console.log(n.constructor);//这里报错,你可能觉得这也是一个靠谱的方法判断数组,我们可以用下面的方式来判断:consta=[];console.log(a.constructor==Array);//true但是很遗憾的通知你,constructor属性是可以重写的,如果你不小心更改了构造函数属性,那么使用此方法将无法确定数组的真实身份。写到这里,我不禁想起了无间道的经典台词,梁朝伟:“对不起,我是警察。”刘德华:“谁知道呢?”。//定义一个数组consta=[];//将constructor属性改成其他的a.contrtuctor=Object;console.log(a.constructor==Array);//false(悲伤的脸)console.log(a.constructor==Object);//true(悲伤的脸)console.log(ainstanceofArray);//true(instanceofsharpeyes)可以看出修改了constructor属性后,无法使用该方法判断是否数组就是一个数组,除非你能保证constructor属性不会被覆盖,否则用这种方法判断数组是不可靠的。4、使用Object的toString方法进行判断还有一个有效的方法是使用Object.prototype.toString方法进行判断。从Object继承的每个对象都有一个toString方法。如果一个对象的toString方法没有被覆盖,toString方法将返回“[objecttype]”,其中type表示对象的类型。根据type的值,我们可以判断出疑似数组对象到底是不是数组。大家可能会纠结,为什么不直接调用数组,或者字符串本身的toString方法呢?让我们试试看。consta=['Hello','Howard'];constb={0:'Hello',1:'Howard'};constc='HelloHoward';a.toString();//"Hello,Howard"b.toString();//[objectObject]"c.toString();//"Hello,Howard"从上面的代码可以看出,除了对象,其他数据类型的toString返回内容的字符创建,只有对象的toString方法返回对象的类型。所以判断对象以外的数据的数据类型,我们需要“借用”对象的toString方法,所以需要使用call或者apply方法来改变toString方法的执行上下文。consta=['Hello','Howard'];constb={0:'Hello',1:'Howard'};constc='HelloHoward';Object.prototype.toString.call(a);//[objectArray]"Object.prototype.toString.call(b);//"[objectObject]"Object.prototype.toString.call(c);//"[objectString]"使用apply方法也可以达到同样的效果:consta=['Hello','Howard'];constb={0:'Hello',1:'Howard'};constc='HelloHoward';Object.prototype.toString.apply(a);//[objectArray]"Object.prototype.toString.apply(b);//"[objectObject]"Object.prototype.toString.apply(c);//"[objectString]"综上所述,我们可以写一个方法来判断是否数组是对于一个数组:constisArray=(something)=>{returnObject.prototype.toString.call(something)==='[objectArray]';}cosnta=[];constb=[];isArray(a);//trueiisArray(b);//false但是,如果你非要在创建这个方法之前就这样做,还要在Object原型链上改掉toString方法,那我就真的帮不了你了……//重写Object的toString方法.prototype.toString=()=>{alert('吃了吗?');}//调用String方法consta=[];Object.prototype.toString.call(a);//弹框问你toeat当然,alert框只能在浏览器中看到,就不解释了。5、用Array对象的isArray方法判断为什么这个方法放在***?因为这是我目前遇到的最靠谱的判断数组的方法。当参数为数组时,isArray方法返回true。当参数不是数组时,isArray方法返回false。consta=[];constb={};Array.isArray(a);//trueArray.isArray(b);//false在调用这个方法之前我尝试重写了Object.prototype.toString方法:Object.prototype.toString=()=>{console.log('HelloHoward');}consta=[];Array.isArray(a);//true不影响判断结果。我再次尝试修改构造函数对象:consta=[];constb={};a.constructor=b.constructor;Array.isArray(a);//trueOK,依然不影响判断结果。可以看出,与实例运算符和Object.prototype.toString方法的判断方式不同,部分列的修改不影响判断结果。你可以放心大胆地使用Array.isArray来判断一个对象是否是数组。除非你不小心覆盖了Array.isArray方法本身。.