Javascript数据类型
值类型和引用类型
- 原始类型(alias: 值类型,基础类型) primitive:
string
number
boolean
undefined
symbol
null
- 引用类型:
Object
其他内置Object派送类型Array
Function
Map
Set
WeakMap
WeakSet
RegExp
- NaN: 特殊的
Number
类型,IsNaN()
判断一个值是否为NaN
值类型引用类型存在的差异
- 引用类型可以有属性和方法,而基础值类型是不可以的
- 为什么
'text'.length
可以访问到'text'
的length
属性?→ 包装类
- 为什么
- 引用类型在堆上, 值类型在栈上
- 引用类型值可变,基础值类型值不可变
- 值类型是按值比较的,引用类型比较的是引用的地址
包装类
String
Number
Boolean
Symbol
new String('')
和 String('')
的区别
new String('')
构造一个String
实例, 得到的是一个对象;let a = new String('a'); let b = new String('b')
,a
和b
是不相等的,a
b
保存的是两个不同的引用地址- 直接调用
String
函数的话是会执行类型转换,这个函数返回的就是一个值类型的string
;String(1)
返回值是'1'
'text'.length
能够工作的原因
通过 .
(术语:属性访问器Property Accessor
) 访问值类型 'text'
的 length
属性时, 会发生类型转换(装箱),值类型的 'text'
会转换为引用类型的 String
实例(相当与 new String('text')
), 然后这个 String
实例的 length
属性会被返回;
每次访问一个 string
值类型的属性时,都会 new
一个新的 String
包装类,返回这个包装类实例对应的属性值,返回后这个包装类的实例就会立即被丢弃
Number
Boolean
同理, Symbol
比较特殊, new Symbol
会抛出 TypeError
, 详见下文 → Symbol
值类型转换为引用类型(ToObject
)的逻辑 → TC39 - sec-toobject
Symbol
Symbol
是一个比较特殊的包装类, 因为无法通过 new
操作符创建 Symbol
实例
通常直接通过 Symbol('bar')
函数创建值类型的 symbol
Symbol(key: string)
不论传入的参数 key
是什么,都会保证返回唯一的 symbol
值类型, 也就是通过 Symbol(key: string)
函数创建的每个 symbol
都是不相等的
let s = Symbol('foo');
let b = Symbol('foo');
console.log(s === b); // false
Symbol.for
Symbol.for(key: string)
可以保证返回相同的 symbol
类型, 如果传入的参数 key
已在全局 symbol
仓库中, 那么返回那个仓库中对应 key
的 symbol
, 否则创建一个新的 symbol
Symbol.keyFor
Symbol.keyFor(s: symbol)
接受一个 symbol
作为参数,返回参数 s:symbol
的 key
, s: symbol
必须是通过 Symbol.for(key: string)
创建在全局 symbol
仓库中的才行,否则会返回 undefined
let s = Symbol.for('foo');
console.log(Symbol.keyFor(s)); // 'foo'
Symbol的使用场景
- 用作对象属性的键值(
key
), 可以有效防止对象属性的键值冲突;- 这应该是最主要的用途了,解决属性名称冲突问题,mdn和其他一些资料都提到了这个
- Symbol 是 es6 中引入的, 引入 Symbol 的动机应该是为了解决私有属性的问题; 但是实际上并没有
Object.getOwnPropertySymbols(object: Object)
返回参数object
的所有symbol
属性数组- 设置可以通过内置的通用Symbol访问对象的某些属性
Javascript中通用Symbol(well-known Symbols
)
Symbol
的静态属性中包含的通用Symbol 如下
- Symbol.iterator with Iterable and Iterator protocol
- Symbol.search
- Symbol.toStringTag
- Symbol.unscopables
- Symbol.isConcatSpreadable
- Symbol.toPrimitive
- Symbol.prototype
- Symbol.split
- Symbol.hasInstance
- Symbol.match
- Symbol.species
类型检测
typeof
和 instanceof
typeof
检测基础值类型
console.log(typeof '1') // string
console.log(typeof 1) // number
console.log(typeof false) // boolean
console.log(typeof Symbol('foo')) // symbol
console.log(typeof undefined) // undefined
console.log(typeof null) // object
console.log(typeof new Date()) // object
有一个特例 typeof null
的返回值按理说应该是 null
但实际却是 object
; 这其实是一个bug
简单来说,
typeof null
的结果为Object
的原因是一个bug
。在javascript
的最初版本中,使用的32
位系统,js
为了性能优化,使用低位来存储变量的类型信息。
在判断数据类型时,是根据机器码低位标识来判断的,而null
的机器码标识为全0
,而对象的机器码低位标识为000
。所以typeof null
的结果被误判为Object
。
instanceof
检测引用类型,判断指定值原型是否在原型链上的任意一个类型
console.log(new Date() instanceof Date) // true
参考资料
简书 - 【JS】string和String差异详解,基本类型和包装类学习
MDN - Symbol
MDN中文- Symbol
掘金 - JavaScript进阶知识点
Github - everything-you-need-to-know-about-javascript-symbols
为什么typeof null的结果是Object?