Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
lizhongzhen11 opened this issue May 25, 2020 · 0 comments
Labels
js基础 Good for newcomers 重学js 重学js系列 规范+MDN

Comments

@lizhongzhen11
Copy link
Owner

lizhongzhen11 commented May 25, 2020

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 )

  • MDN
  • 规范中是介于 0 ~ 100(超过20会转字符串),但是MDN说介于 0 ~ 20,实现环境可能支持更大范围
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步:

  • 对于 2.45n 要满足 n ÷ 10 - 2.45 尽可能接近 0,即 n 要尽可能接近 24.5且是整数
  • 对于 2.55n 要满足 n ÷ 10 - 2.55 尽可能接近 0,即 n 要尽可能接近 25.5且是整数

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

2020-07-31 补充

Daily-Interview-Question 第143题

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

@lizhongzhen11 lizhongzhen11 added js基础 Good for newcomers 重学js 重学js系列 规范+MDN labels May 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
js基础 Good for newcomers 重学js 重学js系列 规范+MDN
Projects
None yet
Development

No branches or pull requests

1 participant