zoukankan      html  css  js  c++  java
  • JavaScript判断对象的类型

    最近阅读了一些关于JavaScript判断对象类型的文章。总结下来,主要有constructor属性、typeof操作符、instanceof操作符和Object.prototype.toString()方法这四个方式来判断对象的类型。

    constructor属性

    构造函数预定义的constructor属性是构造函数本身。

    var Foo = function(){};
    Foo.prototype.constructor === Foo;//true

    通过new调用构造函数所生成的对象以构造函数的prototype属性为原型。虽然JavaScript中没有类的概念,但是构造函数的作用同类的名称相似,是对象类型的标识。访问对象继承的constructor属性可以查看对象的类型。原始类型的变量也可以访问constructor属性,因为在访问的时候JavaScript形成了一个包装对象。

     1 //basic objects
     2 var obj = {name: "obj"};
     3 obj.constructor === Object;//true
     4 
     5 //self defined "class"
     6 var Foo = function(){};
     7 var f = new Foo();
     8 f.constructor === Foo;//true
     9 
    10 //primitive types
    11 //Number
    12 var num = 1;
    13 num.constructor === Number;//true
    14 var nan = NaN;
    15 nan.constructor === Number;//true
    16 //Boolean
    17 var b = true;
    18 b.constructor === Boolean;//true
    19 //String
    20 var s = "string";
    21 s.constructor === String;//true
    22 //Function
    23 var Fun =function(){};
    24 Fun.constructor === Function;//true;

    然而,constructor属性是可以重新复制或者覆盖的,这会引起类型判断的错误。即使我们一般不会刻意去给constructor属性赋值,但是有一些情况下constructor属性的值和我们所期望的值不同。看下面例子:

    var baseClass = function(){};
    var derivedClass = function(){};
    derivedClass.prototype = new baseClass();
    
    var obj = new derivedClass();
    obj.constructor === derivedClass;//false;
    obj.constructor === baseClass;//true;

    因为子类的prototype以父类的实例为原型,所以通过子类实例访问constructor就是父类构造函数。因此在JavaScript面向对象编程中,我们会在定义子类时加上一句代码来纠正constructor属性。

    derivedClass.prototype.constructor = derivedClass;

    使用constructor进行判断变量类型虽然方便,但是不见得特别安全,所以需要小心。

    cross-frame和cross-window问题:

    如果判断来自不同frame或来自不同window的变量的对象的类型,那么constructor属性无法正常工作。因为不同window的核心类型不同[1]。

    使用instanceof操作符

    instanceof操作符判断一个对象的原型链中是否存在某个构造函数的prototype属性[2]。原型链的概念可以阅读JavaScript面向对象编程(一)原型与继承。下面的代码形成了原型链obj1->derivedClass.prototype->baseClass.prototype->...->Object.prototype。Object.prototype是所有对象的原型,anyObj instanceof Object === true。

    var baseClass = function(){};
    var derivedClass = function(){};
    derivedClass.prototype = new baseClass();//use inheritance
    
    var obj1 = new derivedClass();
    obj1 instanceof baseClass;//true
    obj1 instanceof derivedClass;//true
    obj1 instanceof Object;//true
    
    obj2 = Object.create(derivedClass.prototype);
    obj2 instanceof baseClass;//true
    obj2 instanceof derivedClass;//true
    obj2 instanceof Object;//true

    constructor属性可以应用到除了null和undefined之外的原始类型(数字、字符串、布尔类型)。而instanceof不可,但是可以使用包装对象的方法进行判断。

    3 instanceof Number // false
    'abc' instanceof String // false
    true instanceof Boolean // false
    
    new Number(3) instanceof Number // true
    new String('abc') instanceof String //true
    new Boolean(true) instanceof Boolean //true

    然而,instanceof在cross-frame和cross-window的情况下也无法正常工作。

    使用 Object.prototype.toString()方法

    Object.prototype.toString()方法是一个底层的方法,使用它可以返回一个字符串,该字符串表明了对象的类型。也可以用于判断null和undefined。下面列出了多数常见的类型。

    Object.prototype.toString.call(3);//"[object Number]"
    Object.prototype.toString.call(NaN);//"[object Number]"
    Object.prototype.toString.call([1,2,3]);//"[object Array]"
    Object.prototype.toString.call(true);//"[object Boolean]"
    Object.prototype.toString.call("abc");//"[object String]"
    Object.prototype.toString.call(/[a-z]/);//"[object RegExp]"
    Object.prototype.toString.call(function(){});//"[object Function]"
    
    //null and undefined in Chrome and Firefox. In IE "[object Object]" 
    Object.prototype.toString.call(null);//"[object Null]"
    Object.prototype.toString.call(undefined);//"[object Undefined]"
    
    //self defined Objects
    var a = new Foo();
    Object.prototype.toString.call(a);//"[object Object]"
    
    //Typed Wrappers
    var b = new Boolean(true);
    Object.prototype.toString.call(b);//"[object Boolean]"
    var n = new Number(1);
    Object.prototype.toString.call(n);//"[object Number]"
    var s = new String("abc");
    Object.prototype.toString.call(s);//"[object String]"

    经常会使用slice方法截取结果中类型的信息:

    Object.prototype.toString.call("abc").slice(8,-1);//"String"

    使用typeof 运算符

    在MDN的一篇文档中已经很详细介绍了这个[3]。typeof能返回的信息较少,有"undefined"、"object"、"boolean"、"number"、"string"、"function"、"xml"这几种。

    TypeResult
    Undefined "undefined"
    Null "object"
    Boolean "boolean"
    Number "number"
    String "string"
    Host object (provided by the JS environment) Implementation-dependent
    Function object (implements [[Call]] in ECMA-262 terms) "function"
    E4X XML object "xml"
    E4X XMLList object "xml"
    Any other object "object"
    // Numbers
    typeof 37 === 'number';
    typeof 3.14 === 'number';
    typeof Math.LN2 === 'number';
    typeof Infinity === 'number';
    typeof NaN === 'number'; // Despite being "Not-A-Number"
    typeof Number(1) === 'number'; // but never use this form!
    
    // Strings
    typeof "" === 'string';
    typeof "bla" === 'string';
    typeof (typeof 1) === 'string'; // typeof always return a string
    typeof String("abc") === 'string'; // but never use this form!
    
    // Booleans
    typeof true === 'boolean';
    typeof false === 'boolean';
    typeof Boolean(true) === 'boolean'; // but never use this form!
    
    // Undefined
    typeof undefined === 'undefined';
    typeof blabla === 'undefined'; // an undefined variable
    
    // Objects
    typeof {a:1} === 'object';
    typeof [1, 2, 4] === 'object'; // use Array.isArray or Object.prototype.toString.call to differentiate regular objects from arrays
    typeof new Date() === 'object';
    
    typeof new Boolean(true) === 'object'; // this is confusing. Don't use!
    typeof new Number(1) === 'object'; // this is confusing. Don't use!
    typeof new String("abc") === 'object';  // this is confusing. Don't use!
    
    // Functions
    typeof function(){} === 'function';
    typeof Math.sin === 'function';
    
    
    typeof undefined;//"undefined"
    typeof null;//"object" This stands since the beginning of JavaScript
    typeof /s/ === 'object'; // Conform to ECMAScript 5.1

    typeof 包装对象的结果是‘object’需要注意。这里不评价好与不好(如果需要区分包装对象和原始类型呢)。但是typeof不是一个健壮的方法,要小心使用。比如:

    var s = "I am a string";
    typeof s === "string";
    //Add a method to String
    String.prototype.A_String_Method = function(){
        console.log(this.valueOf());
        console.log(typeof this);
    };
    s.A_String_Method();
    //I am a string
    //object

    这里为了表述,在String构造函数的prototype中添加了一个方法。可以看出,字符串处理函数都是将字符串变成一个包装对象,所以typeof的结果是object。要注意,typeof的结果的首字母是小写的。

    参考文献:

    [1]stackoverflow的一个问答http://stackoverflow.com/questions/332422/how-do-i-get-the-name-of-an-objects-type-in-javascript

    [2]MDN关于instanceof的文章:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof

    [3]MDN关于typeof的文章:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof

  • 相关阅读:
    Excel教程集个人珍藏版
    【转】UML中几种类间关系:继承、实现 ...
    【转】UML用户指南(一)入门
    【转】软件项目经理素质能力的必备要求
    【转】类与类之间的常见关系,uml图表示
    【转】UML用户指南(二)类、关系、图、接口、包、实例
    Oracle建立DBLINK的详细步骤记录
    oracle中的默认帐户详解 .
    pro*c
    oracle type类型
  • 原文地址:https://www.cnblogs.com/zhenchaoni/p/JavaScript_Determine_Types.html
Copyright © 2011-2022 走看看