数据类型的判断

427 阅读4分钟

JavaScript类型可以分为两类:原始类型和对象类型。原始类型包括数值、字符串、布尔值和两个特殊值nullundefined。除了上述值以外的值都是对象类型。对象是属性的集合,对象也有很多种,比如普通对象、数组、Set、Map、Date、function等等。

内存结构

程序运行时,计算机内存会为程序开辟出一块专用内存,用于存储数据。在JavaScript中,变量名和变量值都是数据,但是它们存储的位置是不同的,变量名存储在内存的一个空间中,变量值是存储在另一个空间中。

每一个值都有一个内存地址,变量名实际上保存的就是值的内存地址,这样就建立了名字和值的联系。

前面我们知道了值分为原始类型和对象类型,而内存分为栈内存与堆内存。

  • 栈内存用于保存变量名,内存地址和原始类型。
  • 堆内存用于保存对象类型。

内存中不会创建重复的原始类型,可以理解为原始类型是不可改变的。

let a = 'HelloWorld';
let b = 'HelloWorld';

栈内存.png

但是内存中可以创建重复的对象类型,并且它们的内存地址不同。

  • 给不同变量赋值同样的原始类型,它们是相等的,它们保存的是同一个内存地址。
  • 给不同变量赋值同样的对象类型,它们是不相等的,因为它们比较的是内存地址。
let a = 1;
let b = 1;
console.log(a === b); // true
let arr1 = [1, 2, 3];
let arr2 = [1, 2, 3];
console.log(arr1 === arr2); // false

堆内存.png

对象中的属性和值是可修改的。

  • 变量arr1赋值给变量arr2,实际上是把arr1保存的数组[1, 2, 3, 4]的内存地址赋给arr2。它们俩指向同一个地址的数组,所以arr1修改对arr2是有影响的。
var arr1 = [1, 2, 3, 4];
var arr2 = arr1;
arr1.push(5);
// arr1和arr2的地址是同一个
console.log(arr1 + '|' + arr2); // 1,2,3,4,5|1,2,3,4,5
  • 重新赋值的过程是指向了新的内存地址。
var arr1 = [1, 2, 3, 4];
var arr2 = arr1;
arr1 = [1, 2];
console.log(arr1 + '|' + arr2);
// 1,2|1,2,3,4,5

类型判断

typeof

typeof(data)方法 返回一个字符串用于表示参数的数据类型,但是对于引用类型它只能区分是函数还是其它引用类型,比如以下代码中的对于数组的返回结果就是object

console.log(typeof(123)); // "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([])); // "object"
console.log(typeof(function(){})); // "function"
console.log(typeof(null)); // "object"
console.log(typeof(NaN)); // "number"
console.log(typeof(document.all)); // "undefined"

注意null是一个object类型,它最早是空对象的指针,目前来说是一个历史遗留问题。

console.log(typeof(null)); //object

如果一个变量a未定义,使用typeof()返回的是undefined,注意这个undefined是字符串格式的。

console.log(typeof(a)); // undefined
console.log(typeof(typeof(a))); // string

constructor

constructor 指向创建该实例对象的构造函数。

var arr = [];
console.log(arr.constructor); // ƒ Array() { [native code] }

instanceof

instanceOf()方法 判断一个对象是否是右边的实例。

function Car(){}
var car = new Car();

console.log(car instanceof Car); // true

并且只要该对象能通过原型链访问到右边,都会返回true。

  • 第一条语句打印true,因为Car构造函数是由Function构造函数创建的实例。
  • 第二条语句打印fasle,因为car对象和Function之间并不存在原型链上的联系。
  • 第三条语句打印true,因为car对象可以找到Car构造函数的原型,然后接着找到Object
function Car(){}
var car = new Car();

console.log(Car instanceof Function); // true
console.log(car instanceof Function); // false
console.log(car instanceof Object); // true

Object.prototype.toString

toString()方法 不接收参数,返回表示调用它的对象的值的字符串,注意的是它返回的字符串格式为[object 对象类型]

var obj = {name: 'Li'};
console.log(obj.toString()); // [object Object]

所以虽然默认的toString()方法不会显示太多信息,但是可以用于判断数据的类型,所以可以结合call使用。

对于 Object.prototype.toString.call(arg),若参数arg为 null 或 undefined,直接返回结果。

console.log(Object.prototype.toString.call(undefined)) // "[object Udefined]"
console.log(Object.prototype.toString.call(null)) // "[object Null]"

对于其他数据类型,如果是原始数据类型,那么首先是进行包装类,如果是引用对象类型则直接使用。

console.log(Object.prototype.toString.call(123)) // "[object Number]"
console.log(Object.prototype.toString.call('HelloWorld')) // "[object String]"
console.log(Object.prototype.toString.call(true)) // "[object Boolean]"
console.log(Object.prototype.toString.call({name: 'Li'})) // "[object Object]"
console.log(Object.prototype.toString.call([1, 2, 3])) // "[object Array]"
console.log(Object.prototype.toString.call(function(){var a = 1;})) // "[object Function]"
  • 在实际项目中会经常使用这个方式判断数据类型,使用时要注意变量缓存。
var arr = [];

var str = Object.prototype.toString,
    trueTip = '[object Array]';
if(str.call(arr) === trueTip){
    console.log('是数组');
}else{
    console.log('不是数组');
}

由于这个默认方法不会显示太多有用的信息,所以很多类都会重新定义自己的toString()方法。比如,在把数组转换为字符串时,会得到数组元素的一个列表,每个元素都会转换为字符串。而把函数转换为字符串时,可以得到函数的源代码。

  • 原始类型重新定义的toString()方法,会返回当前值的字符串。
  • 注意undefinednull并没有自己的toString()方法,直接调用会报错。
var a = 'HelloWorld',
    b = 123,
    c = true,
    d = undefined,
    e = null,
    f = [4, 5, 6],
    g = function(){
         var str = 'demo';
    };
console.log(a.toString()); // 'HelloWorld'
console.log(b.toString()); // '123'
console.log(c.toString()); // 'true'
// console.log(d.toString()); // error
// console.log(e.toString()); // error
console.log(f.toString()); // '4, 5, 6'
console.log(g.toString()); // 'function(){ var str = 'demo'; }'