众所周知,JavaScript 是一门弱类型语言,不对变量进行类型强制,变量能够随时持有任何类型的值,因此在 JavaScript 中,类型对于咱们开发人员来讲能够理解为值的内部特征,类型定义了值的行为,以使其可以区别于其余值。javascript
JavaScript 中共有七种内置数据类型,包括基本类型和对象类型。html
基本类型分为如下六种:java
string
(字符串)boolean
(布尔值)number
(数字)symbol
(符号)null
(空值)undefined
(未定义)string
、number
、boolean
和 symbol
这四种类型统称为原始类型(Primitive),表示不能再细分下去的基本类型;symbol
表示独一无二的值,经过 Symbol
函数调用生成,因为生成的 symbol
值为原始类型,因此 Symbol
函数不能使用 new
调用;null
和 undefined
一般被认为是特殊值,这两种类型的值惟一,就是其自己。git
对象类型( object
)也称引用类型,以此和 JavaScript 的基本类型区分开来。对象在逻辑上是属性的无序集合,是存放各类值的容器。对象值存储的是引用地址,因此和基本类型值不可变的特性不一样,对象值是可变的。github
声明一个对象一般有如下几种方式:数组
const obj = {} // 字面量形式,推荐
const obj = new Object() // new调用
const obj = Object() // 与new调用相同
cosnt obj = Object.create(null) // 空对象
复制代码
咱们知道对象拥有属性和方法。但好比字符串这种基本类型值不属于对象为何还拥有属性和方法呢?实际上在引用字符串的属性或方法时,会经过调用 new String()
的方式转换成对象,该对象继承了字符串的方法来处理属性的引用,一旦引用结束,便会销毁这个临时对象,这就是包装对象的概念。bash
不只仅只是字符串有包装对象的概念,数字和布尔值也有相对应的 new Number()
和 new Boolean()
包装对象。null
和 undefined
没有包装对象,访问它们的属性会报类型错误。函数
字符串、数字和布尔值经过构造函数显式生成的包装对象,既然属于对象,和基本类型的值必然是有区别的,这点能够经过 typeof
检测出来。post
typeof 'seymoe' // 'string'
typeof new String('seymoe') // 'object'
复制代码
咱们常常听到诸如“ JavaScript 中一切皆是对象”的论断,而且可以指出部分理由(或者说误导性假象):学习
typeof null
结果是 object
但通过上述的内容,咱们应该很容易反驳“ JavaScript 中一切皆是对象”这一错误的论断。
上文中咱们了解了 JavaScript 中的数据类型,那么如何去判断一个值属于什么数据类型呢?
判断一个值属于那种数据类型共有三种方式,分别为 typeof
、instanceof
和 Object.prototype.toString()
,咱们分别来看。
通常经过 typeof
操做符来判断一个值属于哪一种基本类型。
typeof 'seymoe' // 'string'
typeof true // 'boolean'
typeof 10 // 'number'
typeof Symbol() // 'symbol'
typeof null // 'object' 没法断定是否为 null
typeof undefined // 'undefined'
复制代码
根据以上能够看出,只有 null
的断定会有偏差。
若是使用 typeof
操做符对对象类型及其子类型,譬如函数(可调用对象)、数组(有序索引对象)等进行断定,则除了函数都会获得 object
的结果。
typeof {} // 'object'
typeof [] // 'object'
typeof(() => {}) // 'function'
复制代码
因为没法得知一个值究竟是数组仍是普通对象,显然经过 typeof
判断具体的对象子类型远远不够。
经过 instanceof
操做符也能够对对象类型进行断定,其原理就是测试构造函数的 prototype
是否出如今被检测对象的原型链上。
[] instanceof Array // true
({}) instanceof Object // true
(()=>{}) instanceof Function // true
复制代码
注意:instanceof
也不是万能的。
举个例子:
let arr = []
let obj = {}
arr instanceof Array // true
arr instanceof Object // true
obj instanceof Object // true
复制代码
在这个例子中,arr
数组至关于 new Array()
出的一个实例,因此 arr.__proto__ === Array.prototype
,又由于 Array
属于 Object
子类型,即 Array.prototype.__proto__ === Object.prototype
,因此 Object
构造函数在 arr
的原型链上。因此 instanceof
仍然没法判断优雅的判断一个值到底属于数组仍是普通对象。
还有一点,可能有人会说 Object.prototype.__proto__ === null
,岂不是说 arr instanceof null
也应该为 true
,这个语句其实会报错提示右侧参数应该为对象,这也印证 typeof null
的结果为 object
真的只是个 bug 。
Object.prototype.toString()
能够说是断定 JavaScript 中数据类型的终极解决方法了,具体用法请看如下代码:
Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call([]) // '[object Array]'
Object.prototype.toString.call(() => {}) // '[object Function]'
Object.prototype.toString.call('seymoe') // '[object String]'
Object.prototype.toString.call(1) // '[object Number]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(Symbol()) // '[object Symbol]'
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
Object.prototype.toString.call(new Date()) // '[object Date]'
Object.prototype.toString.call(Math) // '[object Math]'
Object.prototype.toString.call(new Set()) // '[object Set]'
Object.prototype.toString.call(new WeakSet()) // '[object WeakSet]'
Object.prototype.toString.call(new Map()) // '[object Map]'
Object.prototype.toString.call(new WeakMap()) // '[object WeakMap]'
复制代码
咱们能够发现该方法在传入任何类型的值都能返回对应准确的对象类型。用法虽简单明了,但其中有几个点须要理解清楚:
Object.prototype.toString()
方法获得对象内部属性 [[Class]]
null
和 undefined
可以输出结果是内部实现有作处理将值从一种类型转换为另外一种类型被称为“类型转换”,在 JavaScript 中类型转换都属于强制类型转换。更进一步,咱们能够借用《You Don't Know JS》做者在中卷提到的观点,将强制类型转换分为隐式强制类型转换和显式强制类型转换。某些操做符产生的反作用等不明显的转换就是隐式转换,咱们可以从代码中看到哪些地方进行了转换就是显式转换。
let a = 10
let b = a + '' // 隐式强制类型转换
var c = String(a) // 显式强制类型转换
复制代码
上述代码中,对于变量 b
来讲,a
被强制转换为字符串类型与 ''
拼接,这个过程是“隐式”的,而对于变量 c
而言,主动调用 String
构造函数进行类型转换是“显式”的。但隐式和显式仍然是相对的,若是你本身清楚数字与字符串相加,数字会被强制转换为字符串这个规则,那么它就是显式的,反之同理。
JavaScript 中,强制类型转换老是会返回基本类型的值,好比字符串、数字、布尔值,不会返回对象和函数。
ES规范定义了一些抽象操做(即仅供内部使用的操做)和转换规则来进行强制类型转换,ToString 抽象操做就负责处理非字符串到字符串的强制类型转换。
转换规则:
null
转换为 'null'
undefined
转换为 undefined
true
转换为 'true'
,false
转换为 'false'
toString()
方法,不然返回内部属性 [[Class]]
,如上文提到的 [object Object]
toString()
被从新定义的则相应调用返回结果String(null) // 'null'
String(undefined) // 'undefined'
String(true) // 'true'
String(1) // '1'
String(-1) // '-1'
String(0) // '0'
String(-0) // '0'
String(Math.pow(1000,10)) // '1e+30'
String(Infinity) // 'Infinity'
String(-Infinity) // '-Infinity'
String({}) // '[object Object]'
String([1,[2,3]]) // '1,2,3'
复制代码
ToNumber 抽象操做负责处理非数字类型转换为数字类型。
转换规则:
null
转换为 0
undefined
转换为 NaN
true
转换为 1
,false
转换为 0
NaN
为了将值转换为基本类型值,规范定义了 ToPrimitive
内部操做,该操做首先检测该值是否存在 valueOf()
方法,有且返回的值为基本类型值则用此值返回或继续转换,没有则检测是否存在 toString()
方法,有且返回基本类型值则用此值返回或继续转换,没有则报错。
ToBoolean 抽象操做负责处理非布尔类型转换为布尔类型。
转换规则:
null
、undefined
、false
、+0
、-0
、NaN
和 ''
JavaScript 中的数据类型总共只有七种,包括六种基本类型和对象类型,对象类型拥有不少子类型,也能够说是 JavaScript 的内置对象。判断一个值属于那种数据类型有三种方式。JavaScript 中的数据类型转换只会返回基本类型值,因此基本存在转换为字符串、数字和布尔值三种状况,转换的更多具体细节,本文不作讨究。
写做是一个学习的过程,尝试写这个系列也主要是为了巩固 JavaScript 基础,并尝试理解其中的一些知识点,以便能灵活运用。若是有错误或者不严谨的地方,请务必给予指正,十分感谢!
整个系列会持续更新,不会完结。