Git Product home page Git Product logo

第 21 题:有以下 3 个判断数组的方法,请分别介绍它们之间的区别和优劣Object.prototype.toString.call() 、 instanceof 以及 Array.isArray() about daily-interview-question HOT 34 CLOSED

xueqingxiao avatar xueqingxiao commented on May 3, 2024 25
第 21 题:有以下 3 个判断数组的方法,请分别介绍它们之间的区别和优劣Object.prototype.toString.call() 、 instanceof 以及 Array.isArray()

from daily-interview-question.

Comments (34)

sisterAn avatar sisterAn commented on May 3, 2024 338

1. Object.prototype.toString.call()

每一个继承 Object 的对象都有 toString 方法,如果 toString 方法没有重写的话,会返回 [Object type],其中 type 为对象的类型。但当除了 Object 类型的对象外,其他类型直接使用 toString 方法时,会直接返回都是内容的字符串,所以我们需要使用call或者apply方法来改变toString方法的执行上下文。

const an = ['Hello','An'];
an.toString(); // "Hello,An"
Object.prototype.toString.call(an); // "[object Array]"

这种方法对于所有基本的数据类型都能进行判断,即使是 null 和 undefined 。

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

Object.prototype.toString.call() 常用于判断浏览器内置对象时。

更多实现可见 谈谈 Object.prototype.toString

2. instanceof

instanceof  的内部机制是通过判断对象的原型链中是不是能找到类型的 prototype

使用 instanceof判断一个对象是否为数组,instanceof 会判断这个对象的原型链上是否会找到对应的 Array 的原型,找到返回 true,否则返回 false

[]  instanceof Array; // true

instanceof 只能用来判断对象类型,原始类型不可以。并且所有对象类型 instanceof Object 都是 true。

[]  instanceof Object; // true

3. Array.isArray()

  • 功能:用来判断对象是否为数组

  • instanceof 与 isArray

    当检测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
    Object.prototype.toString.call(arr); // true
    // Considered harmful, because doesn't work though iframes
    arr instanceof Array; // false
  • Array.isArray()Object.prototype.toString.call()

    Array.isArray()是ES5新增的方法,当不存在 Array.isArray() ,可以用 Object.prototype.toString.call() 实现。

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

from daily-interview-question.

jjeejj avatar jjeejj commented on May 3, 2024 19

对于性能问题,我测试几遍的结果 Array.isArray 的性能最好,instanceof 比 toString.call 稍微好了一点点
image

测试链接: https://jsperf.com/judging-array-type/

对于其中的性能差异的原理,大家可以讨论一下的

from daily-interview-question.

lordGuan avatar lordGuan commented on May 3, 2024 12

从Stack Overflow扒来的资料:
结论:toString.call和isArray的性能一样差,instanceof稍好,constructor性能最好
优劣我只能看到这么多了。非要咬文嚼字大概就是Array.isArray在老浏览器需要polyfill,然后又跟toString.call一样了。
初次之外看到一个神奇之处,instanceof不能检测来自iframe的数组。就是官方文档上,window.frames[xx].Array构造出来的数组。

from daily-interview-question.

yujihu avatar yujihu commented on May 3, 2024 12

instanceof是判断类型的prototype是否出现在对象的原型链中,但是对象的原型可以随意修改,所以这种判断并不准确。

const obj = {}
obj.__proto__ = Array.prototype
// Object.setPrototypeOf(obj, Array.prototype)
obj instanceof Array // true

from daily-interview-question.

xiongchen2012 avatar xiongchen2012 commented on May 3, 2024 11

arr.constructor === Array

from daily-interview-question.

ginobilee avatar ginobilee commented on May 3, 2024 11

@sisterAn

但当除了 Object 类型的对象外,其他类型直接使用 toString 方法时,会直接返回都是内容的字符串,所以我们需要使用call或者apply方法来改变toString方法的执行上下文。
这里感觉不太清晰。事实上应该不是改变 toString 的上下文,而是改变调用的 toString 方法:

