面试题
类型检测的方法有哪些,平时一般都是怎么使用的?
typeof null 的结果是什么,为什么?
typeof NaN 的结果是什么?
instanceof 操作符的实现原理及实现
今天,我们来讲一讲 JavaScriipt中关于类型检测相关的知识点,上面有几道比较流行的面试题,大家可以试着回答一下,看看自己的能力水平如何,如果所有的问题都能很好的回答出来,那么恭喜你,你是一个隐形的大佬,接下来的内容就可以直接跳过。
类型检测
比较常见的类型检测方法有如下几种:
- typeof
- instanceof
- Object.prototype.toString
- constructor
typeof
typeof 是日常开发中比较常用的类型检测方法,它是 JavaScript 中的保留字。typeof 运算符返回一个字符串,表示操作数的类型。下表总结了 typeof 运算符的返回值。
类型 | 值 |
---|---|
Undefined | 'undefined' |
Null | 'object' |
Boolean | 'boolean' |
Number | 'number' |
BigInt | 'bigint' |
String | 'string' |
Symbol | 'symbol' |
Function | 'function' |
Object | 'object' |
Date | 'object' |
Array | 'object' |
Regexp | 'object' |
那么对于Number中三个特殊的数值执行 typeof 运算,其返回值是什么呢?
csharp
typeof NaN
> "number"
typeof Infinity
> "number"
typeof -Infinity
> "number"
通过上述的内容,可知在这其中只有两个类型的值是不符合预期的,一个是Null(预期应该是'null'),另外一个是Function(预期应该是'object'),那具体原因是为什么呢?
typeof null
在JavaScript最初的实现中,JavaScript 中的值都是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下由机器码 NULL 指针表示,其值为 0x00),因此,null 的类型标签是 0,typeof null 也因此返回 'object'。
曾有一个 ECMAScript 的修复提案(通过选择性加入的方式),但被拒绝了,因为目前有很多程序代码是依靠 typeof null === 'object' 来实现逻辑的,因此这个缺陷将一直会保留,永远不会被修复。
csharp
typeof null
> "object"
标签 | 类型 |
---|---|
000 | 对象 |
1 | 整数 |
010 | 浮点数 |
100 | 字符串 |
110 | 布尔 |
typeof Function
这里贴一段ECMAScript规范的文档,其中明确的表明了 typeof 去检测引用类型的时候,会去看这个引用类型内部有没有 [[call]] 方法,如果有,则返回 function ;如果没有,则返回object
通过上面的分析可知,typeof
操作符适合对 基本类型 (除 null
之外)及 function
的检测使用,而对引用数据类型(如 Array)等不适合使用。
instanceof
instanceof
运算符 用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上。
instanceof
运算符左操作数为对象,不是就返回 false,右操作数必须为函数对象或者函数构造器,不是就返回TypeError。
typescript
1 instanceof Number
> false
new Number(1) instanceof Number
> true
1 instanceof 3
> Uncaught TypeError: Right-hand side of 'instanceof' is not an object
at <anonymous>:1:3
instanceof
适合用于判断对象是否属于 Array、Date 和 RegExp 等内置对象。
不同 window 或 iframe
之间的对象类型检测无法使用 instanceof
检测。
instanceof实现
javascript
function myInstanceOf(left, right) {
let proto = left.__proto__; // 实例对象的原型
let prototype = right.prototype; // 构造函数的原型
if (proto === null || prototype === null) {
return false
} else if (proto === prototype) {
return true;
} else {
myInstance(proto, right) // 递归遍历原型链
}
}
Object.prototype.toString
toString()
方法返回一个表示该对象的字符串 "[object Type]" ,这里的 Type
是对象的类型。
所有继承自 Object.prototype
的对象(即,除了 null
-prototype 对象之外的对象)都继承 toString()
方法。当你创建一个自定义对象时,你可以重写 toString()
以调用自定义方法,以便将自定义对象转换为一个字符串。Object.prototype.toString
属于 Object 的原型方法,而 Array 或 Function 等类型作为 Object 的实例,都重写了 toString
方法。因此,不同对象类型调用 toString
方法时,调用的是重写后的 toString
方法,而非 Object
上原型 toString
方法,所以采用 xxx.toString()
不能得到其对象类型,只能将 xxx
转换成字符串类型,因此只有使用 Object.prototype.toString
方法才能精准地判断出值的数据类型。其各类型对应的返回值如下:
类型 | 值 |
---|---|
Undefined | "[object Undefined]" |
Null | "[object Null]" |
Boolean | "[object Boolean]" |
Number | "[object Number]" |
BIgInt | "[object BigInt]" |
String | "[object String]" |
Symbol | "[object Symbol]" |
Function | "[object Function]" |
Object | "[object Object]" |
Daten | "[object Date]" |
Array | "[object Array]" |
Regexp | "[object RegExp]" |
改写toString
javascript
class People {
constructor(name) {
this.name = name;
}
}
const lilei = new People('lilei');
lilei.toString()
> "[object Object]" // 未改写
class People {
constructor(name) {
this.name = name;
}
toString() {
return this.name
}
}
const lilei = new People('lilei');
lilei.toString()
> "lilei" // 改写
Constructor
任何对象都有 constructor
属性,继承自原型对象,根据原型链之间的关系constructor
会指向构造这个对象的构造器或构造函数,因此可以通过constructor
属性来判断对象的类型。
ini
class People {
constructor(name) {
this.name = name;
}
}
const lilei = new People('lilei');
lilei.constructor === People
> true
数组检测
ECMAScript5 将 Array.isArray()
正式引入 JavaScript,该方法能准确检测一个变量是否为数组类型。
ini
Array.isArray(variable);
答案
问1:类型检测的方法有哪些,平时一般都是怎么使用的?
javascript
答:类型检测一般有 typeof、instanceof、Object.protorype.toString以及Constructor。其中 typeof常用于
基本数据类型(除null)和 Function 的检测使用,instanceof 常用于引用类型的使用,其中数组可以使用
ECMAScript5 中新引入的 `Array.isArray()` 来检测,而Object.protorype.toString 和 Constructor 可以适
用于所有的类型检测。
问2:typeof null 的结果是什么,为什么?
csharp
答:结果为 object
因为在JavaScript最初的实现中,JavaScript 中的值都是由一个表示类型的标签和实际数据值表示的。对象的类型标
签是 0。由于 null 代表的是空指针(大多数平台下由机器码 NULL 指针表示,其值为 0x00),因此,null 的类型
标签是 0,typeof null 也因此返回 'object'。
问3:typeof NaN 的结果是什么?
javascript
答:结果为 Number
因为全局属性 NaN 是一个表示非数字的值,所以其类型依然是Number。
问4:instanceof 操作符的实现原理及实现
javascript
答: instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
实现:
function myInstanceof(left, right) {
let proto = left.__proto__;
let prototype = right.prototype;
if(proto === null || prototype === null) {
return false;
} else if (protp === prototype) {
return true;
} else {
myInstance(proto, right);
}
}
参考:
[1] 262.ecma-international.org/#sec-typeof...
[2] developer.mozilla.org/zh-CN/docs/...
[3] 262.ecma-international.org/#sec-typeof...
[4] developer.mozilla.org/zh-CN/docs/...