javascript中对变量范例的推断

在JavaScript中,有5种基础数据范例和1种庞杂数据范例,基础数据范例有:Undefined, Null, Boolean, NumberString;庞杂数据范例是ObjectObject中还细分了许多详细的范例,比方:Array, Function, Date等等。本日我们就来讨论一下,运用什么要领推断一个出一个变量的范例。

在解说种种要领之前,我们起首定义出几个测试变量,看看背面的要领终究能把变量的范例剖析成什么模样,以下几个变量差不多包含了我们在现实编码中经常使用的范例。

var num  = 123;
var str  = 'abcdef';
var bool = true;
var arr  = [1, 2, 3, 4];
var json = {name:'wenzi', age:25};
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();

1. 运用typeof检测

我们日常平凡用的最多的就是用typeof检测变量范例了。此次,我们也运用typeof检测变量的范例:

console.log(
    typeof num, 
    typeof str, 
    typeof bool, 
    typeof arr, 
    typeof json, 
    typeof func, 
    typeof und, 
    typeof nul, 
    typeof date, 
    typeof reg, 
    typeof error
);
// number string boolean object    object function undefined object object object object

从输出的效果来看,arr, json, nul, date, reg, error 悉数被检测为object范例,其他的变量能够被准确检测出来。当须要变量是不是是number, string, boolean, function, undefined, json范例时,能够运用typeof举行推断。其他变量是推断不出范例的,包含null。

另有,typeof是辨别不出arrayjson范例的。由于运用typeof这个变量时,array和json范例输出的都是object

2. 运用instance检测

在 JavaScript 中,推断一个变量的范例试试会用 typeof 运算符,在运用 typeof 运算符时采纳援用范例存储值会涌现一个题目,不论援用的是什么范例的对象,它都返回 “object”。ECMAScript 引入了另一个 Java 运算符 instanceof 来处置惩罚这个题目。instanceof 运算符与 typeof 运算符相似,用于辨认正在处置惩罚的对象的范例。与 typeof 要领差别的是,instanceof 要领请求开发者明确地确认对象为某特定范例。比方:

function Person(){

}
var Tom = new Person();
console.log(Tom instanceof Person); // true

我们再看看下面的例子:

function Person(){

}
function Student(){

}
Student.prototype = new Person();
var John = new Student();
console.log(John instanceof Student); // true
console.log(John instancdof Person);  // true

instanceof还能检测出多层继续的关联。

好了,我们来运用instanceof检测上面的那些变量:

console.log(
    num instanceof Number,
    str instanceof String,
    bool instanceof Boolean,
    arr instanceof Array,
    json instanceof Object,
    func instanceof Function,
    und instanceof Object,
    nul instanceof Object,
    date instanceof Date,
    reg instanceof RegExp,
    error instanceof Error
)
// num : false 
// str : false 
// bool : false 
// arr : true 
// json : true 
// func : true 
// und : false 
// nul : false 
// date : true 
// reg : true 
// error : true

从上面的运转效果我们能够看到,num, str和bool没有检测出他的范例,然则我们运用下面的体式格局建立num,是能够检测出范例的:

var num = new Number(123);
var str = new String('abcdef');
var boolean = new Boolean(true);

同时,我们也要看到,und和nul是检测不成Object范例的,其他的范例也不对,因而,若要运用instanceof举行变量检测时,须要起首推断是不是是undefined和null。

3. 运用constructor检测

在运用instanceof检测变量范例时,我们是检测不到number, ‘string’, bool的范例的。因而,我们须要换一种体式格局来处置惩罚这个题目。

constructor本来是原型对象上的属性,指向组织函数。然则根据实例对象寻觅属性的递次,若实例对象上没有实例属性或要领时,就去原型链上寻觅,因而,实例对象也是能运用constructor属性的。

我们先来输出一下num.constructor的内容,即数字范例的变量的组织函数是什么模样的:

function Number() { [native code] }

