前言
本篇可能有些枯燥,我收集了大量资料后整理下来的,因为都是理论性的东西,最好挑一个能静下心的时间段,然后配合文中的“来源”地址一起阅读。
数据类型
ECMAScript数据类型分为两大类: 语言类型(Language Types)和规范类型(Specification Types)
语言类型(Language Types)
语言类型就是我们常用的7类: Undefined, Null, Boolean, String, Symbol, Number 和 Object
来源:http://www.ecma-international.org/ecma-262/9.0/index.html#sec-ecmascript-language-types
规范类型(Specification Types)
规范类型用来规范、描述ECMAScript的一些操作行为,规范类型值可用于描述ECMAScript表达式计算的中间结果,但这些值不能存储为对象的属性或ECMAScript语言变量的值。也就是说我们不能直接在ECMAScript中使用这种类型。有这7类: Reference, List, Completion, Property Descriptor, Lexical Environment, Environment Record, 和 Data Block
比如 Completion类型是用来解释行为break、continue、return和throw语句的:
The Completion type is a Record used to explain the runtime propagation of values and control flow such as the behaviour of statements (break, continue, return and throw) that perform nonlocal transfers of control. 来源:http://www.ecma-international.org/ecma-262/9.0/index.html#sec-completion-record-specification-type
规范类型我们几乎用不到,稍作了解即可,主要深入了解一下语言类型。
语言类型又分为两类:原始值和引用值,变量可以存在这两种类型的值。
在ECMAScript中,用原始值(primitive values)和对象(objects)来区分实体,因此有些文章里说的“在JavaScript里,一切都是对象”是不完全对的。
下面说一说原始值和对象(引用值)都是什么。
原始值(primitive values)
定义
存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。
分类
原始值类型一共6类:Undefined, Null, Boolean, String, Number, Symbol (其中,最后一个 Symbol是ES6才出现的)
对应的原始值就是:undefined, null, true/false, 字符串, 数字, symbol
A primitive value is a datum that is represented directly at the lowest level of the language implementation.
原始值是在底层上直接实现的表现的数据,所以没有原型、没有构造函数。 因此有如下结果:
undefined.toString() // 报错
null.toString() // 报错
boolean.toString() // 报错2
3
但是为什么下面这个不报错呢?
'vinsea'.toString() // vinsea
true.toString() // true2
因为这时候的 'vinsea'、true 已经不是原始值类型了,已经被强转成了对象类型。详情见该专题后续文章解释。
判断
如何判断一个原始值的所属类型?用 typeof:
typeof true // boolean
typeof 'vinsea' // string
typeof 1993 // number
typeof undefined // undefined2
3
4
但是!typeof null 却不是 null,而是 object。 为什么?见该专题后续文章解释。
对象(objects)
定义
存储在堆(heap) 中,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存处。 对象类型和原始类型不同的是:原始类型存储的是值,对象类型存储的是地址(指针)。
::: hljs-center
-- 来源于 w3cschool -- :::
既然ECMAScript用原始值和对象区分实体,那说明除了上述的原始值外,其他全都是对象类型了。
An Object is logically a collection of properties. Properties are identified using key values. A property key value is either an ECMAScript String value or a Symbol value
对象是一个个属性的合集,属性是由key-values键值对的方式存储的,key值可以是string或者symbol,value是原始值和其他对象。
举个栗子:
let Vinsea = {
sex: 'male',
favorites: {
game: 'none',
sport: 'swimming,skiing,traveling and so on'
},
dance: function () {
return 'dancing ... ';
}
}
console.log(Vinsea.sex) // male
console.log(Vinsea.favorites) // {game: "none", sport: "swimming,skiing,traveling and so on"}
console.log(Vinsea.favorites.game) // none
console.log(Vinsea.favorites.sport) // swimming,skiing,traveling and so on
console.log(Vinsea.dance()) // dancing ...
console.log(typeof Vinsea.favorites); // object2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
对象是包含键值对的属性的合集,这个键值对的“键”(key)就是对象的属性,“值”(value)就是对象的属性的值。如果这个值是个函数,那么就把这个值对应的键称为:方法。
记好上面这句话,结合定义,分析一下刚才这个例子:
- Vinsea 是一个对象;
- Vinsea 有三个属性,key分别是
sex、favorite、dance。 - 第一个属性 sex 的值(value)为 'male';
- 第二个属性 favorite 又是一个对象,里面有两个属性,key是 game 和 sport;
- game 属性的值(value)为 'none';
- sport 属性的值(value)为 'skiing,traveling and so on';
- 第三个属性 dance 是一个方法,因为值(value)是个函数,这个函数返回一个字符串 'dancing ... ',调用的时候要在属性名后加括号。
判断
判断一个对象属于什么类型,就不能用 typeof 了,因为 typeof 对于对象来说,除了函数都会显示 object:
console.log(typeof {}) // 'object'
console.log(typeof []) // 'object'
console.log(typeof Vinsea.favorites) // object
console.log(typeof new String('Vinsea')) // object
console.log(typeof Vinsea.dance) // 'function'2
3
4
5
如果我们想判断一个对象的正确类型,可以考虑使用 instanceof,因为内部机制是通过原型链来判断的。
console.log('Vinsea' instanceof String) // false
console.log(1993 instanceof Number) // false
console.log(new String('Vinsea') instanceof String) // true
let Vinsea = function() {}
let v1 = new Vinsea()
console.log(v1 instanceof Vinsea) // true2
3
4
5
6
7
可以看到instanceof判断原始类型都返回false。
小总结一下就是:判断原始类型用 typeof,判断对象用 instanceof。
要是想用 instanceof 判断原始类型呢?见本专题后续文章。
注意:本篇说的Object类型,不要和Object构造函数混淆了,现在讨论的是抽象类型,是描述ECMAScript对象的唯一一个数据类型