2

js中的数据类型

js中只有六种原始数据类型和一个Object:

  • Boolean
  • Null
  • Undefined
  • Number
  • String
  • Symbol (ECMAScript 6 新定义)
  • Object

大家认真记清这个描述,不要到时候把Array、Date都当成js的数据类型就尴尬了。那可能会有人问,那Array和Date算什么呢,他们都属于Object,看下面分类:

Object分类

Object分为本地对象内置对象宿主对象三种

本地对象

定义:独立于宿主环境的ECMAScript实现提供的对象。简单的说就是ECMA定义的类。他们包括:
Object   Function   Array   String
Boolean   Number  Date RegExp
Error   EvalError   RangeError  ReferenceError
SyntaxError   TypeError URIError

所以Array和Date都属于对象类型,它们是本地对象。


疑问:

1.有人可能会问,为什么String也是Object类型,上面不是说了是原始类型吗?
答:原始类型中有字符串String不错,它只是表达了一种数据类型,但数据类型也有自己的类定义啊,是吧,上面的String说的就是它的类型定义,是个对象,所以当然也是引用类型了。其他同理。
看下面demo

var str1='hello';
var str2=new String("hello");
typeof str1 //string
typeof str2 //object

//如果想获取str2的字符串,可以通过str2.toString()

str1 instanceof String //false
str2 instanceof String //true

内置对象

定义:“由ECMAScript实现提供的、独立于宿主环境的所有对象,在ECMAScript程序开始执行时出现”。这意味着开发者不必明确实例化内置对象,它已经被实例化了。
内置对象只有两个GlobalMath,他们其实也是本地对象,根据定义每个内置对象都是本地对象。

宿主对象

所有非本地对象都是宿主对象,即由ECMAScript实现的宿主环境提供的对象。所有BOMDOM对象都是宿主对象。

typeof

最常见的判断方法:typeof,它的官方解释

typeof操作符返回一个字符串,表示未经计算的操作数的类型。
简单理解就是typeof是判断的是原始类型(值类型),但函数返回的是function,null返回的也是object
typeof Undefined //'undefined'
var num;
typeof num  //undefined

typeof各类型返回结果列表

类型 结果
Undefined "undefined"
Null "object"
Boolean "boolean"
Number "number"
String "string"
Symbol (ECMAScript 6 新增) "symbol"
宿主对象(由JS环境提供) Implementation-dependent
函数对象([[Call]] 在ECMA-262条款中实现了) "function"
任何其他对象 "object"

为什么typeof null是object

在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null的类型标签也成为了 0,typeof null就错误的返回了"object"。

typeof优缺点列表

优点 缺点
判断原始类型比较方便 null返回的是object
方法返回的是function
所有的引用类型都返回object,Array、Date等不能准确定位

instanceof

定义:“instanceof 运算符用来测试一个对象(第一个参数)在其原型链中是否存在一个构造函数(第二个参数)的 prototype 属性。”
简单理解就是:instanceof是判断两个对象“最近”prototype是否一样。
另外,instanceof是判断对象是否属于某一类型,而不是获取的对象的类型。
var str1="hello";
var str2=new String("hello");
var arr=[1,2,3];
function person(){}
function man(){}
man.prototype=new person();
var m1=new person();
var m2=new man();

str1 instanceof String    //false
str2 instanceof String    //true
arr instanceof Array      //true
arr instanceof window.frames[0].Array  //false
m1 instanceof person      //true
m2 instanceof man         //true
m2 intanceof person       //true

优缺点列表

优点 缺点
判断对象的具体类型 只能判断对象,对原始类型不能判断
多全局对象时返回不正确

多全局对象解释

简单来说:多全局对象就是跨窗口或跨frame操作。

全局环境

在浏览器中,我们的脚本可能需要在多个窗口之间进行交互。多个窗口意味着多个全局环境,不同的全局环境拥有不同的全局对象,从而拥有不同的内置类型构造函数。
这可能会引发一些问题。
比如,表达式 [] instanceof window.frames[0].Array 会返回false,因为 Array.prototype !== window.frames[0].Array.prototype,因此你必须使用 Array.isArray(myObj) 或者 Object.prototype.toString.call(myObj) === "[object Array]"来判断myObj是否是数组。


根据对象的constructor判断

alert(c.constructor === Array) ----------> true
alert(d.constructor === Date) -----------> true
alert(e.constructor === Function) -------> true
注意: constructor 在类继承时会出错
eg:
      function A(){};
      function B(){};
      A.prototype = new B(); //A继承自B
      var aObj = new A();
      alert(aobj.constructor === B) -----------> true;
      alert(aobj.constructor === A) -----------> false;
而instanceof方法不会出现该问题,对象直接继承和间接继承的都会报true:
      alert(aobj instanceof B) ----------------> true;
      alert(aobj instanceof B) ----------------> true;
言归正传,解决construtor的问题通常是让对象的constructor手动指向自己:
      aobj.constructor = A; //将自己的类赋值给对象的constructor属性
      alert(aobj.constructor === A) -----------> true;
      alert(aobj.constructor === B) -----------> false; //基类不会报true了;

缺点:继承的对象判断时,不准确。感觉鸡肋。

最靠谱的方法: Object.prototype.toString.call(obj)

  • 这种方法不存在多全局环境和Array、null返回object的情况,
  • 原始类型和原始类型对应的引用类型声明的变量都能返回正确的值
  • 但是这个方法对自定义类型无效,自定义类型返回的都是Object,所以自定义时还是使用instanceof
var str1="hello";
var str2=new String("hello");
var arr=[1,2,3];
function Man(){}
var man=new Man();
Object.prototype.toString.call(str1);   //[object String]
Object.prototype.toString.call(str2);   //[object String]
Object.prototype.toString.call(arr);   //[object Array]
Object.prototype.toString.call(man);   //[object Object]
Object.prototype.toString.call(null);   //[object Null]
Object.prototype.toString.call(/test/)  //[object RegExp]
优点 缺点
不存在多全局环境问题 只能判断本地对象和宿主对象
原始类型无论是字面量语法声明还是通过对应的引用类型声明都能正确判断 自定义类型都返回[object Object]

jquery.type()

就是对prototype的封装。源码附上:

type: function( obj ) {
        return obj == null ?
            String( obj ) :
            class2type[ toString.call(obj) ] || "object";
    },

对数组的判断

var arr=[1,2,3];
typeof arr   //object  分辨不出类型
arr instanceof Array   //true //受多全局环境影响
Object.prototype.toString.call(arr);  //[object Array] //推荐
Array.isArray(arr)    //true //推荐
$.type(arr)   //array  //推荐

code_sir
543 声望10 粉丝