我们能够看到它指向了Number的组织函数,因而,我们能够运用num.constructor==Number来推断num是不是是Number范例的,其他的变量也相似:


function Person(){

}
var Tom = new Person();

// undefined和null没有constructor属性
console.log(
    Tom.constructor==Person,
    num.constructor==Number,
    str.constructor==String,
    bool.constructor==Boolean,
    arr.constructor==Array,
    json.constructor==Object,
    func.constructor==Function,
    date.constructor==Date,
    reg.constructor==RegExp,
    error.constructor==Error
);
// 一切效果均为true

从输出的效果我们能够看出,除了undefined和null,其他范例的变量均能运用constructor推断出范例。

不过运用constructor也不是保险的,由于constructor属性是能够被修改的,会致使检测出的效果不准确,比方:

function Person(){

}
function Student(){

}
Student.prototype = new Person();
var John = new Student();
console.log(John.constructor==Student); // false
console.log(John.constructor==Person);  // true

在上面的例子中,Student原型中的constructor被修改为指向到Person,致使检测不出实例对象John实在的组织函数。

同时,运用instaceof和construcor,被推断的array必需是在当前页面声明的!比方,一个页面(父页面)有一个框架,框架中援用了一个页面(子页面),在子页面中声清楚明了一个array,并将其赋值给父页面的一个变量,这时候推断该变量,Array == object.constructor;会返回false;
缘由:
1、array属于援用型数据,在通报过程当中,仅仅是援用地点的通报。
2、每一个页面的Array原生对象所援用的地点是不一样的,在子页面声明的array,所对应的组织函数,是子页面的Array对象;父页面来举行推断,运用的Array并不等于子页面的Array;牢记,不然很难跟踪题目!

4. 运用Object.prototype.toString.call

我们先不论这个是什么,先来看看他是怎样检测变量范例的:

console.log(
    Object.prototype.toString.call(num),
    Object.prototype.toString.call(str),
    Object.prototype.toString.call(bool),
    Object.prototype.toString.call(arr),
    Object.prototype.toString.call(json),
    Object.prototype.toString.call(func),
    Object.prototype.toString.call(und),
    Object.prototype.toString.call(nul),
    Object.prototype.toString.call(date),
    Object.prototype.toString.call(reg),
    Object.prototype.toString.call(error)
);
// '[object Number]' '[object String]' '[object Boolean]' '[object Array]' '[object Object]'
// '[object Function]' '[object Undefined]' '[object Null]' '[object Date]' '[object RegExp]' '[object Error]'

从输出的效果来看,Object.prototype.toString.call(变量)输出的是一个字符串,字符串里有一个数组,第一个参数是Object,第二个参数就是这个变量的范例,而且,一切变量的范例都检测出来了,我们只须要掏出第二个参数即可。或许能够运用Object.prototype.toString.call(arr)=="object Array"来检测变量arr是不是是数组。

我们如今再来看看ECMA里是是怎样定义Object.prototype.toString.call的:

Object.prototype.toString( ) When the toString method is called, the following steps are taken:

  1. Get the [[Class]] property of this object.
  2. Compute a string value by concatenating the three strings “[object “, Result (1), and “]”.
  3. Return Result (2)

上面的范例定义了Object.prototype.toString的行动:起首,获得对象的一个内部属性[[Class]],然后根据这个属性,返回一个相似于”[object Array]”的字符串作为效果(看过ECMA规范的应当都晓得,[[]]用来示意言语内部用到的、外部不可直接接见的属性,称为“内部属性”)。应用这个要领,再合营call,我们能够获得任何对象的内部属性[[Class]],然后把范例检测转化为字符串比较,以到达我们的目标。

5. jquery中$.type的完成

在jquery中供应了一个$.type的接口,来让我们检测变量的范例:

console.log(
    $.type(num),
    $.type(str),
    $.type(bool),
    $.type(arr),
    $.type(json),
    $.type(func),
    $.type(und),
    $.type(nul),
    $.type(date),
    $.type(reg),
    $.type(error)
);
// number string boolean array object function undefined null date regexp error

