js 类型检测
typeof
typeof 操作符返回一个字符串,表示未经计算的操作数的类型。
语法
typeof operand 或者 typeof (operand)
描述
下表总结了typeof可能的返回值
类型 | 结果 |
---|---|
Undefined | “undefined” |
Null | “object” |
Boolean | “boolean” |
Number | “number” |
String | "string " |
Symbol (ECMAScript 6 新增) | “symbol” |
宿主对象(由JS环境提供) | “Implementation-dependent” |
函数对象([[Call]] 在ECMA-262条款中实现了) | “function” |
任何其他对象 | “object” |
示例
// Numbers
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 尽管NaN是"Not-A-Number"的缩写
typeof Number(1) === 'number'; // 但不要使用这种形式!
// Strings
typeof "" === 'string';
typeof "bla" === 'string';
typeof (typeof 1) === 'string'; // typeof总是返回一个字符串
typeof String("abc") === 'string'; // 但不要使用这种形式!
// Booleans
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(true) === 'boolean'; // 但不要使用这种形式!
// Symbols
typeof Symbol() === 'symbol';
typeof Symbol('foo') === 'symbol';
typeof Symbol.iterator === 'symbol';
// Undefined
typeof undefined === 'undefined';
typeof declaredButUndefinedVariable === 'undefined';
typeof undeclaredVariable === 'undefined';
// Objects
typeof {a:1} === 'object';
// 使用Array.isArray 或者 Object.prototype.toString.call
// 区分数组,普通对象
typeof [1, 2, 4] === 'object';
typeof new Date() === 'object';
// 下面的容易令人迷惑,不要使用!
typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String("abc") === 'object';
// 函数
typeof function(){} === 'function';
typeof class C{} === 'function'
typeof Math.sin === 'function';
typeof new Function() === 'function';
使用new 操作符号
// All constructor functions while instantiated with 'new' keyword will always be typeof 'object'
//所有使用new 和构造函数创建的对象 使用typeof 都会返回 ‘object’
var str = new String('String');
var num = new Number(100);
typeof str; // It will return 'object'
typeof num; // It will return 'object'
// But there is a exception in case of Function constructor of Javascript
// 只有一个例外 那就是 Function 构造函数
var func = new Function();
typeof func; // It will return 'function'
正则表达式
对正则表达式字面量的类型判断在某些浏览器中不符合标准:
typeof /s/ === 'function'; // Chrome 1-12 , 不符合 ECMAScript 5.1
typeof /s/ === 'object'; // Firefox 5+ , 符合 ECMAScript 5.1
暂存死区
typeof undeclaredVariable === 'undefined';
typeof newLetVariable; let newLetVariable; // ReferenceError
typeof newConstVariable; const newConstVariable = 'hello'; // ReferenceError
IE 特别提示
在IE 6,7和8上,很多宿主对象是对象而不是函数。例如:
typeof alert === 'object'
instanceof
instanceof运算符用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置
语法
object instanceof constructor
object: 要检测的对象.
constructor: 某个构造函数
描述
instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
// 定义构造函数
function C(){}
function D(){}
var o = new C();
o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype
o instanceof D; // false,因为 D.prototype不在o的原型链上
o instanceof Object; // true,因为Object.prototype.isPrototypeOf(o)返回true
C.prototype instanceof Object // true,同上
C.prototype = {};
var o2 = new C();
o2 instanceof C; // true
o instanceof C; // false,C.prototype指向了一个空对象,这个空对象不在o的原型链上.
D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true 因为C.prototype现在在o3的原型链上
需要注意的是,如果表达式 obj instanceof Foo 返回true,则并不意味着该表达式会永远返回true,因为Foo.prototype属性的值有可能会改变,改变之后的值很有可能不存在于obj的原型链上,这时原表达式的值就会成为false。另外一种情况下,原表达式的值也会改变,就是改变对象obj的原型链的情况,虽然在目前的ES规范中,我们只能读取对象的原型而不能改变它,但借助于非标准的__proto__伪属性,是可以实现的。比如执行obj.proto = {}之后,obj instanceof Foo就会返回false了。
instanceof和多全局对象(多个frame或多个window之间的交互)
在浏览器中,我们的脚本可能需要在多个窗口之间进行交互。多个窗口意味着多个全局环境,不同的全局环境拥有不同的全局对象,从而拥有不同的内置类型构造函数。这可能会引发一些问题。比如,表达式 [] instanceof window.frames[0].Array 会返回false,因为 Array.prototype !== window.frames[0].Array.prototype,并且数组从前者继承。
起初,你会认为这样并没有意义,但是当你在你的脚本中开始处理多个frame或多个window以及通过函数将对象从一个窗口传到另一个窗口时,这就是一个有效而强大的话题。比如,实际上你可以通过使用 Array.isArray(myObj) 或者Object.prototype.toString.call(myObj) === "[object Array]"来安全的检测传过来的对象是否是一个数组。
比如检测一个Nodes在另一个窗口中是不是SVGElement,你可以使用myNode instanceof myNode.ownerDocument.defaultView.SVGElement
示例
演示String对象和Date对象都属于Object类型和一些特殊情况
下面的代码使用了instanceof来证明:String和Date对象同时也属于Object类型(他们是由Object类派生出来的)。
但是,使用对象文字符号创建的对象在这里是一个例外:虽然原型未定义,但instanceof Object返回true。
var simpleStr = "This is a simple string";
var myString = new String();
var newStr = new String("String created with constructor");
var myDate = new Date();
var myObj = {};
var myNonObj = Object.create(null);
simpleStr instanceof String; // 返回 false, 检查原型链会找到 undefined
myString instanceof String; // 返回 true
newStr instanceof String; // 返回 true
myString instanceof Object; // 返回 true
myObj instanceof Object; // 返回 true, 尽管原型没有定义
({}) instanceof Object; // 返回 true, 同上
myNonObj instanceof Object; // 返回 false, 一种创建对象的方法,这种方法创建的对象不是Object的一个实例
myString instanceof Date; //返回 false
myDate instanceof Date; // 返回 true
myDate instanceof Object; // 返回 true
myDate instanceof String; // 返回 false
演示mycar属于Car类型的同时又属于Object类型
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
var mycar = new Car("Honda", "Accord", 1998);
var a = mycar instanceof Car; // 返回 true
var b = mycar instanceof Object; // 返回 true
不是一个实例
要测试对象是否不是特定构造函数的实例,你可以这样做
if (!(mycar instanceof Car)) {
// Do something, like mycar = new Car(mycar)
}
下面代码完全不同
if (!mycar instanceof Car)
这将永远是假的(!mycar将在instanceof之前被处理,所以你总是验证布尔值是否是Car的一个实例)。
安全检测
原因:当检测对象的原型时 instanceof 存在缺陷
- iinstanceof 在一个页面包含多个iframe时问题多多
- 无法确定某个对象是不是原生对象
function getType (value){
return Object.prototype.toString.call(value)
}
//JavaScript 中一切都是对象,任何都不例外,对所有值类型应用 Object.prototype.toString.call() 方法结果如下:
getType('hello') // "[object String]"
getType(123) //"[object Number]"
getType(true) // "[object Boolean]"
getType(Symbol(1)) // "[object Symbol]"
getType(null) // "[object Null]"
getType() // "[object Undefined]"
getType({}) // "[object Object]"
getType(Date) //"[object Function]"
getType([]) //"[object Array]"
getType(new Date()) //"[object Date]"
getType(JSON) // "[object JSON]"
总结
- typeof 可以检测 除了 null、Object、Array 以外的数据类型
- instanceof 可以目标对象的原型的链是否包含某个构造函数
- Object.prototype.toString.call() 可以检测所有的数据类型比较好用。