首先,总结判断数据类型的方法:
1.typeof:一般判断基本数据类型
2.instanceof :一般判断引用数据类型,主要的作用就是判断一个实例是否属于某种类型,或者判断一个实例是否是其父类型或者祖先类型的实例。(原型链知识)
3. constructor:通过原型链继承属性判断。null和undefined是无效的对象,JS对象的constructor是不稳定的,这个主要体现在自定义对象上,当开发者重写prototype后,原有的constructor会丢失,constructor会默认为Object。
4. Object.prototype.toString.call():较为准确的判断方法。toString是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型。
二、深究原理
1.typeof
js提供了typeof运算符,用来检测一个变量的类型。
typeof是一个运算符,有2种使用方式:typeof(表达式)和typeof 变量名,第一种是对表达式做运算,第二种是对变量做运算。
目前能返回string,number,boolean,symbol,bigint,undefined,object,function这八种判断类型。示例:
console.log(typeof a); //'undefined'
console.log(typeof(true)); //'boolean'
console.log(typeof '123'); //'string'
console.log(typeof 123); //'number'
console.log(typeof NaN); //'number'
console.log(typeof null); //'object'
var obj = new String();
console.log(typeof(obj)); //'object'
var fn = function(){};
console.log(typeof(fn)); //'function'
console.log(typeof(class c{})); //'function'
总结:typeof运算符用于判断对象的类型,但是对于一些创建的对象,它们都会返回'object',有时我们需要判断该实例是否为某个对象的实例,那么这个时候需要用到instanceof运算符,后续记录instanceof运算符的相关用法。
2.instanceof
一般用来判断引用数据类型的判断,如:Object,Function,Array,Date,RegExp等。
原理:
<script>
// 判断一个实例是否属于某种类型
let animal = function() {};
let dog = new animal();
console.log(dog instanceof animal); //true
// 判断一个实例是否是其父类型或者祖先类型的实例
let person = function() {};
let jack = function() {};
jack.prototype = new person();
let a = new jack();
console.log(a instanceof person); //true
console.log(a instanceof jack); //true
// instanceof原理
function new_instanceof(leftValue, rightValue) {
let rightProto = rightValue.prototype;
leftValue = leftValue.__proto__;
while (true) {
if (leftValue === null) {
return false;
}
if (leftValue === rightProto) {
return true;
}
leftValue = leftValue.__proto__;
}
}
console.log(new_instanceof(a, person)); //true
console.log(new_instanceof(a, jack)); //true
console.log(new_instanceof(jack, person)); //false
console.log(new_instanceof(person, jack)); //false
</script>
3.constructor
4.Object.prototype.toString.call()
toString方法则是直接返回对象的类型,因此也就少了很多问题。不过这个方法对于那些不属于js内置类型的变量,检测为object类型。
在接触到这个方法的时候也是心存疑惑,为什么需要去object上取这个方法,而不是直接使用那个对象的toString方法呢?
因为JavaScript中的很多内置对象都重写了toString函数,跟最初的object上的函数功能已然不一样。
var toString = Object.prototype.toString;
toString.call(undefined); // "[object Undefined]"
toString.call(null); // "[object Null]"
toString.call(new String); // "[object String]"
toString.call("abc"); // "[object String]"
toString.call(new Number); // "[object Number]"
toString.call(123); // "[object Number]"
toString.call(new Array); // "[object Array]"
toString.call([1,2,3]); // "[object Array]"
toString.call(new Boolean); // "[object Boolean]"
toString.call(true); // "[object Boolean]"
toString.call(new Object); // "[object Object]"
toString.call({a: 1, b: 2}); // "[object Object]"
toString.call(new Function); // "[object Function]"
toString.call(function(x){ return x * x; }); // "[object Function]"
toString.call(Math); // "[object Math]"
toString.call(new Date); // "[object Date]"
三、补充原型链