JavaScript 是一种弱类型或者说动态语言。这意味着你不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。
这也意味着你可以使用同一个变量保存不同类型的数据。
最新的 ECMAScript 标准定义了 7 种数据类型:
6种原始类型:Boolean、Null、Undefined、Number、String、Symbol (ECMAScript 6 新定义)和Object,除 Object 以外的所有类型都是不可变的(值本身无法被改变)。
typeof操作符返回一个字符串,表示未经求值的操作数(unevaluated operand)的类型。查看在线代码:
// 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 blabla === ‘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‘; // 从JavaScript一开始出现就是这样的 typeof null === ‘object‘;
// 正则表达式 typeof /s/ === ‘object‘; // Chrome 12+ , 符合 ECMAScript 5.1 typeof /s/ === ‘object‘; // Firefox 5+ , 符合 ECMAScript 5.1 // 函数 typeof function(){} === ‘function‘; typeof Math.sin === ‘function‘; typeof /s/ === ‘function‘; // Chrome 1-12 , 不符合 ECMAScript 5.1
可以通过使用toString.call(obj)来检测对象类型。
可以用来检测Object、Number、Array、Date、Function、String、Boolean、Error和RegExp。
下面的代码与上面的代码做了一一比较,其中在注释中有标红的“不同”,说明有区别。查看在线代码:
var toString = Object.prototype.toString; // Numbers 都返回[object Number] toString.call(37); toString.call(3.14); toString.call(Math.LN2); toString.call(Infinity); toString.call(Number(1)); // Strings 都返回[object String] toString.call(""); toString.call("bla"); toString.call(String("abc")); // Booleans 都返回[object Boolean] toString.call(true); toString.call(false); toString.call(Boolean(true)); // Symbols 都返回[object Symbol] toString.call(Symbol()); toString.call(Symbol(‘foo‘)); toString.call(Symbol.iterator); // Undefined 都返回[object Undefined] toString.call(undefined); //toString.call(blabla);//不同 一个未定义的变量会报错 // Objects toString.call({a:1});//[object Object] toString.call([1, 2, 4]);//[object Array] 不同 toString.call(new Date());//[object Date] 不同 toString.call(new Boolean(true));//[object Boolean] 不同 toString.call(new Number(1));//[object Number] 不同 toString.call(new String("abc"));//[object String] 不同 toString.call(null);//[object Null] 不同 toString.call(/s/);//[object RegExp] 不同 toString.call(new TypeError());//[object Error] 不同 // 函数 都返回[object Function] toString.call(function(){}); toString.call(Math.sin);
instanceof 运算符可以用来判断某个构造函数的 prototype 属性是否存在另外一个要检测对象的原型链上,返回boolean值。语法如下:
object:要检测的对象,constructor:某个构造函数。查看在线代码:
1 // 定义构造函数 2 function C(){} 3 function D(){} 4 5 var o = new C(); 6 o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype 7 //o.__proto__={}; //改变o原型链,o instanceof C将会返回false 8 o instanceof D; // false,因为 D.prototype不在o的原型链上 9 o instanceof Object; // true,因为Object.prototype.isPrototypeOf(o)返回true 10 C.prototype instanceof Object // true,同上 11 12 C.prototype = {}; 13 var o2 = new C(); 14 o2 instanceof C; // true 15 o instanceof C; // false,C.prototype指向了一个空对象,这个空对象不在o的原型链上. 16 17 D.prototype = new C(); // 继承 18 var o3 = new D(); 19 o3 instanceof D; // true 20 o3 instanceof C; // true
有两种方式可以将"o instanceof C"返回“false”:
1、注意上面代码的第12行,改变了函数C.prototype属性,改变之后导致这个对象不在o的原型链上。
2、改变对象o的原型链,借助于非标准的__proto__魔法属性可以实现。比如代码的第7行执行o.__proto__ = {}。
这里需要注意一个地方,就是Object.prototype.isPrototypeOf()与instanceof的区别。请看下面的代码:
var human = function() {} var socrates = Object.create(human); console.log(human.isPrototypeOf(socrates)); // true console.log(socrates instanceof human); // false console.log(socrates.__proto__ == human.prototype);//false console.log(socrates.__proto__ == human);//true
上面的Object.create()传递的是human函数,“socrates.__proto__ == human.prototype”不想等,
也就是说human.prototype不在socrates的原型链上,所以instanceof返回的是false。
isPrototypeOf() 是指测试一个对象是否存在于另一个对象的原型链上;现在human这个对象在socrates的原型链上。
constructor返回一个指向创建了该对象原型的函数引用。
需要注意的是,该属性的值是那个函数本身,而不是一个包含函数名称的字符串。对于原始值(如1,true 或 "test"),该属性为只读。
所有对象都会从它的原型上继承一个 constructor 属性。查看在线代码。
1、在JavaScript的继承中,instanceof和constructor表现的是不一样的:
function C(){} function D(){} D.prototype = new C(); // 继承 var o = new D(); o instanceof D; // true o instanceof C; // true o.constructor == D; // false o.constructor == C; // true o.constructor == D.prototype.constructor;//true o.constructor == Object.prototype.constructor;// false
对象的constructor属性是根据函数的prototype.constructor来的。
2、改变这个对象的constructor属性的值,只有 true, 1 和 "test" 的不受影响,其他的都变成了"function type(){}"
function Type() { }; var types = [ new Array, [], new Boolean, true, // remains unchanged new Date, new Error, new Function, function(){}, Math, new Number, 1, // remains unchanged new Object, {}, new RegExp, /(?:)/, new String, "test" // remains unchanged ]; for(var i = 0; i < types.length; i++) { types[i].constructor = Type; types[i] = [ types[i].constructor, types[i] instanceof Type, types[i].toString() ]; console.log(types[i]); };
下图分别是“new Boolean” 和 “true”的打印结果:
参考资料:
http://www.cnblogs.com/ecalf/archive/2012/12/03/2799968.html JavaScript对象及原型继承有关的属性
http://anykoro.sinaapp.com/2012/01/31/javascript%E4%B8%ADfunctionobjectprototypes__proto__%E7%AD%89%E6%A6%82%E5%BF%B5%E8%AF%A6%E8%A7%A3/ Javascript中Function,Object,Prototypes,__proto__等概念详解
http://rockyuse.iteye.com/blog/1426510 理解js中的原型链,prototype与__proto__的关系
http://www.cnblogs.com/snandy/archive/2012/09/01/2664134.html JavaScript中__proto__与prototype的关系
http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html Javascript继承机制的设计思想
JavaScript中typeof、toString、instanceof与constructor
原文:http://www.cnblogs.com/strick/p/4979949.html