const arr = [1, 2]
arr.toString === Object.prototype.toString // false, 所以两者不同,实际上数组上重写了 toString 方法
const o = {o: 1}
o.toString === Object.prototype.toString // true, 所以对象默认不需要如此调用。但如果将对象的方法改写就不一定了
o.toString = function changedToString() {
  return 'haha';
}
o.toString() // 'haha'
Object.prototype.toString.call(o) // '[object Object]'. 发现 Object.prototype.toString 也是可以被改写的...

call 方法的第一个参数会被当作 this,所以 arr.toString()Object.prototype.toString.call(arr) 并没有改变 this,而是改变了调用的函数。

from daily-interview-question.

bazinga-web avatar bazinga-web commented on May 3, 2024 7

https://www.cnblogs.com/onepixel/p/5126046.html

from daily-interview-question.

NANAYWY avatar NANAYWY commented on May 3, 2024 7

typeof 是什么原理呢?
哪位大神给讲讲

typeof 只能检测 基本数据类型,包括boolean、undefined、string、number、symbol,而null ,Array、Object ,使用typeof出来都是Objec。无法检测具体是哪种引用类型。

from daily-interview-question.

masx200 avatar masx200 commented on May 3, 2024 5

Object.prototype.toString.call()
这个方法也不是完全靠谱的啊,
如果遇到对象的属性 Symbol.toStringTag 被改成了"Array" 怎么办啊

应该要加上instanceoftypeof三重判断才行

from daily-interview-question.

xufeiayang avatar xufeiayang commented on May 3, 2024 4

typeof不能校验object的其他类型,引用类型除了function都不能区分

instanceof不能校验原始值类型

'a' instanceof String
// false

Object.prototype.toString.call()
不能校验自定义类型

function Animal (){}
let a = new Animal()
Object.prototype.toString.call(a)
"[object Object]"

from daily-interview-question.

GitHdu avatar GitHdu commented on May 3, 2024 3

constructor可以被修改?

from daily-interview-question.

yujihu avatar yujihu commented on May 3, 2024 3

typeof 是什么原理呢?
哪位大神给讲讲

typeof 只能检测 基本数据类型,包括boolean、undefined、string、number、symbol,而null ,Array、function、Object ,使用typeof出来都是Objec。无法检测具体是哪种引用类型。

函数的typeof是'function'

from daily-interview-question.

masx200 avatar masx200 commented on May 3, 2024 2

其实还可以用
JSON.stringify
来判断是不是数组
数组转json是以[开头,以]结尾的

from daily-interview-question.

masx200 avatar masx200 commented on May 3, 2024 1

如果真数组的Symbol.toStringTag属性被修改了,或者__proto__被修改了,怎么判断?

var realarray=[]
realarray[Symbol.toStringTag]='Function'
realarray.__proto__=Function.prototype

Array.isArray判断结果是true

from daily-interview-question.

LemonSprit avatar LemonSprit commented on May 3, 2024 1

isArray()不是es6新增吗

from daily-interview-question.

sushiGump avatar sushiGump commented on May 3, 2024 1

typeof 是什么原理呢?
哪位大神给讲讲

  1. typeof在判断一些引用类型时会分辨不出具体类型:
  • 例如对象和数组;
    typeof [1,2,3]; //object
    typeof {}; //object

  • 还有typeof判断String/Array/Boolean/Number等等,都会返回'function',当作是String/Array/Boolean/Number类型的构造函数;
    typeof Array; //function Array类型的构造函数

2.实际上js在底层存储变量的时候,会在变量的机器码的低位(1-3位)存储其类型信息,对象用的是000,null的所有机器码(不仅是1-3位)都是0,所以typeof还无法区分object 和 null;

from daily-interview-question.

soraly avatar soraly commented on May 3, 2024 1

Object.prototype.toString.call可以识别出所有的数据类型,比如

Object.prototype.toString.call({ }) // "[object Object]"
Object.prototype.toString.call([2,3]) // "[object Array]"
Object.prototype.toString.call('An') // "[object String]"
Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(function(){}) // "[object Function]"

