constructor属性
构造函数预定义的constructor属性是构造函数本身。
var foo = function(){};
foo.prototype.constructor === foo;//true通过new调用构造函数所生成的对象以构造函数的prototype属性为原型。虽然javascript中没有类的概念,但是构造函数的作用同类的名称相似,是对象类型的标识。访问对象继承的constructor属性可以查看对象的类型。原始类型的变量也可以访问constructor属性,因为在访问的时候javascript形成了一个包装对象。
1 //basic objects
2 var obj = {name: obj};
3 obj.constructor === object;//true
4
5 //self defined class
6 var foo = function(){};
7 var f = new foo();
8 f.constructor === foo;//true
9
10 //primitive types
11 //number
12 var num = 1;
13 num.constructor === number;//true
14 var nan = nan;
15 nan.constructor === number;//true
16 //boolean
17 var b = true;
18 b.constructor === boolean;//true
19 //string
20 var s = string;
21 s.constructor === string;//true
22 //function
23 var fun =function(){};
24 fun.constructor === function;//true;然而,constructor属性是可以重新复制或者覆盖的,这会引起类型判断的错误。即使我们一般不会刻意去给constructor属性赋值,但是有一些情况下constructor属性的值和我们所期望的值不同。看下面例子:
var baseclass = function(){};
var derivedclass = function(){};
derivedclass.prototype = new baseclass();
var obj = new derivedclass();
obj.constructor === derivedclass;//false;
obj.constructor === baseclass;//true;因为子类的prototype以父类的实例为原型,所以通过子类实例访问constructor就是父类构造函数。因此在javascript面向对象编程中,我们会在定义子类时加上一句代码来纠正constructor属性。
derivedclass.prototype.constructor = derivedclass;使用constructor进行判断变量类型虽然方便,但是不见得特别安全,所以需要小心。
cross-frame和cross-window问题:
如果判断来自不同frame或来自不同window的变量的对象的类型,那么constructor属性无法正常工作。因为不同window的核心类型不同[1]。
使用instanceof操作符
instanceof操作符判断一个对象的原型链中是否存在某个构造函数的prototype属性[2]。原型链的概念可以阅读javascript面向对象编程(一)原型与继承。下面的代码形成了原型链obj1->derivedclass.prototype->baseclass.prototype->...->object.prototype。object.prototype是所有对象的原型,anyobj instanceof object === true。
var baseclass = function(){};
var derivedclass = function(){};
derivedclass.prototype = new baseclass();//use inheritance
var obj1 = new derivedclass();
obj1 instanceof baseclass;//true
obj1 instanceof derivedclass;//true
obj1 instanceof object;//true
obj2 = object.create(derivedclass.prototype);
obj2 instanceof baseclass;//true
obj2 instanceof derivedclass;//true
obj2 instanceof object;//trueconstructor属性可以应用到除了null和undefined之外的原始类型(数字、字符串、布尔类型)。而instanceof不可,但是可以使用包装对象的方法进行判断。
3 instanceof number // false
'abc' instanceof string // false
true instanceof boolean // false
new number(3) instanceof number // true
new string('abc') instanceof string //true
new boolean(true) instanceof boolean //true然而,instanceof在cross-frame和cross-window的情况下也无法正常工作。
使用 object.prototype.tostring()方法
object.prototype.tostring()方法是一个底层的方法,使用它可以返回一个字符串,该字符串表明了对象的类型。也可以用于判断null和undefined。下面列出了多数常见的类型。
object.prototype.tostring.call(3);//[object number]
object.prototype.tostring.call(nan);//[object number]
object.prototype.tostring.call([1,2,3]);//[object array]
object.prototype.tostring.call(true);//[object boolean]
object.prototype.tostring.call(abc);//[object string]
object.prototype.tostring.call(/[a-z]/);//[object regexp]
object.prototype.tostring.call(function(){});//[object function]
//null and undefined in chrome and firefox. in ie [object object]
object.prototype.tostring.call(null);//[object null]
object.prototype.tostring.call(undefined);//[object undefined]
//self defined objects
var a = new foo();
object.prototype.tostring.call(a);//[object object]
//typed wrappers
var b = new boolean(true);
object.prototype.tostring.call(b);//[object boolean]
var n = new number(1);
object.prototype.tostring.call(n);//[object number]
var s = new string(abc);
object.prototype.tostring.call(s);//[object string]经常会使用slice方法截取结果中类型的信息:
object.prototype.tostring.call(abc).slice(8,-1);//string使用typeof 运算符
在mdn的一篇文档中已经很详细介绍了这个[3]。typeof能返回的信息较少,有undefined、object、boolean、number、string、function、xml这几种。
type result
undefined undefined
null object
boolean boolean
number number
string string
host object (provided by the js environment) implementation-dependent
function object (implements [[call]] in ecma-262 terms) function
e4x xml object xml
e4x xmllist object xml
any other object object
// numbers
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof math.ln2 === 'number';
typeof infinity === 'number';
typeof nan === 'number'; // despite being not-a-number
typeof number(1) === 'number'; // but never use this form!
// strings
typeof === 'string';
typeof bla === 'string';
typeof (typeof 1) === 'string'; // typeof always return a string
typeof string(abc) === 'string'; // but never use this form!
// booleans
typeof true === 'boolean';
typeof false === 'boolean';
typeof boolean(true) === 'boolean'; // but never use this form!
// undefined
typeof undefined === 'undefined';
typeof blabla === 'undefined'; // an undefined variable
// objects
typeof {a:1} === 'object';
typeof [1, 2, 4] === 'object'; // use array.isarray or object.prototype.tostring.call to differentiate regular objects from arrays
typeof new date() === 'object';
typeof new boolean(true) === 'object'; // this is confusing. don't use!
typeof new number(1) === 'object'; // this is confusing. don't use!
typeof new string(abc) === 'object'; // this is confusing. don't use!
// functions
typeof function(){} === 'function';
typeof math.sin === 'function';
typeof undefined;//undefined
typeof null;//object this stands since the beginning of javascript
typeof /s/ === 'object'; // conform to ecmascript 5.1typeof 包装对象的结果是‘object’需要注意。这里不评价好与不好(如果需要区分包装对象和原始类型呢)。但是typeof不是一个健壮的方法,要小心使用。比如:
var s = i am a string;
typeof s === string;
//add a method to string
string.prototype.a_string_method = function(){
console.log(this.valueof());
console.log(typeof this);
};
s.a_string_method();
//i am a string
//object
