lizhongzhen11 / lizz-blog

前端学习
80 stars 6 forks source link

重学js —— Number 原型对象和实例上的属性(tofixed/toLocaleString/toPrecision/toString等) #112

Open lizhongzhen11 opened 4 years ago

lizhongzhen11 commented 4 years ago

Number 原型对象和实例上的属性

thisNumberValue(value)

  1. 如果 valueNumber 类型,返回 value
  2. 如果 value 是对象类型且 value[[NumberData]] 内置插槽
    1. 定义 nvalue.[[NumberData]]
    2. 断言:nNumber 类型
    3. 返回 n
  3. TypeError 异常

规范中短语 "this Number value" 表示将方法的 this 值作为参数传给抽象操作 thisNumberValue 调用后返回的结果

Number.prototype.constructor

初始值为 %Number%

Number.prototype.toExponential ( fractionDigits )

// 有趣
// 和 https://github.com/lizhongzhen11/lizz-blog/issues/96 提到的思考本质是一样的
77.toExponential() // 报错
77..toExponential() // "7.7e+1"
77                 .toExponential() // "7.7e+1"
  1. 定义 x? thisNumberValue(this 值)

  2. 定义 f? ToInteger(fractionDigits)

  3. 断言:如果 fractionDigitsundefined,则 f0

  4. 如果 x 不是有限的,返回 ! Number::toString(x)

  5. 如果 f < 0f > 100,抛 RangeError 异常

  6. 定义 s 为空字符串

  7. 如果 x < 0

    1. 设置 s"-"
    2. 设置 x-x
  8. 如果 x = 0

    1. 定义 m 为字符串,由 f + 1 处出现的码位 0x0030(数字0) 组成
    2. 定义 e0
  9. 否则,

    1. 如果 fractionDigits 不是 undefined
      1. 定义 en 为整数,使得 10f ≤ n < 10f + 1 并且 R(n) x 10RR(e) - R(n) - R(x) 尽可能的接近0。如果有两对 en,选满足 R(n) x 10RR(e) - R(f) 运算较大的那一对。
    2. 否则,
      1. 定义 enf 为整数,使得 f ≥ 010f ≤ n < 10f + 1R(n) x 10RR(e) - R(f)Number 值为 x,并且 f 尽可能的小。注意 n 的十进制表示有 f + 1 个数字,n 不能被 10 整除,但是这些标准不一定能唯一确定 n 的最低有效位。
    3. 定义 m 为字符串,由 n 的十进制表示数字组成(按顺序,没有前导零)
  10. 如果 f ≠ 0

    1. 定义 am 的第一个码位,定义 bm 的剩余 f 位码位。
    2. 设置 ma"."b 的字符拼接
  11. 如果 e = 0

    1. 定义 c"+"
    2. 定义 d"0"
  12. 否则,

    1. 如果 e > 0,定义 c"+"
    2. 否则,
      1. 断言:e < 0
      2. 定义 c"-"
      3. 设置 e-e
    3. 定义 d 为字符串,由 e 的十进制表示数字组成(按顺序,没有前导零)
  13. 设置 mm"e"cd 的字符拼接

  14. 返回 sm 的字符拼接

Number.prototype.toFixed ( fractionDigits )

2.34.toFixed(3) // '2.340'
2.45.toFixed(1) // '2.5'
2.55.toFixed(1) // '2.5'
-2.34.toFixed(1) // -2.3
(-2.34).toFixed(1) // '-2.3'

2.34.toFixed(100) // 自己去试下吧
  1. 定义 x? thisNumberValue(this 值)
  2. 定义 f? ToInteger(fractionDigits)
  3. 断言:如果 fractionDigitsundefined,则 f0
  4. 如果 f < 0f > 100,抛 RangeError 异常
  5. 如果 x 不是有限的,返回 ! Number::toString(x)
  6. 定义 s 为空字符串
  7. 如果 x < 0
    1. 设置 s"-"
    2. 设置 x-x
  8. 如果 x ≥ 1021
    1. 定义 m! ToString(x)
  9. 否则,
    1. 定义 n 为满足 R(n) ÷ 10RR(f) - R(x) 运算中尽可能接近0的整数。如果有两个 n,选择较大的。
    2. 如果 n = 0,定义 m 为字符 "0"。否则,定义 m 为字符串,由 n 的十进制表示数字组成。(按顺序,没有前导零)
    3. 如果 f ≠ 0
      1. 定义 km 的长度
      2. 如果 k ≤ f
        1. 定义 z 为字符串,由 f + 1 - k 处出现的码位 0x0030(数字0) 组成
        2. 设置 mzm 的字符拼接
        3. 设置 kf + 1
      3. 定义 am 的前 k - f 码位,定义 bm 的剩余 f 个码位
      4. 设置 ma"."b 的字符拼接
  10. 返回 sm 的字符拼接