instanceof 不能使用在原始类型上,只能用在对象类型上,
left instance right,
如果left的原型链上能找到right的prototype,即left是right的一个实例,如果能找到返回为true,比如

[] instanceof Array //true

但是这样写区分不了对象和数组,因为

[] instanceof Object//也返回true

原因是所有对象类型的祖宗都是Object

isArray可以用来判断是否是数组,而且可以区分对象
image
上图解析:

  1. 原型链就是多个对象通过__proto__连接了起来
  2. 凡是对象,最终都可以通过__proto__寻址到Object.prototype
  3. 凡是函数,最终都可以通过__proto__寻址到Function.prototype
  4. 函数的prototype是一个对象

from daily-interview-question.

DennisYongLe avatar DennisYongLe commented on May 3, 2024 1

这里在理解的时候可能会把Object.prototype.toString.call()与[12].toString()方法相混淆,如果把这两个toString方法当作是一个,那么后续的理解会造成困难。因为当我们期待Object.prototype.toString.call([12])返回一个12时,发现控制台打印的却是【object array】。
首先,得理解这两个方法为什么不是一个?[12]是Array的实例,那么他的toString方法就得从Array这个构造者的prototype中去寻找,发现确实有这个方法,那么直接调用即可,不会再向上去寻找toString。而Object.prototype.toString方法属于最顶层的方法,从位置上来看他俩压根就不是一个。
其次,他俩有什么样的关系呢?通过下面这个式子就可以理解了。
[12].proto===Array.prototype
Array.prototype.proto===Object.prototype

from daily-interview-question.

thinkfish avatar thinkfish commented on May 3, 2024

constructor可以被修改?
目测是可以被修改的
arr.constructor = '123'
arr. proto .constructor = '123'
可以console.log(arr.constructor)看下结果,然后再看一下__proto__中的constructor的结果

from daily-interview-question.

zhuzhh avatar zhuzhh commented on May 3, 2024

typeof 是什么原理呢?
哪位大神给讲讲

from daily-interview-question.

xingorg1 avatar xingorg1 commented on May 3, 2024

想仿写一下Object.prototype.toString,但是卡在了null 和 undefined的判断上,返回[object Window]... ...

from daily-interview-question.

aoyeshirenbianchou avatar aoyeshirenbianchou commented on May 3, 2024

具体来讲:每一个继承 Object 的对象都有 toString 方法,该方法返回[Object type];Array、function、Date等都继承于Object,但它们都改写了toString方法,所以阻断了对Object原型上toSting方法的调用。
验证:可以使用delete操作符删除原型实例上的toString方法,然后再调用toString,就可以调用到Object原型上的toString了。
题中用法是:直接调用原型方法,使用call改变this指向,以此来使对象直接调用原型方法。

from daily-interview-question.

xiaobai2017666 avatar xiaobai2017666 commented on May 3, 2024

@sisterAn

但当除了 Object 类型的对象外,其他类型直接使用 toString 方法时,会直接返回都是内容的字符串,所以我们需要使用call或者apply方法来改变toString方法的执行上下文。
这里感觉不太清晰。事实上应该不是改变 toString 的上下文,而是改变调用的 toString 方法:

const arr = [1, 2]
arr.toString === Object.prototype.toString // false, 所以两者不同,实际上数组上重写了 toString 方法
const o = {o: 1}
o.toString === Object.prototype.toString // true, 所以对象默认不需要如此调用。但如果将对象的方法改写就不一定了
o.toString = function changedToString() {
  return 'haha';
}
o.toString() // 'haha'
Object.prototype.toString.call(o) // '[object Object]'. 发现 Object.prototype.toString 也是可以被改写的...

call 方法的第一个参数会被当作 this,所以 arr.toString()Object.prototype.toString.call(arr) 并没有改变 this,而是改变了调用的函数。

我觉得两者说的都没有问题,只是角度不同,对于Object的toString方法来说确实是修改了上下文,而对于Array来说,修改的是调用的toString方法

