【数据类型】JavaScript数据类型&聊聊Object.prototype.toString

一、数据类型

JavaScript定义了7种基本数据类型:

  • Symbol (ES6)
  • String
  • Number
  • Null
  • Boolean
  • Undefined
  • Object

JavaScript是一种弱类型脚本语言,即定义变量时不需要声明变量的类型,在程序运作过程中会自动判断变量的类型,定义变量的方法:

  • var
  • let (ES6)
  • const (ES6)

不添加关键词var/let/const也能定义变量,此时会创建一个全局变量,且变量不会提升


二、值类型和引用类型

除了以上类型的划分,变量还分为值类型和引用类型,在传递过程中分为值传递和引用传递。值传递只会传递变量的值,引用传递会传递变量的存储地址(指针)

var a = 1,
	b = {name: 1};
	
var c = a; //值传递,a会赋值给c
console.log(c); // 1

c = 2;
console.log(a); // 1 值传递相当于内存中复制了一份,c和a没有关系

var d = b;
d.name = 2;
console.log(b.name); // 2 引用传递传递的是地址,所以b和d指向同一内存地址

三、判断数据类型的方法

我们很多时候需要对数据的类型进行判断,然后进行相关的操作,判断数据类型常见有以下几种方法:

  • typeof
  • instanceof / constructor
  • Object.prototype.toString.call()

四、typeof

调用typeof方法时会返回以下几种值之一:

  • symbol
  • string
  • number
  • boolean
  • undefined
  • object
  • function
typeof Symbol(); // symbol
typeof 'abc'; // string
typeof 123; // number
typeof NaN; // number
typeof true; // boolean
typeof undefined; // undefined
typeof {a:1}; // object
typeof [1,2,3]; // object
typeof function a(){}; // function
typeof null; // object

// typeof检测一个未声明的变量时会返回undefined
typeof undeclare_variable; // undefined
  • typeof null => object 这是typeof 的一个bug,null并不是引用类型
    Javascript语言第一版只设计了五种数据类型(对象、整数、浮点数、字符串、布尔值),没考虑null,只把它当作object的一种特殊值,后来null独立出来,作为一种单独的数据类型,为了兼容以前的代码就没有改变null的类型
  • typeof [1,2,3] => object 除了函数返回的是function,其他引用类型返回的都是object,所以typeof无法区分array和object

五、instanceof / constructor

instanceof和constructor都是用于实例和构造函数的对应,可以弥补typeof无法区分数组和对象的问题
但是,instanceof只能用于非对象类型数据的判断

[1,2,3] instanceof Array; // true

var a = {name: 1};
a instanceof Object; // true

1 instanceof Number; // false

constructor可以用于任何类型的判断

var num = 1;
num.constructor === Number; // true

var arr = [1, 2, 3];
arr.constructor === Array; // true

但是,这两种方法都不能用于跨iframe的情况,例如

//pageOne中
...
<div>父页面</div>
<iframe src="pageB.html" frameborder="0"></iframe>
<script>
  //这里定义了一个数组a
  var a = [1, 2, 3];
  console.log( a.constructor === Array ); // true
</script>
...

//pageTwo中
...
<div>子页面</div>
<script>
  //子页面获取父页面中的值
  var c = top.a;
  console.log( c.constructor === Array ); // false
</script>
...

这是因为浏览器会把不同页面中的Array做区分,即pageOne和pageTwo的Array是不同的两个构造器,所以跨iframe的变量无法通过这两种方法来判断


六、Object.prototype.toString.call()

使用typeof无法区分null、array、date
instanceof无法运用在值类型区分
没事,我们还有一种方法,Object.prototype.toString.call()

Object.prototype.toString.call()是一种比较常用,也是比较有效的方法

var a = {name: 1};
Object.prototype.toString.call(a); // [object Object]

var b = new Date();
Object.prototype.toString.call(b); // [object Date]

Object.prototype.toString.call(null); // [object Null]

Object.prototype.toString.call(undefined); // [object Undefined]

function a(){
	console.log(Object.prototype.toString.call(arguments)); // [object Arguments]
}

通过这种方式我们就可以解决常见问题中的类型判断

那么,为什么Object.prototype.toString.call()可以区分数据类型?


七、探索为什么Object.prototype.toString.call()可以区分数据类型

我们先来了解一下在调用Object.prototype.toString.call()的时候发生了什么

1.在ECMA5中,调用Object.prototype.toString会执行以下步骤:

这里写图片描述

(1).如果值为undefined,则返回"[object Undefiend]"

(2).如果值为null,则返回"[object Null]"

(3).将传递的值调用ToObject方法,并赋给O作为调用后的结果

(4).将O的内部属性[[Class]]的值赋给class

(5).结果返回字符串,该字符串由三个字符串"[object ", class, and "]"拼接而成

根据上面的描述我们可以看出来,主要通过对象的内置属性[[Class]]来判断

2.内置属性[[Class]]

ECMA规范中这么介绍[[Class]]
这里写图片描述
这里写图片描述

翻译:本规范针对每种内置对象定义了[[Class]]内部属性的值。对象的[[Class]]内部属性的值可以是除了。。。之外的任何字符串值。[[Class]]内部属性的值用于内部区分不同类型的对象。 请注意,除了通过Object.prototype.toString外,本规范没有提供任何方法让程序访问该值。

我们再来看规范中,在创建某种类型变量的时候,会对对象内置属性[[Class]]进行赋值

  • 创建数组时:
    这里写图片描述

  • 创建函数时:
    这里写图片描述

  • 创建字符串时:
    这里写图片描述

3.ES6中不再使用[[Class]]内置属性进行判断

最新规范中不再使用[[Class]]内置属性进行判断,在调用Object.prototype.toString时执行了以下步骤:
这里写图片描述

(这里不详细讲,有兴趣的可以去了解下)

综上,大家应该了解了为什么Object.prototype.toString.call()可以用来区分数据类型


一些问题

1.null和undefined不是对象,为什么Object.prototype.toString.call()返回的值要采用[object *]的格式

这是ES5.1规范中的修正。 在ES5之前,将null或undefined传递给toString总是导致全局对象被传递。 ES5中严格模式相关的更改会导致null和undefined被传递而不进行修改。 按照ES5的规定,将null或undefined传递给Object.prototype.toString会导致TypeError异常。 这个例外破坏了一些现有的代码,所以ES5.1修复这个规范,以防止这种情况发生。

那么,为什么toString返回null和undefined? 事实证明,很多现有的代码也期望Object.prototype.toString始终返回形式为“[object *]”的字符串。 因此,ES5.1规范中决定将传入null和undefined的值“[object Null]”和“[object Undefined]”。

2.Object.prototype.toString(‘foo’)和Object.prototype.toString.call(‘foo’)的区别

前者传入的参数实际是Object.prototype,而Object.prototype是个对象,所以始终返回’[object Object]’,其中的’foo’会被忽略;而后者通过call,硬绑定到传入的’foo’;所以千万不要把call忘了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值