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” |
undefined | undefined.toString() | Uncaught TypeError: Cannot read property ‘toString’ of undefined |
null | null.toString() | Uncaught TypeError: Cannot read property ‘toString’ of null |
String | String.toString() | “function String() { [native code] }” |
Number | Number.toString() | “function Number() { [native code] }” |
Boolean | Boolean.toString() | “function Boolean() { [native code] }” |
Function | Function.toString() | “function Function() { [native code] }” |
Array | Array.toString() | “function Array() { [native code] }” |
Date | Date.toString() | “function Date() { [native code] }” |
RegExp | RegExp.toString() | “function RegExp() { [native code] }” |
Error | Error.toString() | “function Error() { [native code] }” |
Promise | Promise.toString() | “function Promise() { [native code] }” |
Obejct | Obejct.toString() | “function Obejct() { [native code] }” |
Math | Math.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]。
以上就是能实现浏览器兼容的原因。