from daily-interview-question.

masx200 avatar masx200 commented on May 3, 2024

如果遇到精心设计的徦数组怎么判断呢?

var fakearray={length:0,__proto__:Array.prototype,[Symbol.toStringTag]:'Array'}
var fakearray=Object("fakestring")
 fakearray.__proto__=Array.prototype
fakearray[Symbol.toStringTag]='Array'

Array.isArray判断结果是false

from daily-interview-question.

dmljc avatar dmljc commented on May 3, 2024

个人感觉题目有必要加上 typeof

from daily-interview-question.

YMaster avatar YMaster commented on May 3, 2024

想仿写一下Object.prototype.toString,但是卡在了null 和 undefined的判断上,返回[object Window]... ...

这两个都满足“不可变”性,也就是全局唯一,直接在你的判断函数中用 === 来判断好了,不等于这俩的再去做其他判断。

from daily-interview-question.

Hideer avatar Hideer commented on May 3, 2024

@sisterAn

但当除了 Object 类型的对象外,其他类型直接使用 toString 方法时,会直接返回都是内容的字符串,所以我们需要使用call或者apply方法来改变toString方法的执行上下文。
这里感觉不太清晰。事实上应该不是改变 toString 的上下文,而是改变调用的 toString 方法:

const arr = [1, 2]
arr.toString === Object.prototype.toString // false, 所以两者不同,实际上数组上重写了 toString 方法
const o = {o: 1}
o.toString === Object.prototype.toString // true, 所以对象默认不需要如此调用。但如果将对象的方法改写就不一定了
o.toString = function changedToString() {
  return 'haha';
}
o.toString() // 'haha'
Object.prototype.toString.call(o) // '[object Object]'. 发现 Object.prototype.toString 也是可以被改写的...

call 方法的第一个参数会被当作 this,所以 arr.toString()Object.prototype.toString.call(arr) 并没有改变 this,而是改变了调用的函数。

我觉得两者说的都没有问题,只是角度不同,对于Object的toString方法来说确实是修改了上下文,而对于Array来说,修改的是调用的toString方法

突然很好奇Object下原始toString都干了啥

from daily-interview-question.

monxiaolee avatar monxiaolee commented on May 3, 2024

var arr = [1, 2, 3]

Array.isArray(arr) // es5新增的 如果不存在可以使用Object.prototype.toString.call(arr)
// Array.isArray 要优于instanceof 因为Array.isArray可以检测出iframe
arr instanceof Array
arr.constructor === Array // 性能最好
Object.prototype.toString.call(arr) === '[objecr Array]'

from daily-interview-question.

xsfxtsxxr avatar xsfxtsxxr commented on May 3, 2024

Object.prototype.toString.call()

万金油,啥类型都能准确的判断,并且没有兼容性问题

instanceof

虽然 [] instanceof Array 返回true,但是 [] instanceof Object 也是true,说不出有啥缺点

Array.isArray()

ES6才有的新方法,有兼容性问题

各位大佬轻喷😸

from daily-interview-question.

JayeeHsu avatar JayeeHsu commented on May 3, 2024

https://blog.csdn.net/qq_43540219/article/details/108010265?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159833773119195162538251%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=159833773119195162538251&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_blog_v1-1-108010265.pc_v2_rank_blog_v1&utm_term=%E5%88%A4%E6%96%AD&spm=1018.2118.3001.4187

from daily-interview-question.

passing-j avatar passing-j commented on May 3, 2024

Object.prototype.toString.call()

万金油,啥类型都能准确的判断,并且没有兼容性问题

instanceof

虽然 [] instanceof Array 返回true,但是 [] instanceof Object 也是true,说不出有啥缺点

Array.isArray()

ES6才有的新方法,有兼容性问题

各位大佬轻喷😸

杠一下,Array.isArray() 在 ES5 就有了,兼容性很好

from daily-interview-question.

Yuweiai avatar Yuweiai commented on May 3, 2024

