问答题711/1593写一个返回数据类型的函数,要求自定义的类实例化的对象返回定义的类名

难度:
2022-04-26 创建

参考答案:

Javascript是一门动态类型的语言,一个变量从声明到最后使用,可能经过了很多个函数,而数据类型也会发生改变,那么,对一个变量的数据类型判断就显得尤为重要。

获取数据类型

我们先来看下怎么获取一个数据的类型。

typeof是否能正确判断类型?

由于由于历史原因,在判断原始类型时,typeof null会等于object。而且对于对象(Object)、数组(Array)来说,都会转换成object。例子如下:

1 typeof 1 // 'number' 2 typeof "1" // 'string' 3 typeof null // 'object' 4 typeof undefined // 'undefined' 5 6 typeof [] // 'object' 7 typeof {} // 'object' 8 typeof function() {} // 'function'

所以我们可以发现,typeof可以判断基本数据类型,但是难以判断除了函数以外的复杂数据类型。于是我们可以使用第二种方法,通常用来判断复杂数据类型,也可以用来判断基本数据类型。

对于返回值为object,有三种情况:

  • 值为null
  • 值为object
  • 值为array

对于null,我们可以直接用===来进行判断,那么数组和对象呢?不急,我们接着说。

instanceof是否能正确判断类型?

instanceof是通过原型链来判断的,但是对于对象来说,Array也会被转换成Object,而且也不能区分基本类型stringboolean。可以左边放你要判断的内容,右边放类型来进行JS类型判断,只能用来判断复杂数据类型,因为instanceof 是用于检测构造函数(右边)的 prototype 属性是否出现在某个实例对象(左边)的原型链上。例如:

1 function Func() {} 2 const func = new Func() 3 console.log(func instanceof Func) // true 4 5 const obj = {} 6 const arr = [] 7 obj instanceof Object // true 8 arr instanceof Object // true 9 arr instanceof Array // true 10 11 const str = "abc" 12 const str2 = new String("abc") 13 str instanceof String // false 14 str2 instanceof String // true

单独使用instanceof好像也是不行的,但是我们对于typeof已经得出结论,不能区分数组和对象,那么,我们结合下instanceof,来写一个完整的判断逻辑

1 function myTypeof(data) { 2 const type = typeof data 3 if (data === null) { 4 return 'null' 5 } 6 if (type !== 'object') { 7 return type 8 } 9 if (data instanceof Array) { 10 return 'array' 11 } 12 return 'object' 13 }

constructor

constructor 判断方法跟instanceof相似,但是constructor检测Object与instanceof不一样,constructor还可以处理基本数据类型的检测,不仅仅是对象类型。

注意:

  1. null和undefined没有constructor;
  2. 判断数字时使用(),比如 (123).constructor,如果写成123.constructor会报错
  3. constructor在类继承时会出错,因为Object被覆盖掉了,检测结果就不对了
1 function A() {}; 2 function B() {}; 3 A.prototype = new B(); 4 console.log(A.constructor === B) // false 5 6 var C = new A(); 7 console.log(C.constructor === B) // true 8 console.log(C.constructor === A) // false 9 10 C.constructor = A; 11 console.log(C.constructor === A); // true 12 console.log(C.constructor === B); // false

Array.isArray()

Array.isArray() 用于确定传递的值是否是一个 Array。如果对象是 Array ,则返回true,否则为false。

1 Array.isArray([1, 2, 3]); // true 2 Array.isArray({foo: 123}); // false 3 Array.isArray("foobar"); // false 4 Array.isArray(undefined); // false

正则判断

我们可以把对象和数组转成一个字符串,这样就可以做格式判断,从而得到最终的类型。

1 function myTypeof(data) { 2 const str = JSON.stringify(data) 3 if (/^{.*}$/.test(data)) { 4 return 'object' 5 } 6 if (/^\[.*\]$/.test(data)) { 7 return 'array' 8 } 9 }

Object.prototype.toString.call()

上面我们通过typeofinstanceof实现了一版类型判断,那么是否有其他渠道,使我们的代码更加简洁吗?答案就是使用Object.prototype.toString.call()

每个对象都有一个toString()方法,当要将对象表示为文本值或以预期字符串的方式引用对象时,会自动调用该方法。默认情况下,从Object派生的每个对象都会继承toString()方法。如果此方法未在自定义对象中被覆盖,则toString()返回[Object type],其中type是对象类型。所以就有以下例子:

1 Object.prototype.toString.call(new Date()) // [object Date] 2 Object.prototype.toString.call("1") // [object String] 3 Object.prototype.toString.call(1) // [object Numer] 4 Object.prototype.toString.call(undefined) // [object Undefined] 5 Object.prototype.toString.call(null) // [object Null]

所以综合上述知识点,我们可以封装出以下通用类型判断方法:

1 function myTypeof(data) { 2 var toString = Object.prototype.toString; 3 var dataType = data instanceof Element ? "Element" : toString.call(data).replace(/\[object\s(.+)\]/, "$1") 4 return dataType 5 }; 6 7 myTypeof("a") // String 8 myTypeof(1) // Number 9 myTypeof(window) // Window 10 myTypeof(document.querySelector("h1")) // Element

获取实例化对象的类名

题目中的第二个要求,是对于自定义的类实例化的对象,需要返回定义的类名。

这个也比较简单,我们对于上述获取的 Object 类型的数据,直接使用 xx.constructor.name 即可获取到这个数据对应的类名。

最终实现

1function myTypeof(data) { 2 var toString = Object.prototype.toString; 3 var dataType = data instanceof Element ? "Element" : toString.call(data).replace(/\[object\s(.+)\]/, "$1") 4 5 if(dataType === 'Object'){ 6 return data.constructor.name 7 } 8 9 return dataType 10};

最近更新时间:2024-08-10

赞赏支持

预览

题库维护不易,您的支持就是我们最大的动力!