判断是否是一个数组的方法与原理

JS判断是否是为数组的方法

首先区别Javascript类型:

JS中有六种类型

❑String
❑Number
❑Boolean
❑Null
❑Undefined
❑Object

除了Object,其他都是基本数据类型,Object是引用数据类型

一、typeof 操作符

❑ "undefined"表示值未定义;
❑ "boolean"表示值为布尔值;
❑ "string"表示值为字符串;
❑ "number"表示值为数值;
❑ "object"表示值为对象(而不是函数)或null;
❑ "function"表示值为函数;
❑ "symbol"表示值为符号【ES6新增的】
在这里插入图片描述
特别注意:
(1)要是检测Array的对象就不起作用了。 利用typeof除了array和null判断为object外,其他的都可以正常判断。
(2)Symbol
Symbol(符号)是ECMAScript 6新增的数据类型。符号是原始值,且符号实例是唯一、不可变的。符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。

基本使用方法:
符号需要使用Symbol()函数初始化。因为符号本身是原始类型,所以typeof操作符对符号返回symbol。

let sym = Symbol();
console.log(typeof sym); //symbol

调用Symbol()函数时,也可以传入一个字符串参数作为对符号的描述(description),将来可以通过这个字符串来调试代码。但是,这个字符串参数与符号定义或标识完全无关。

二、instanceof操作符

这个操作符和JavaScript中面向对象有点关系,了解这个就先得了解JavaScript中的面向对象。因为这个操作符是检测对象的原型链是否指向构造函数的prototype对象的。
在这里插入图片描述
在ES6中,instanceof操作符会使用Symbol.hasInstance函数来确定关系。以Symbol. hasInstance为键的函数会执行同样的操作,只是操作数对调了一下:
在这里插入图片描述

var arr = [1,2,3,1];
alert(arr instanceof Array); // true 

三.对象的constructor属性

除了instanceof,每个对象还有constructor的属性,利用它似乎也能进行Array的判断。

var arr = [1,2,3,1];
alert(arr.constructor === Array); // true 

在这里插入图片描述
结合instanceof操作符和对象的constructor属性这两种方法貌似无懈可击,但是实际上还是有些漏洞的,当你在多个frame中来回穿梭的时候,这两种方法就亚历山大了。由于每个iframe都有一套自己的执行环境,跨frame实例化的对象彼此是不共享原型链的,因此导致上述检测代码失效。

在这里插入图片描述

四、isArray()

ECMAScript5将Array.isArray()正式引入到javaScript,目前能够准确地检测一个值是否为数组。

// 下方都回傳 true
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
Array.isArray(new Array('a', 'b', 'c', 'd'));
Array.isArray(new Array(3));
// 小細節:Array.prototype 本身是陣列:
Array.isArray(Array.prototype);

// 下方都回傳 false
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);
Array.isArray({ __proto__: Array.prototype });

但是依旧存在部分旧版浏览器不兼容的问题。

目前浏览器的兼容性:
在这里插入图片描述

为了解决浏览器兼容的问题,可以这样处理:

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

五、总结:

综合 上述的各种方式,目前比较完整的判断是否为数组的函数如下:

var arr = [1,2,3,4];
var arr2 = [{ a : 1, b : 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

六、拓展:实现浏览器兼容的原理

1、toString()方法的使用:

var num = 123
num.toString() // '123'

var str = 'hello'
str.toString() // 'hello'

var bool = false
bool.toString() // 'false'

var arr = [1, 2, 3]
arr.toString()  // '1,2,3'

var obj = {lang:'zh'}
obj.toString()  // '[object Object]'

var fn = function(){}
fn.toString()  // 'function(){}'

null.toString()  // Cannot read property 'toString' of null

undefined.toString() // Cannot read property 'toString' of undefined

toString:是将传入的数据类型转换成字符串输出(null和undefined除外)。

我们再来看一下Object以及其原型上的toString方法:

在这里插入图片描述
Object输出的是其函数体"function Object() { [native code] }"而Object上输出的是其类型。我们可以看出Object对象和它的原型链上各自有一个toString()方法,第一个返回的是一个函数,第二个返回的是值类型

2、各种数据类型调用toString()方法的返回值:

数据类型例子返回
字符串“foo”.toString()“foo”
数字1.toString()Uncaught SyntaxError: Invalid or unexpected token
布尔值false.toString()“false”
undefinedundefined.toString()Uncaught TypeError: Cannot read property ‘toString’ of undefined
nullnull.toString()Uncaught TypeError: Cannot read property ‘toString’ of null
StringString.toString()“function String() { [native code] }”
NumberNumber.toString()“function Number() { [native code] }”
BooleanBoolean.toString()“function Boolean() { [native code] }”
FunctionFunction.toString()“function Function() { [native code] }”
ArrayArray.toString()“function Array() { [native code] }”
DateDate.toString()“function Date() { [native code] }”
RegExpRegExp.toString()“function RegExp() { [native code] }”
ErrorError.toString()“function Error() { [native code] }”
PromisePromise.toString()“function Promise() { [native code] }”
ObejctObejct.toString()“function Obejct() { [native code] }”
MathMath.toString()“[object Math]”

由此,我们可以看出不同的数据类型都有其自身的toString()方法。所以上述的toString()方法来自于Number、String、BOOlean…这些类。

并且在JavaScript中,所有类都继承于Object,因此,toString()方法也被继承了,但由上述可见事实并不是我们想的样子,其实个数据类型使用toString()方法后的结果不一样的原因在于:
所有在继承Object时,都改写了toString()方法。
Object原型上的方法是可以输出数据类型的。因此,我们想判断数据类型时,也只能使用原始方法。继而有了此方法:

Object.prototype.toString.call(obj)

3、接下来我们验证:

// 定义一个数组
var arr = [34,23,1]

// 数组原型上是否具有 toString() 方法
console.log(Array.prototype.hasOwnProperty('toString')) //true

// 数组直接使用自身的 toString() 方法
console.log(arr.toString()) // '34,23,1'

// delete操作符删除数组原型上的 toString()
delete Array.prototype.toString

// 删除后,数组原型上是否还具有 toString() 方法
console.log(Array.prototype.hasOwnProperty('toString')) //false

// 删除后的数组再次使用 toString() 时,会向上层访问这个方法,即 Object 的 toString()
console.log(arr.toString()) // '[object Array]'

当我们把Array自身的toString()方法删除之后,再次使用它时,由原型链它会向上查找这个方法,即Object的toString(),也便将Object上的toString()方法作用在数组上,得出其数据类型[object Array]。

以上就是能实现浏览器兼容的原因。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值