1. Object.prototype.toString.call()

每一个继承 Object 的对象都有 toString 方法,如果 toString 方法没有重写的话,会返回 [Object type],其中 type 为对象的类型。但当除了 Object 类型的对象外,其他类型直接使用 toString 方法时,会直接返回都是内容的字符串,所以我们需要使用call或者apply方法来改变toString方法的执行上下文。

const an = ['Hello','An'];
an.toString(); // "Hello,An"
Object.prototype.toString.call(an); // "[object Array]"

这种方法对于所有基本的数据类型都能进行判断,即使是 null 和 undefined 。

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

Object.prototype.toString.call() 常用于判断浏览器内置对象时。

更多实现可见 谈谈 Object.prototype.toString

2. instanceof

instanceof  的内部机制是通过判断对象的原型链中是不是能找到类型的 prototype

使用 instanceof判断一个对象是否为数组,instanceof 会判断这个对象的原型链上是否会找到对应的 Array 的原型,找到返回 true,否则返回 false

[]  instanceof Array; // true

instanceof 只能用来判断对象类型,原始类型不可以。并且所有对象类型 instanceof Object 都是 true。

[]  instanceof Object; // true

3. Array.isArray()

  • 功能:用来判断对象是否为数组
  • instanceof 与 isArray
    当检测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
    Object.prototype.toString.call(arr); // true
    // Considered harmful, because doesn't work though iframes
    arr instanceof Array; // false
  • Array.isArray()Object.prototype.toString.call()
    Array.isArray()是ES5新增的方法,当不存在 Array.isArray() ,可以用 Object.prototype.toString.call() 实现。
    if (!Array.isArray) {
      Array.isArray = function(arg) {
        return Object.prototype.toString.call(arg) === '[object Array]';
      };
    }

null和undefined不能直接使用toString:Cannot read properties of null/undefined

from daily-interview-question.

kiiirra avatar kiiirra commented on May 3, 2024

1. Object.prototype.toString.call()

每一个继承 Object 的对象都有 toString 方法,如果 toString 方法没有重写的话,会返回 [Object type],其中 type 为对象的类型。但当除了 Object 类型的对象外,其他类型直接使用 toString 方法时,会直接返回都是内容的字符串,所以我们需要使用call或者apply方法来改变toString方法的执行上下文。

const an = ['Hello','An'];
an.toString(); // "Hello,An"
Object.prototype.toString.call(an); // "[object Array]"

这种方法对于所有基本的数据类型都能进行判断,即使是 null 和 undefined 。

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

Object.prototype.toString.call() 常用于判断浏览器内置对象时。
更多实现可见 谈谈 Object.prototype.toString

2. instanceof

instanceof  的内部机制是通过判断对象的原型链中是不是能找到类型的 prototype
使用 instanceof判断一个对象是否为数组,instanceof 会判断这个对象的原型链上是否会找到对应的 Array 的原型,找到返回 true,否则返回 false

[]  instanceof Array; // true

instanceof 只能用来判断对象类型,原始类型不可以。并且所有对象类型 instanceof Object 都是 true。

[]  instanceof Object; // true

3. Array.isArray()

  • 功能:用来判断对象是否为数组
  • instanceof 与 isArray
    当检测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
    Object.prototype.toString.call(arr); // true
    // Considered harmful, because doesn't work though iframes
    arr instanceof Array; // false
  • Array.isArray()Object.prototype.toString.call()
    Array.isArray()是ES5新增的方法,当不存在 Array.isArray() ,可以用 Object.prototype.toString.call() 实现。
    if (!Array.isArray) {
      Array.isArray = function(arg) {
        return Object.prototype.toString.call(arg) === '[object Array]';
      };
    }

null和undefined不能直接使用toString:Cannot read properties of null/undefined

那是你没有定义变量....

from daily-interview-question.

yyISACoder avatar yyISACoder commented on May 3, 2024
  • Array.isArray()是ES5新增的方法

Array.isArray()应该是ES6新增的方法哦

from daily-interview-question.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.