对于某些值,toFixed 的输出可能比 toString 更精确,因为 toString 仅打印足够的有效数字以将数字与相邻数字值区分开。

(1000000000000000128).toString() // "1000000000000000100"
(1000000000000000128).toFixed(0) // "1000000000000000128"

Number.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] )

// 好方便啊,我真第一次知道
123456789 .toLocaleString() // "123,456,789"

Number.prototype.toPrecision ( precision )

  1. 定义 x? thisNumberValue(this 值)
  2. 如果 precisionundefined,返回 ! ToString(x)
  3. 定义 p ? ToInteger(precision)
  4. 如果 x 不是有限的,返回 ! Number::toString
  5. 如果 p < 1p > 100,抛 RangeError 异常
  6. 定义 s 为空字符串
  7. 如果 x < 0
    1. 设置 s 为码位 0x002D(减号)
    2. 设置 x-x
  8. 如果 x = 0
    1. 定义 m 为字符串,由 p 处d的码位 0x0030(数字0) 组成
    2. 定义 e0
  9. 否则
    1. 定义 en 为整数,使得 10p - 1 ≤ n < 10p,同时满足 R(n) × 10RR(e) - R(p) + 1R - R(x) 运算结果尽可能的接近0。如果有两对 en,选择执行 R(n) × 10RR(e) - R(p) + 1R 运算结果较大的那对。
    2. 定义 m 为字符串,由 n 的十进制表示数字组成(按顺序,没有前导零)
    3. 如果 e < -6e ≥ p
      1. 断言:e ≠ 0
      2. 如果 p ≠ 1
        1. 定义 am 的第一个码位,定义 bm 剩下的 p - 1 位码位
        2. 设置 ma".",和 b 的字符拼接
      3. 如果 e > 0
        1. 定义 c 为码位 0x002B(加号)
      4. 否则,
        1. 断言:e < 0
        2. 定义 c 为码位 0x002D(减号)
        3. 设置 e-e
      5. 定义 d 为字符串,由 e 的十进制表示数字组成(按顺序,没有前导零)
      6. 返回 sm,码位 0x0065(拉丁文小写字母E)cd 的字符拼接
  10. 如果 e = p - 1,返回 sm 的字符串拼接
  11. 如果 e ≥ 0
    1. 设置 mm 的前 e + 1 位码位,码位 0x002E(句号),以及 m 剩余的 p - (e + 1) 的字符拼接
  12. 否则,
    1. 设置 m 为码位 0x0030(数字0),码位 0x002E(句号)-(e + 1) 处的码位 0x0030(数字0) 和字符 m 的字符拼接
  13. 返回 sm 的字符串拼接

Number.prototype.toString ( [ radix ] )

  1. 定义 x? thisNumberValue(this 值)
  2. 如果 radixundefined,定义 radixNumber10
  3. 否则,定义 radixNumber? ToInteger(radix)
  4. 如果 radixNumber < 2radixNumber > 36,抛 RangeError 异常
  5. 如果 radixNumber = 10,返回 ! ToString(x)
  6. 返回使用 radixNumber 做基数的 Number 值的字符串表示。字母a-z用于数值从10到35的数字。精度算法与实现有关,但是,该算法应该是 Number::toString(x) 中指定的算法的概括。

该方法的 "length" 属性值为 1.

Number.prototype.valueOf ( )

  1. 返回 ? thisNumberValue(this 值)

Number 实例属性

属于普通对象,属性继承自 Number 原型对象。实例也有 [[NumberData]] 内置插槽。该插槽表示该 Number 对象的 Number 类型值

为何 2.45.toFixed(1) 是 '2.5' 而 2.55.toFixed(1) 还是 '2.5'?

主要还是浮点运算问题。看算法内部,走第9步:

由于js采用 IEEE-754 64位双精度浮点类型来表示数字,所以先要得出 25.5 的二进制表示,然后再确定最接近的那个整数。这个算起来好麻烦。。。

2020-07-31 补充

Daily-Interview-Question 第143题

我第一想法就是用 toLocaleString,不过转换成 . 真没记住。。。