typeof
对一个值使用typeof操作符可能返回:
undefined、string、number、boolean、symbol、object(对象或null)、function
console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof 'str'); // string
console.log(typeof []); // object []数组的数据类型在 typeof 中被解释为object
console.log(typeof function(){}); // function
console.log(typeof {}); // object
console.log(typeof undefined); // undefined
console.log(typeof null); // object null 的数据类型被 typeof 解释为 object
typeof 对于基本类型,除了null都可以显示正确的类型;对于对象,除了函数都会显示object。
对于null来说,虽然它是基本类型,但是会显示object,这是一个存在了很久的bug。
因为在js的最初版本中,使用的是32位系统,为了性能考虑使用低位存储了变量的类型信息,000开头代表是对象,然而null表示为全零,所以将它错误的判断为object。虽然现在的内部类型 判断代码已经改变了,但是对于这个bug却是一直流传下来。
instanceof
只有引用数据类型(Array,Function,Object)被精准判断,其他(数值Number,布尔值Boolean,字符串String)字面值不能被instanceof精准判断。
instanceof可以正确的判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找得类型的prototype。
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
console.log({} instanceof Object); // true
// console.log(undefined instanceof Undefined);
// console.log(null instanceof Null);
function Person(name, age) {
this.name = name;
this.age = age;
}
function Dog(name, age) {
this.name = name;
this.age = age;
}
var p = new Person('zs', 18);
var d = new Dog('小花', 8);
console.log(p instanceof Person); // true
console.log(d instanceof Person); // true
console.log(p instanceof Object); // false
constructor
console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // true
用costructor来判断类型看起来是完美的,然而,如果我创建一个对象,更改它的原型,这种方式也变得不可靠了。
function Person(name, age) {
this.name = name;
this.age = age;
}
var p = new Person('csm', 21);
console.log(p.constructor.name); // Person
// 改变原型
Person.prototype = {
name: 'zs',
age: 18
};
var p1 = new Person('csm', 21);
console.log(p1.constructor.name); // Object
因此,当要修改对象的proptotype时,一定要设置constructor指向其构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype = {
constructor: Person,
name: 'zs',
age: 18
};
var p = new Person('csm', 21);
console.log(p.constructor.name); // Person
object.prototype.toString.call()
console.log(Object.prototype.toString.call(2)); // [object Number]
console.log(Object.prototype.toString.call(true)); // [object Boolean]
console.log(Object.prototype.toString.call('str')); // [object String]
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call(function(){})); // [object Function]
console.log(Object.prototype.toString.call({})); // [object Object]
console.log(Object.prototype.toString.call(undefined)); // [object Undefined]
console.log(Object.prototype.toString.call(null)); // [object Null]
使用 Object 对象的原型方法 toString ,使用 call 进行狸猫换太子,借用Object的 toString 方法结果精准的显示我们需要的数据类型。就算我们改变对象的原型,依然会显示正确的数据类型。