类型检测

以下为《JavaScript.info》教程的部分译文。

类型检测

注:有背景色的为注释,非原文内容

  1. Typeof运算符
    1.原始值
    2.typeof的正确用法
    3.typeof的错误用法

2.[[class]]区分本地对象

3.检查自定义对象的类型

4.综述

多态函数是一个很好的编程概念,这种函数对不同类型参数的处理方式不同。

为了支持多态性,我们需要一种获得变量类型的方法。这里是一个小型的JS动物园[这里的zoo翻译需确认],让我们来看看吧。

众所周知,Javascript中有许多原始类型:
nullundefined
  特殊值。
  
number
  所有数字,如03.14,同样包括伪数值NaNInfinity

boolean
  Truefalse
string
  字符串,如“Meow”和“”。

Typeof运算符

其他值均为对象。举例,如函数和数组都是对象。
typeof运算符返回一个值的数据类型。有以下两种可行的语法:
1.运算符:typeof x
2.类函数:typeof(x)
以上两种语法作用相同,但第一种更为简短。

typeof undefined // "undefined"
typeof 0  //"number"
typeof true   //"boolean"
typeof "foo"  //"string"
typeof {} //"object"
typeof null //"object"
typeof function(){} //"function"
typeof NaN //"number"

可以发现最后三行为红色。[上述代码少了红色背景]原因如下。
1.第一, typeof null == "object"是这个语言的一个官方错误,是为了兼容性性而从90x[不明白90x什么意思]保持的。
我们可以确认:

var x = null
x.prop = 1 // error, can't assign a property to primitive

2.尽管对函数进行特殊对待,但仍然属于对象。
3.typeof NaN == 'number'十分可笑,因为NaN是'Not-A-Number'的缩写。

原始值

typeof在处理原始值(null除外)的效果很好。但是它没有对对象类型进行任何的说明。
typeof 不能区分对象
举个例子,Object,Array和Date对象得到的结果相同。

alert( typeof {} ) // 'object'
alert( typeof [] ) // 'object'
alert( typeof new Date ) // 'object'

我们也可以发现原始字符串和new String之间的不同。

alert( typeof "lalala" ) // string
alert( typeof new String("lalala") ) // object

typeof 的正确用法

让我们写一个多态函数。

function f(x) {
 if (typeof x == 'function') {
    ... // in case when x is a function
  } else {
    ... // in other cases
  }
}

这是一个合理的使用。

typeof 的错误用法

与现在的模式相反。在以前的代码中可以发现利用typeof来测试已经存在的变量:

// check if global variable jQuery exists
if(typeof(jQuery) !== 'undefined') ...

这里使用typeof是因为直接使用一个未定义的变量会出错:

// error if jQuery is not defined
if(jQuery) { .. }

千万别用这种方式使用typeof
一个全局变量可以作为window对象内置的属性来访问。让我们来确认一下:

if(window.jQuery !== undefined) { ... }

这样不会发生错误,因为没人会要求(可能未定义)jQuery。我们仅仅要求对象的属性。
在大多数情况下,比如这里,我们知道jQuery如果存在的话不可能是错误的,所以检测可以简写为:

if(window.jQuery) { ... }

typeof不能用于检测已经存在的变量

[[class]]区分原生对象

typeof 的主要问题在于它不告诉我们对象的更多信息。function是个例外。

alert( typeof {key:'val'} ) // Object is object
alert( typeof [1,2] ) // Array is object
alert( typeof new Date ) // Date object

幸运的是,Javascript原生对象中有一个隐藏的[[class]]属性。它等同于"Arrays"对应arrays,"Date"对应dates等。
这个属性不能直接访问,但是可以借用本地对象的toString方法返回一个小数据包[小数据包?哈哈]

var toClass = {}.toString // (1)
alert( toClass.call( [1,2] ) ) // [object Array]
alert( toClass.call( new Date ) ) // [object Date]

这里我们是这样做的:
1.把一个对象的toString赋值给toClass.
2.提供我们需要检查的对象并调用这个方法.所以,对象toString开始应用于数组、日期等。我们必须这么做,因为他们自身toString行为不同。对于数组而言,返回一个元素列表,日期类型的则返回对应的字符串。
这个方法同样适用于原始值:

alert( toClass.call(123) ) // [object Number]
alert( toClass.call("primitive") ) // [object String]

null和undefined除外,因为通过null和undefined调用call把window传递给了this。

对于自定义对象,[[class]]为"Object":

function Animal(name) { 
  this.name = name
}
var animal = new Animal("Goofy")
var class = {}.toString.apply( animal )
alert(class) // [object Object]

所以,这只能用于本地对象。

自定义对象的类型检查

通过构造函数创建的对象,我们通常使用instanceof 操作符。
语法为 obj instanceof Func:

function Animal(name) { 
  this.name = name
}
var animal = new Animal("Goofy")
alert( animal instanceof Animal ) // true

更多讨论见文章"instanceof"操作符

目前,对于本地对象而言,[[class]]方法比较好并且被应用于大多数的框架。

为什么不使用"arr instanceOf Array"?
我们可以通过instanceof运算符检测一个数组:

var arr = [1,2,3]
alert(arr instanceof Array) // true

尽管如此,如果arr是在别的窗口或者内嵌框架(iframe)创建后再传递进来的,instanceof将不起作用。这是因为每个窗口都有自己的对象层次。
为了解决这个问题,对于本地对象,大多数框架使用[[class]]。

综述

typeof
适用于原始类型和函数,不适用于null.
[[class]]
通过{}.toString暴露。适用于内置对象和原始类型,null和undefined除外。
instanceof
适用于自定义对象。也可用于本地对象,但不适用于从其他窗口或内嵌框架(iframe)传递的本地对象。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容