类型
pr1mavera 2019/11/20
# 基本类型
# Undefined
意为:定义了但是为空
非关键字,变量,可以被重新赋值
通常使用 void 0
代替
隐式转换成 false
# Null
意为:空值
关键字
隐式转换成 false
# Boolean
布尔值,true
/ false
# String
字符串,最大长度 2^53 - 1(根据字符串的 UTF16 编码)
有 length
属性
空字符串 ''
隐式转换成 false
# new String()
# Number
数字,有效的整数范围是 -2^53 到 2^53(-0x1fffffffffffff 至 0x1fffffffffffff)
存在 +0 和 -0 ,检验方式:检测 1/x 是 Infinity 还是 -Infinity
隐式转换成 false
# 几个例外情况
- NaN
- 占用了 9007199254740990,原本是符合 IEEE 规则的数字
- NaN != NaN(NaN不等于任何内容,甚至其本身,使用
isNaN()
检测) - 判断两个 NaN 是否是相同的类型,使用
Object.is(NaN, NaN) === true
- Infinity,无穷大,使用
isFinite()
检测 - -Infinity,负无穷大,使用
isFinite()
检测
浮点数之间不可用 ==(===)比较 !
0.1 + 0.2 == 0.3
为 false
- 原因:浮点数运算的精度问题导致等式两边并不是严格相等
- 解决方式:(换一种比较的方法)使用 JavaScript 提供的最小精度值比较
Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON
true
# 多进制
- 二进制 -
0b
(或0B
) - 八进制 -
0o
(或0O
) - 十六进制 -
0x
(或0X
)
# Number.EPSILON
极小的常量,表示 1 与大于 1 的最小浮点数之间的差,通常用于 js 中数值的最小精度
// 安全的浮点数大小比较方式
function safeFloatComparators (left, right) {
return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2);
}
safeFloatComparators(0.1 + 0.2, 0.3);
# 引用类型
# Object
- 属性的集合,存在一套自己的类型系统
- 基础类型存在其对应的引用类型
- 需认识到:
'123'
与Object('123')
完全是两个东西'123'
- 基本类型String
Object('123')
- 引用类型,私有的[[Class]]
为[object String]
更多请移步 深入js对象
# 类型转换
# String -> Number
# parseInt
parseInt(str: string, radix: number = 10)
- str - 待转成数字的字符串,若不是字符串则会先尝试转成字符串
- radix - 转换的进制数,默认为
10
,不传入该参数时只支持解析 16 进制前缀0x
,建议始终传入该参数,可读性、兼容性
- 常见使用
parseInt('0xb'); // 11 parseInt('011'); // 11 parseInt(011); // 9 parseInt(11.99); // 11 parseInt('11,123', 10); // 11 parseInt('f', 16); // 15 parseInt('fx', 16); // 15
# parseFloat
- 将解析至非法字符之前
- 非法字符:除了
+
、-
、0-9
、.
、e
之外的字符(包括第二个.
) - 忽略之前、之后的空字符
# 按位非
~~
- 按位非(反码):对任一数值 x 进行按位非操作的结果为
-(x + 1)
,例~5 == -6
- 原理:每一位,按位非两次
- 只用于可以解析的整数部分,存在解析不了的直接返回
0
# Number()
Number构造函数,将转换为数字对应的引用类型,与 运算符
使用同样的解析算法,若存在无法解析的值将直接返回 NaN
# 一元运算符
- 运算符会将参数隐式类型转换(引用类型则拆箱)
- 转换规则为:
- 存在引用类型则都先拆箱(转换成对应的基本类型)再做后续判断
+
且 运算符两侧存在字符串- 将两侧尝试转换成字符串进行拼接,转换失败的拼接成
NaN
- 将两侧尝试转换成字符串进行拼接,转换失败的拼接成
- 其他情况
- 将两侧尝试转换成数字进行运算,转换失败的返回
NaN
- 将两侧尝试转换成数字进行运算,转换失败的返回
# Number -> String
符合直觉上的转换成十进制字符串,若字符串过长则使用科学计数法
# 装箱
将基本类型包装成对应的对象,装箱后可以调用对象上的方法(使用方法调用会将基本类型隐式装箱)
true.toString(); // "true"
// true -> Object(true) / Boolean(true) -> Object(true).toString()
Object(123).__proto__ === Number(123).__proto__ // true
# 显示装箱
- 可以通过
Object()
- 函数的 call 方法强制装箱
# 装箱检验
- typeof 检测为
'object'
- instanceof 对应的构造函数 为 true
- .constructor 检测为对应的构造函数
- Object.prototype.toString(获取对象皆有私有的 Class 属性) 可以用来准确判断对象类型
var someNumber = Object(0);
// var someNumber = (function(){ return this; }).call(0);
typeof someNumber // 'object'
someNumber instanceof Number // true
someNumber.constructor == Number // true
Object.prototype.toString.call(someNumber) // [object Number]
# 拆箱
标准中制定了 ToPrimitive
函数,指对象类型到基本类型的转换
- 引擎先尝试调用 valueOf 和 toString 来获得拆箱后的基本类型,若 valueOf 和 toString 都不存在,或者没有返回基本类型,报错 TypeError
- 调用 valueOf 和 toString 的先后顺序是依照
ToPrimitive(o [, PreferredType])
中的 PreferredType(第二个参数)决定的,默认为 'number' ,因此顺序为 valueOf -> toString - 几类对象类型的 toString 的重写覆盖
// Object ({}).toString(); // "[object Object]" // String ('abcd').toString(); // "abcd" // Array ([1, 2, 3]).toString(); // "1,2,3" // Function (function () {}).toString(); // "function () {}" // RegExp /d/.toString(); // "/d/"
- 对
Object.prototype.toString
特别说明- 获取对象皆有私有的 Class 属性
Object.prototype.toString.call({}) /* "[object Object]" */ Object.prototype.toString.call('abcd') /* "[object String]" */ Object.prototype.toString.call([1, 2, 3]) /* "[object Array]" */ Object.prototype.toString.call(function () {}) /* "[object Function]" */ Object.prototype.toString.call(/d/) /* "[object RegExp]" */
- 常用类型检测
interface IsType: ( tar: any, type: 'Undefined' | 'Boolean' | 'Number' | 'String' | 'Object' | 'Function' ) => boolean; const isType: IsType = (tar, type) => typeof tar === type.toLowerCase() && Object.prototype.toString.call(tar) === `[object ${type}]`;
# 相等性检测
===
严格相等判断,既判断类型,也判断值==
相等判断,会先产生隐式类型转换,再尝试使用===
从上图可以找到的规律:
- Number \ String \ Boolean 之间比较的时候总是将非数字转换成数字(使用
+
,类似于+'123' === 123
) - Object 与其他类型比较时基本进行拆箱操作,转换成更简单的类型,再进行比较
- 有几个特殊的要记一下
-0 == +0 /* true */ null == undefined /* true */ null == false /* false */ undefined == false /* false */ 0 == null /* false */