看到输出效果,有无一种熟习的觉得?对,他就是上面运用Object.prototype.toString.call(变量)输出的效果的第二个参数呀。

我们这里先来对照一下上面一切要领检测出的效果,横排是运用的检测要领, 竖排是各个变量:

范例推断typeofinstanceofconstructortoString.call$.type
numnumberfalsetrue[object Number]number
strstringfalsetrue[object String]string
boolbooleanfalsetrue[object Boolean]boolean
arrobjecttruetrue[object Array]array
jsonobjecttruetrue[object Object]object
funcfunctiontruetrue[object Function]function
undundefinedfalse[object Undefined]undefined
nulobjectfalse[object Null]null
dateobjecttruetrue[object Date]date
regobjecttruetrue[object RegExp]regexp
errorobjecttruetrue[object Error]error
长处运用简朴,能直接输出效果能检测出庞杂的范例基础能检测出一切的范例检测出一切的范例
瑕玷检测出的范例太少基础范例检测不出,且不能跨iframe不能跨iframe,且constructor易被修改IE6下undefined,null均为Object

如许对照一下,就更能看到各个要领之间的区别了,而且
Object.prototype.toString.call
$type输出的效果真的很像。我们来看看jquery(2.1.2版本)内部是怎样完成$.type要领的: // 实例对象是能直接运用原型链上的要领的 var class2type = {}; var toString = class2type.toString; // 省略部份代码… type: function( obj ) { if ( obj == null ) { return obj + “”; } // Support: Android<4.0, iOS<6 (functionish RegExp) return (typeof obj === “object” || typeof obj === “function”) ? (class2type[ toString.call(obj) ] || “object”) : typeof obj; }, // 省略部份代码… // Populate the class2type map jQuery.each(“Boolean Number String Function Array Date RegExp Object Error”.split(” “), function(i, name) { class2type[ “[object ” + name + “]” ] = name.toLowerCase(); }); 我们先来看看
jQuery.each的这部份: // Populate the class2type map jQuery.each(“Boolean Number String Function Array Date RegExp Object Error”.split(” “), function(i, name) { class2type[ “[object ” + name + “]” ] = name.toLowerCase(); }); //轮回以后,
class2type的值是: class2type = { ‘[object Boolean]’ : ‘boolean’, ‘[object Number]’ : ‘number’, ‘[object String]’ : ‘string’, ‘[object Function]’: ‘function’, ‘[object Array]’ : ‘array’, ‘[object Date]’ : ‘date’, ‘[object RegExp]’ : ‘regExp’, ‘[object Object]’ : ‘object’, ‘[object Error]’ : ‘error’ } 再来看看
type要领: // type的完成 type: function( obj ) { // 若传入的是null或undefined,则直接返回这个对象的字符串 // 即若传入的对象obj是undefined,则返回”undefined” if ( obj == null ) { return obj + “”; } // Support: Android<4.0, iOS<6 (functionish RegExp) // 低版本regExp返回function范例;高版本已修改,返回object范例 // 若运用typeof检测出的obj范例是object或function,则返回class2type的值,不然返回typeof检测的范例 return (typeof obj === “object” || typeof obj === “function”) ? (class2type[ toString.call(obj) ] || “object”) : typeof obj; } 当
typeof obj === "object" || typeof obj === "function"时,就返回
class2type[ toString.call(obj)。到这儿,我们就应当邃晓为何Object.prototype.toString.call和$.type那末像了吧,实在jquery中就是用
Object.prototype.toString.call完成的,把'[object Boolean]’范例转成’boolean’范例并返回。若class2type存储的没有这个变量的范例,那就返回”object”。 除了”object”和”function”范例,其他的范例则运用typeof举行检测。即
number,
string,
boolean范例的变量,运用typeof即可。

    原文作者:wenzi
    原文地址: https://segmentfault.com/a/1190000002962215
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