js技巧--数据类型及检测数据类型

178 阅读4分钟

数据类型分类

  • 基本数据类型

    6种基本数据类型:string number boolean undefined null symbol

  • 复杂数据类型

    1种复杂数据类型:Oobject,包括有 Object 类型,Array 类型,Date 类型, Regexp 类型,function, Math 类型;

两种类型的比较

  • 基本数据类型存放在栈内存中,并且它的值本身不会发生变化,数据之间进行的是值的比较。
var a,b;
a = "jay_chou";
b = a;
console.log(a);  // jay_chou
console.log(b);  // jay_chou
a = "coldplay";  // 改变 a 的值,并不影响 b 的值
console.log(a);   // coldplay

  • 复杂数据类型存放在堆内存中,并且会在栈内存中保存一个指向这个数据的指针变量,这个值是可能发生变化的,数据之间的比较是比较引用。
var a = {
    name: "jay_chou"
}

var b = a;

var c = {
    name: "jay_chou"
}

a === b; // true
a === c; // false

检测数据类型

typeof

console.log(typeof(1));  //number
  console.log(typeof('hello'));  //string
  console.log(typeof(true));  //boolean
  console.log(typeof(undefined));  //undefined
  console.log(typeof(null));  //object
  console.log(typeof({}));  //object
  console.log(typeof(function() {}));  //function

返回值:
  • 返回值是字符串;
  • 基本数据类型只能检测:string, number, undefined, boolean, symbol;
  • null检测出来的是‘object’;
  • 除了function外其他数据类型都只能检测出‘object’;
  • function能正确检测出来;
原理

js底层在存储变量时,会在变量的机器码的1-3低位存储变量的类型信息:

  • 000:对象
  • 010:浮点数
  • 100:字符串
  • 110:布尔
  • 1:整数
  • 而null在存储时的前三位也是000,所以typeof检测是null也是‘object’

instanceof

原理

通过检测变量的构造函数的原型prototype是否出现在类型的原型链上;

返回值
  • 布尔值;
  • 因为它的原理是检测变量的构造函数的原型是否出现在类型的原型链上,所以只能用于检测复杂数据类型;
  • 直接访问的变量的原始值,不会自动建立包装类。因此不能用来判断基本类型值。
  • 不能用于检测null和undefined,会报错。(虽然typeof null== object 和 typeof undefined == undefined ,但是这是js的一个早期的bug)
使用
console.log("1" instanceof String); // false
console.log(1 instanceof Number); // false
console.log(true instanceof Boolean); // false
// instanceof不能检测基本数据类型,但是如果是通过new的方式创建的话就能正确检测
console.log(new String("1") instanceof String); // true
console.log(new Number(1) instanceof Number); // true
console.log(new Boolean(true) instanceof Boolean); // true


//            console.log(null instanceof Null); // null is not a constructor
//            console.log(undefined instanceof Undefined); // undefined is not a constructor
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
console.log({} instanceof Object); // true
局限性
  • 不能用于检测和处理字面量方式创建出来的基本数据类型值,即原始数据类型;
  • instanceof的特性:只要在当前实例的原型链上的对象,我们用其检测出来都为true;
  • 在类的原型继承中,我们最后检测出来的结果未必正确;
  • 只能检测出这个实例是这个原型链上的对象,而不能检测出是那个构造函数new出来的对象。

constructor

原理

与instanceof类似,但是它不但止可以检测引用类型还能检测基本类型;

返回值
  • 布尔值;
局限性
  • 如果修改了实例对象的原型,那么它的constructor也会发生改变;
function Fn(){};

Fn.prototype=new Array();

var f=new Fn();

console.log(f.constructor===Fn);
console.log(f.constructor===Array);

上面的例子修改了f这个实例的构造函数的原型,那么它的constructor也会发生改变。

使用
console.log(("1").constructor === String);
console.log((1).constructor === Number);
console.log((true).constructor === Boolean);
//console.log((null).constructor === Null);
//console.log((undefined).constructor === Undefined);
console.log(([]).constructor === Array);
console.log((function() {}).constructor === Function);
console.log(({}).constructor === Object);

这里有一个需要注意的点就是,当检测基本数据类型的constructor时,要用()将这个数据包起来,不然会报错Invalid or unexceped token。因为js在解析的过程中会把. 解析成小数点,{}会解析成语句,所以会报错。

使用js模拟
function _instance(left, right) {
    while(Object.getPrototypeOf(left) && right.prototype){
        if(Object.getPrototypeOf(left) == right.prototype){
            return true
        }
        let left = Object.getPrototypeOf(left)
    }
    return false
}

Object.prototype.toString.call()

原理

返回当前方法的执行主体的(this的指向)的类型。

返回值

返回的是类型的字符串[object *]

使用
  console.log(Object.prototype.toString.call(1));          //[object Number]
  console.log(Object.prototype.toString.call(/^sf/));        //[object RegExp]
  console.log(Object.prototype.toString.call("hello"));      //[object String]
  console.log(Object.prototype.toString.call(true));        //[object Boolean]
  console.log(Object.prototype.toString.call(null));        //[object Null]
  console.log(Object.prototype.toString.call(undefined));      //[object Undefined]
  console.log(Object.prototype.toString.call(function() {}));    //[object Function]
  console.log(typeof(Object.prototype.toString.call(function() {})));    //string

这个方法也能解决constructor的局限问题:

function Fn(){};

Fn.prototype=new Array();

var f=new Fn();

console.log(Object.prototype.toString.call(Fn));//[object function]
console.log(Object.prototype.toString.call(f));//[object object]

总结:

  1. 数据类型包括有基本数据类型(string number boolean undefined null symbol)和复杂数据类型(object);
  2. 基本数据类型是按指存储,复杂数据类型是按引用存储;
  3. 检测数据类型的方法有四种:typeof,instanceof , constructor,Arrary.prototype.toString().call(),需要区分他们能检测的类型,返回值和局限性。

参考资料:

js检测数据类型四种办法

js数据类型及检测方法

js检测数据类型的四种方法