说在前面
JavaScript作为前端当家的语言,其重要程度不言而喻,一些基础的语法以及概念之前经常有看,但是随看随忘,过程中有一些自己觉得惊鸿一瞥的发现也随着时间消失不见,特此开一个专题,把往往种种的体会分享出来,供自己回顾以及各位拿取。
开门见山
其实在阅读一些源码或者封装的代码时,经常会看到 使用 typeof
或者 instanceof
来进行一些判断,有时不能很好地理解判断的具体含义,下面通过分析这两者的使用方式以及自身特性来加强理解。
typeof
语法: typeof operand
后面可以紧跟表示对象或者原始值的表达式,他会返回表达式的类型。
那么他判断的所有类型都是准确无误的嘛?或者说,他返回的类型都是我们想看到的吗?显然不是,比如JavaScript
最初设计中的一个小“瑕疵”,
typeof null // 'object'
我们不能说他错,但是我们在实际使用的过程中可不希望把null 判断成为一个object,因为这样会导致一些严重的错误。
用一句简单的话来说 typeof
可以准确的判断结果不为 object
的类型的数据,别急,后面我们会印证这个观点。
下面我们一起来看一下typeof
关键字在判断类型时的一些表现:
typeof 37 // 'number'
typeof Nan // 'number' 注意,特殊类型的number,not a number的number
typeof true // 'boolean'
typeof '1' // 'string'
typeof String('1') // 'string'
typeof Symbol() // 'symbol'
typeof undefined // 'undefined'
typeof function() {} // 'function'
typeof {a: 1} // 'object' 一直到这里,所有得到的数据类型都是我们想得到的
------------------------------------------------我是分界线--------------------------------------------
var a = [1,2,3]
typeof a // 'object', 数组是一种特殊的对象,判断是否为数组,需要使用Array.isArray方法
typeof null // 'object' 可以通过 operand === null 判断是否为 null
typeof new Date() // 'object'
typeof new String('a')
// 'object',如果你打印过控制台的信息,你会看到得到的结果是 String {"a"},确实展示形式是对象,但是我们使用
// 过程中会将其理解为字符串(当然他在使用过程中和字符串无异,但是他在内存中确实是以String {"a"}存在)
从上述例子中可以看出typeof
对于一些创建类型的数据(使用了new 关键字)都会返回 object
,虽说返回了内存中正确的存在形式,但结果可能并不是我们想要得到的。所以说 typeof
关键字,返回的不为 object
类型的数据都是准确的,但是对于返回类型为 object
的数据,我们需要斟酌一下实际的结果。
延伸一刻:如果我们想判断一个数据表达式是否为object
类型,要如何判断?
// we got a referance named a
if (typeof a !== null && typeof a === 'object') {
return true
}
唉? 刚才不是说typeof
判断的类型为object
的不准吗?怎么现在又这样写呢?其实根据上述结果,new String('123')
虽然我们想得到的结果是string
,但是说他是一个object
却没有任何问题!
instanceof
语法: object instanceof constructor
用来检测constructor.protype
是否 存在于参数 object
的原型链上。一定注意,后面跟的是一个构造函数。
一言以蔽之:可以准确判断复杂引用的数据类型,但不能正确判断基础数据类型。
var d = new Date()
d instanceof Date // true
var s = new String('cctv')
s instanceof String // true s在控制台打印出来的结果是 String{"cctv"}
var str = 'cctv'
str instanceof String // false 这是怎么回事? 参见下方分析。
Object.getPrototypeOf(str) === String.prototype
// true 确实符合了概念,看似存在于str的原型链上,但是str自身并不是一个 object
由此可以判断,instanceof
在内部实现中,会判断 instanceof
左侧是否为 object
。如果不是,返回 false
。
再有,原型链是具有传递性的:
function C() {}
var o = new C();
o instanceof C // true Object.getPrototypeOf(o) === C.prototype
C.prototype instanceof Object // true Object.getPrototypeof(C.prototype) === Object.prototype
o instanceof Object // true 原型链的传递性
由此可以分析得出,原生js
在实现 instanceof
的时候,会循环遍历左侧object
的 Object.getPrototypeOf('object')
属性,并与 constructor.prototype
进行对比,如果相等,则返回 true,如果不相等则继续排查,直到 Object.getPrototypeOf('object')
的结果为 null
则返回 false
。
综上二者提出的概念,可以简单的实现一个 自己的instanceof
,网上例子很多,这里不贴代码了,根据我的经验,贴上来代码大家很少会自己实践,just try it.
最佳类型判断实践
可曾听闻十三太保之 toString
,这是个很神奇的方法,每个对象都继承了来自object
的这个是属性,他可以被重写来完成一些特殊的任务,这里主要介绍他的默认用法,返回 [object class]
,其中class
是该对象的类,可以为 Object,Number,Function,Date,Window,HTMLDocument
等。
function getType(obj){
// 对于typeof返回结果是object的,再进行如下的判断,正则返回结果
return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1');
}
getType(window) // Window
getType(new Date()) // Date
getType(document) // HTMLDocument
参考网站: