类型


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

# 一元运算符

  • 运算符会将参数隐式类型转换(引用类型则拆箱)
  • 转换规则为:
    1. 存在引用类型则都先拆箱(转换成对应的基本类型)再做后续判断
    2. + 且 运算符两侧存在字符串
      • 将两侧尝试转换成字符串进行拼接,转换失败的拼接成 NaN
    3. 其他情况
      • 将两侧尝试转换成数字进行运算,转换失败的返回 NaN

# Number -> String

符合直觉上的转换成十进制字符串,若字符串过长则使用科学计数法

# 装箱

将基本类型包装成对应的对象,装箱后可以调用对象上的方法(使用方法调用会将基本类型隐式装箱)

true.toString(); // "true"
// true -> Object(true) / Boolean(true) -> Object(true).toString()
Object(123).__proto__ === Number(123).__proto__ // true

# 显示装箱

  1. 可以通过 Object()
  2. 函数的 call 方法强制装箱

# 装箱检验

  1. typeof 检测为 'object'
  2. instanceof 对应的构造函数 为 true
  3. .constructor 检测为对应的构造函数
  4. 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}]`;
    

# 相等性检测

  • === 严格相等判断,既判断类型,也判断值
  • == 相等判断,会先产生隐式类型转换,再尝试使用 ===

相等性判断

从上图可以找到的规律:

  1. Number \ String \ Boolean 之间比较的时候总是将非数字转换成数字(使用 + ,类似于 +'123' === 123
  2. Object 与其他类型比较时基本进行拆箱操作,转换成更简单的类型,再进行比较
  3. 有几个特殊的要记一下
    -0 == +0 /*             true */
    null == undefined /*    true */
    null == false /*        false */
    undefined == false /*   false */
    0 == null /*            false */
    
Last Updated: 12/2/2019, 9:23:57 AM