1、判断数据类型有一下方法
typeofinstanceofconstructorObject.prototype.toString.call()
2、各个方法的使用方式
(1)typeof
typeof ""; //"string"
typeof 1; //"number"
typeof false; //"boolean"
typeof undefined; //"undefined"
typeof function(){}; //"function"
typeof {}; //"object"
typeof Symbol(); //"symbol"
typeof null; //"object"
typeof []; //"object"
typeof new Date(); //"object"
typeof new RegExp(); //"object"
typeof new Number(33) //"object"
typeof Null //"undefined"
总结:
typeof对基本类型做出准确的判断(除了null)。返回的数据类型有number、string、undefined、symbol、object、function。但都是小写。null返回的是object。因为不同对象在底层都是用二进制来表示的,在**js中二进制的前三位是000的话,表示的是object类型的数据,null的二进制全都是0**,所以typeof的时候是'object'。
(2) instanceof
var a= new Number(22);
a instanceof Number // true
a instanceof number // 报错!number is not defined
let num = 1
num instanceof Number // false
[] instanceof Array; // true
[] instanceof Object; // true
null instanceof Object //false
undefined instanceof Object //false
总结:
instanceof判断 A 是否是 B 的实例,instanceof左侧必须是对象,如果不是直接返回false。instanceof只能判断两个对象是否属于实例关系,不能具体判断一个对象实例属于哪种类型。
(3) constructor
当一个函数 F 被定义时,JS 引擎会为F 添加 prototype 原型,然后再在 prototype 上添加一个 constructor 属性,并让其指向自身。
var f=new F()
f.constructor===F // true
F.prototype={a:"XXXX"}
var ff=new F()
ff.constructor===F // false
ff.constructor // ƒ Object() { [native code] }
总结:
- 函数的
constructor是不稳定的,这个主要体现在自定义对象上,当开发者重写prototype后,原有的constructor引用会丢失,constructor会默认为Object。
(4) Object.prototype.toString.call()
toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]]。这是一个内部属性,其格式为 [object Xxx],其中Xxx就是对象的类型。
Object.prototype.toString.call("a")
// "[object String]"
Object.prototype.toString.call(undefined)
// "[object Undefined]"
Object.prototype.toString.call(null)
// "[object Null]"
Object.prototype.toString.call(new Date())
// "[object Date]"
那为什么不直接用obj.toString()呢?
console.log("Merlin".toString());//Merlin
console.log((1).toString());//1
console.log([1,2].toString());//1,2
console.log(new Date().toString());//Wed Dec 21 2016 20:35:48 GMT+0800 (中国标准时间)
console.log(function(){}.toString());//function (){}
console.log(null.toString());//报错
console.log(undefined.toString());//报错
这是因为toString为Object的原型方法,而Array ,function等类型作为Object的实例,都重写了toString方法。
不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法。(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串.....),而不会去调用Object上原型toString方法(返回对象的具体类型),所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型。
因此,在想要得到对象的具体类型时,应该调用Object上原型toString方法。
现将数组的toString方法删除
var arr=[1,2,3];
console.log(Array.prototype.hasOwnProperty("toString"));//true
console.log(arr.toString());//1,2,3
delete Array.prototype.toString;//delete操作符可以删除实例属性
console.log(Array.prototype.hasOwnProperty("toString"));//false
console.log(arr.toString());//"[object Array]"
3、深入理解Object.prototype.toString方法
ECMAScript 3
在toString方法被调用时,会执行下面的操作步骤:
- 获取
this对象的[[Class]]属性的值. - 计算出三个字符串
[object ", 第一步的操作结果Result(1), 以及 "]连接后的新字符串. - 返回第二步的操作结果
Result(2).
[[Class]]是一个内部属性,所有的对象(原生对象和宿主对象)都拥有该属性。
[[Class]] 一个字符串值,表明了该对象的类型。
所有内置对象的[[Class]]属性的值是由本规范定义的.
所有宿主对象的[[Class]]属性的值可以是任意值,甚至可以是内置对象使用过的[[Class]]属性的值.
[[Class]]属性的值可以用来判断一个原生对象属于哪种内置类型.需要注意的是,除了通过Object.prototype.toString方法之外,本规范没有提供任何其他方式来让程序访问该属性的值。
ECMAScript 5
在ECMAScript 5中,Object.prototype.toString()被调用时,会进行如下步骤:
- 如果
this是undefined,返回[object Undefined]; - 如果
this是null, 返回[object Null]; - 令
O为以this作为参数调用ToObject的结果; - 令
class为O的内部属性[[Class]]的值; - 返回三个字符串
"["object, class, 以及"]拼接而成的字符串。
[[Class]]是一个内部属性,值为一个类型字符串,可以用来判断值的类型。
本规范的每种内置对象都定义了 [[Class]] 内部属性的值。宿主对象的 [[Class]] 内部属性的值可以是除了 "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", "String" 的任何字符串。[[Class]] 内部属性的值用于内部区分对象的种类。
ECMAScript 6
在ES6,调用 Object.prototype.toString 时,会进行如下步骤:
- 如果
this是undefined,返回[object Undefined]; (函数直接返回分支) - 如果
this是null, 返回[object Null];(函数直接返回分支) - 令
O为以this作为参数调用ToObject的结果;(调用ToObject函数获取结果O) - 令
isArray为IsArray(O);(调用IsArray(O)函数获取结果赋值给isArray) ReturnIfAbrupt(isArray)(如果isArray不是一个正常值,比如抛出一个错误,中断执行);- 如果
isArray为true, 令builtinTag为Array; - else ,如果
O is an exotic String object, 令builtinTag为String; - else ,如果 O 含有
[[ParameterMap]] internal slot, 令builtinTag为Arguments; - else ,如果 O 含有
[[Call]] internal method, 令builtinTag为Function; - else ,如果 O 含有
[[ErrorData]] internal slot, 令builtinTag为Error; - else ,如果 O 含有
[[BooleanData]] internal slot, 令builtinTag为Boolean; - else ,如果 O 含有
[[NumberData]] internal slot, 令builtinTag为Number; - else ,如果 O 含有
[[DateValue]] internal slot, 令builtinTag为 Date ; - else ,如果 O 含有
[[RegExpMatcher]] internal slot, 令builtinTag为RegExp; - else , 令
builtinTag为Object; - 令
tag为Get(O, @@toStringTag)的返回值( Get(O, @@toStringTag)方法,既是在 O 是一个对象,并且具有@@toStringTag属性时,返回O[Symbol.toStringTag]); ReturnIfAbrupt(tag),如果 tag 是正常值,继续执行下一步;- 如果
Type(tag)不是一个字符串,let tag be builtinTag ; - 返回由三个字符串
“[object”, tag, “]”拼接而成的一个字符串。 参考文章
toStringTag
Symbol.toStringTag是一个内置 symbol,它通常作为对象的属性键使用,对应的属性值应该为字符串类型,这个字符串用来表示该对象的自定义类型标签- 通常只有内置的
Object.prototype.toString()方法会去读取这个标签并把它包含在自己的返回值里。
let obj = {};
console.log(Object.prototype.toString.call(obj));// [object Object]
let myExports = {};
// 在这里可以自定义object类型的数据
Object.defineProperty(myExports, Symbol.toStringTag, { value: "Module" });
console.log(Object.prototype.toString.call(myExports)); //[object Module]
4、如何实现instanceOf
function _instanceOf(left, right){
left = left.__proto__;
right = right.prototype;
while(true){
if(left === null){
return false;
}
if(left === right){
return true;
}
left = left.__proto__;
}
}