在我的第一篇文章里,介绍过JS各大类型并使用typeof进行输出查看.也有提到过每个函数都有一个自己的内部属性[[class]],这个class指的是js内部分类.这个类的大致包括:数据类型
和构造函数
这两种。
我们讲过JS的几大数据类型,也用typeof查看了几个简单的数据类型值。那么今天我们再来更宽泛的了解一下这方面的知识。请看如下代码。
var num = 123;
var str = 'aflypig';
var bool = true;
var arr = [1, 2, 3, 4];
var obj = {name:'aflypig', age:21};
var func = function(){ console.log('this is function'); }
var und = undefined;
var nul = null;
var date = new Date();
var reg = /^[a-zA-Z]{5,20}$/;
var error= new Error();
显然,上次我们只用typeof查看了几个常用的数据类型,但这次多了一些内置构造函数,还有Array(上次特意没讲Array)类型。那么步入正题,我们怎样才能准确得获得这些值
(再强调一次,这里不是变量,JS当中衡量类型的是值,变量是储存值的容器)数据类型呢?
其实,一共有四种方法,但能完全准确地识别出它们的只有一种方法,这也是面试过程中屡见不鲜的一道题。
如果判断不同类型
typeof
typeof num //number
typeif str //string
typeof bool //boolean
typeof arr //object
typeof obj //object
typeof func//function
typeof und //undefined
typeof nul //object
typeof date //object
tyepof reg //object
tyoeof error //object
解析:typeof可以识别简单基本类型值
(比如:number,string,boolean),但对于复合类型(Object,Array,Function)却只能识别Function。
undefined和null本身就是JS一直以来的bug,此处typeof `undefined`可以识别出正确的类型值,但null被归类到`Object`大家庭中。
对于此处的 date && reg && error 类型都是实例后的对象,typeof并不会深入识别他们的`构造函数`(这里不是数据类型)。显然typeof并不能处理这种复杂的类型。
总结:typeof可以看作JS内部已经定义好的各个类型返回其对应的字符串,它不深入值本身,不进行类型转换,只针对于当前值返回其对应的类型值。同样的数据类型通过typeof运算符运算都是一样的,它没有原理可言,JS就是这样定义的,我们只管记死它。
instanceof
通过上面的typeof判断,我们知道它并不能满足一些内置构造函数创建的
伪类型
。那么,我们这里来使用 constructor 查看他们的构造函数,从而分辨它们的类型。
num instanceof Number //false
str instanceof String //false
bool instanceof Boolean //false
arr instanceof Array //true
obj instaneof Object //true
func instanceof Function //true
und instanceof Object //false
nul instanceof Object //false
date instanceof Date //true
reg instanceof RegExp //true
error instanceof Error //true
解析:这里我们使用instanceof来复合判断
的是否为对应类型。首先,我们先看false项,num str bool 这三个在使用instanceof 时并没有包装封装对象且instanceof
则是根据
constructor
num.constructor .name //Numer
str.constructor.name //String
bool.constructor.name //Boolean
arr.constructor.name //Array
obj.constructor.name //Objeact
func.constructor.name //Function
und.constructor.name // TypeError
nul.constructor.name //TypeError
date.constructor.name //Date
reg.constructor.name // RegExp
error.constructor.name //Error
上面除了undefined 和 null 类型错误(两者都没有属性值)之外, 其他都可以获得我们想要的数据类型。但实际真的如此吗?
// 1⃣️
var Structure = function (){ }
var ins = new Structure();
ins.constructor.name //Structure
//2⃣️
var Person = function(){}
var Student = function(){}
Person.prototype = new Student();
var obj = new Person();
obj.constructor === Student
解析:第一种情况,对于通过我们的构造函数生成的实例,不能准确得获得其对应得类型名称,这一点恐怕就已经遏制了我们使用这种方式。
第二种情况,由于对象的构造函数是`可变的`,`不准确的`,我们还是无法准确的通过constructor获得具体的类型.
总结:通过constructor我们可以得到 instance不能得到的 str num bool 这些基本类型值
,但另一个问题又浮现出来,constructor的可变性
,由于它的不确定性,我们在很多情况下都无法判断出正确的数据类型,所以使用constructor这个方法也差不多废了....
[[Class]]
解析:此[[class]]指的是隐藏在javascript内部的分类属性,它不可读,不可枚举,不可修改,不可配置。(两边出现__下划线__的属性都属于部分浏览器支持的属性。[[]]两个中括号括起来的属性属于JavaScript内部属性。),我记得上一章说过,JavaScript中一切皆为对象
的理念,我们可以强制把它转换成字符串,使它暴露出内部的[[class]]属性。
了解了以上各种方法,我们发现它们只能完成部分的类型验证,有些情况是可变和不准确的。
Object.prototype.toString.call(num); // "[object Number]"
Object.prototype.toString.call(str); // "[object String]"
Object.prototype.toString.call(bool); // "[object Boolean]"
Object.prototype.toString.call(arr); // "[object Array]"
Object.prototype.toString.call(func); // "[object Function]"
Object.prototype.toString.call(und); // "[object Undefined]"
Object.prototype.toString.call(nul); // "[object Null]"
Object.prototype.toString.call(date); // "[object Date]"
Object.prototype.toString.call(reg); // "[object RegExp]"
Object.prototype.toString.call(error); // "[object Error]"
arr instanceof Array //true
obj instaneof Object //true
func instanceof Function //true
und instanceof Object //false
nul instanceof Object //false
date instanceof Date //true
reg instanceof RegExp //true
error instanceof Error //true
我们通过 Object 的 toString 方法来查看了当前对象的数据类型
,我们看到使用这种方式可以完美的查看对应的数据类型,正是我们想要的,而且每个对象都有属于自己的[[class]],我们可以理解为,它是JavaScript根据内置构造函数做出的内部分类。
对于这种经常使用原生js又难以需求的情况下,怎么能少得了jqquery呢?
以下是与jQuery.type()函数相关的jQuery示例代码:
jQuery.type( undefined ); // "undefined"
jQuery.type( null ); // "null"
jQuery.type( true ); // "boolean"
jQuery.type( new Boolean(true) ); // "boolean"
jQuery.type( 3 ); // "number"
jQuery.type( new Number(3) ); // "number"
jQuery.type( "test" ); // "string"
jQuery.type( new String("test") ); // "string"
jQuery.type( function(){} ); // "function"
jQuery.type( new Function() ); // "function"
jQuery.type( [] ); // "array"
jQuery.type( new Array() ); // "array"
jQuery.type( new Date() ); // "date"
jQuery.type( new Error() ); // "error" // jQuery 1.9 新增支持
jQuery.type( /test/ ); // "regexp"
jQuery.type( new RegExp("\\d+") ); // "regexp"
jquery内部也是通过我们刚才说到的 [[class]]的方式实现的,它返回一个字符串,固定为小写字母。
我们可以写行代码,来简单的实现jquery中的type方法
function type(o){
var s = Object.prototype.toString.call(o);
return s.slice(s.indexOf(" ")+1,s.length-1).toLowerCase();
}
type(false) //boolean
type({}) //object
type([]) //array
type("") //string
type(/^/) //regexp
希望通过本次粗浅的讲解能给大家带来一点收获,在知道最终有适合的方式时,应该多去考虑使用另外的方式去实现的手段,因为做这样可以扩展自己的知识范围。就比如上文,如果从后向前列举,我想有很多人都不会去思考 constructor 和 instance 的不足以及他们的适用范围吧,