ForeveHG / Frontend-Daily-Interview

学习,尝试回答一些前端面试题
1 stars 0 forks source link

28. 有以下 3 个判断数组的方法,请分别介绍它们之间的区别和优劣Object.prototype.toString.call() 、 instanceof 以及 Array.isArray() #29

Open ForeveHG opened 4 years ago

ForeveHG commented 4 years ago

原理:

Object.prototype.toString.call() 是借用Object.prototype上的toString方法,该方法在内部访问[Symbol.toStringTag]属性,默认返回值是[object Type],其中type是内置对象的类型,使用这种方法可以判断所有js内置对象的类型

Object.prototype.toString.call('An') // "[object String]"
Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"
Object.prototype.toString.call({name: 'An'}) // "[object Object]"
Object.prototype.toString.call(function(){}) // "[object Function]"
Object.prototype.toString.call([]) // "[object Array]"

instanceof 是判断对象的原型链上是否包含指定对象的原型(prototype) 但对象的原型是可以修改的

var obj = {};
obj.__proto__ = Array.prototype

obj instanceof Array //true
Object.prototype.toString.call(obj) //[object Object]
Array.isArray(obj) //false

Array.isArray() es5中新增的方法,专门用来判断对象是否为数组。

Array.isArray与Object.prototype.toString.call:

当不支持Array.isArray时可以用Object.prototype.toString.call()来polyfill

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

Array.isArray与 instanceof

MDN文档上说:

当检测Array实例时, Array.isArray 优于 instanceof,因为Array.isArray能检测iframes.

同时还举了例子

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // [1,2,3]

// Correctly checking for Array
Array.isArray(arr);  // true
// Considered harmful, because doesn't work though iframes
arr instanceof Array; // false

我写了个例子测试一下:

frame1.html的代码

var array = [1, 2, 3]

index.html的代码

<button onclick="confirm()">确定</button>
<iframe src="./iframe1.html" name="f1"></iframe>
var name = "parent"
var array = ['a','b','c']
function confirm() {
    console.log("index array", array instanceof Array) //true
    console.log("Array.isArray", Array.isArray(f1.window.array)) //true
    console.log("instanceof",  f1.window.array instanceof Array) //false
}

可以看到f1.window.array instanceof Array)返回的是false,就是因为当前有两个全局执行环境,也就是有两个Array构造函数

f1.window.array.__proto__ ===  f1.window.Array.prototype  //true
f1.window.array.__proto__ ===  Array.prototype  //false
array.__proto__ == Array.prototype  //true

所以遇到iframe这种情况可以使用下面的方法,更方便的是直接使用Array.isArray()

console.log("instanceof",  f1.window.array instanceof f1.window.Array) //true

性能: 测试性能 测试几次都是 Array.isArray > instanceof > Object.prototype.toString.call