ES6學習筆記(數(shù)據(jù)類型的擴展方法——字符串岁忘、數(shù)值)

這篇文章僅記錄了本人在系統(tǒng)性學習ES6時辛慰,遇到的產(chǎn)生困惑或留意的點,用于以后開發(fā)中的review干像。

1.字符串擴展

1-1.JSON.stringify()

根據(jù)標準,JSON 數(shù)據(jù)必須是 UTF-8 編碼驰弄。但是麻汰,現(xiàn)在的JSON.stringify()方法有可能返回不符合 UTF-8 標準的字符串。

為了確保返回的是合法的 UTF-8 字符戚篙,ES2019 改變了JSON.stringify()的行為五鲫。如果遇到0xD8000xDFFF之間的單個碼點,或者不存在的配對形式岔擂,它會返回轉義字符串位喂,留給應用自己決定下一步的處理。

JSON.stringify('\u{D834}') // ""\\uD834""
JSON.stringify('\uDF06\uD834') // ""\\udf06\\ud834""

1-2.模板字符串

如果使用模板字符串表示多行字符串乱灵,所有的空格和縮進都會被保留在輸出之中塑崖。

$('#list').html(`
<ul>
  <li>first</li>
  <li>second</li>
</ul>
`);

上面代碼中,所有模板字符串的空格和換行痛倚,都是被保留的规婆,比如<ul>標簽前面會有一個換行。如果你不想要這個換行蝉稳,可以使用trim方法消除它抒蚜。

$('#list').html(`
<ul>
  <li>first</li>
  <li>second</li>
</ul>
`.trim());

模板字符串中嵌入變量,需要將變量名寫在${}之中耘戚。

由于模板字符串的大括號內(nèi)部嗡髓,就是執(zhí)行 JavaScript 代碼,因此如果大括號內(nèi)部是一個字符串收津,將會原樣輸出饿这。

可以進行運算,以及引用對象屬性朋截。還能調用函數(shù)蛹稍。如果大括號中的值不是字符串,將按照一般的規(guī)則轉為字符串部服。比如唆姐,大括號中是一個對象,將默認調用對象的toString方法廓八。

let x = 1;
let y = 2;

`${x} + ${y} = ${x + y}`
// "1 + 2 = 3"

`${x} + ${y * 2} = ${x + y * 2}`
// "1 + 4 = 5"

let obj = {x: 1, y: 2};
`${obj.x + obj.y}`
// "3"


//調用函數(shù)
function fn() {
  return "Hello World";
}

`foo ${fn()} bar`
// foo Hello World bar

模板字符串甚至還能嵌套奉芦。

const tmpl = addrs => `
  <table>
  ${addrs.map(addr => `
    <tr><td>${addr.first}</td></tr>
    <tr><td>${addr.last}</td></tr>
  `).join('')}
  </table>
`;
const data = [
    { first: '<Jane>', last: 'Bond' },
    { first: 'Lars', last: '<Croft>' },
];

console.log(tmpl(data));
// <table>
//
//   <tr><td><Jane></td></tr>
//   <tr><td>Bond</td></tr>
//
//   <tr><td>Lars</td></tr>
//   <tr><td><Croft></td></tr>
//
// </table>

1-3.標簽模板

模板字符串的功能赵抢,不僅僅是上面這些。它可以緊跟在一個函數(shù)名后面声功,該函數(shù)將被調用來處理這個模板字符串烦却。這被稱為“標簽模板”功能(tagged template)。

alert`hello`
// 等同于
alert(['hello'])

標簽模板其實不是模板先巴,而是函數(shù)調用的一種特殊形式其爵。但是,如果模板字符里面有變量伸蚯,就不是簡單的調用了摩渺,而是會將模板字符串先處理成多個參數(shù),再調用函數(shù)剂邮。

let a = 5;
let b = 10;

tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);

可以簡單理解為將參數(shù)中的字符串提取出來分割出一個裝有字符串的數(shù)組(字符串分割位置由變量所處位置決定)摇幻,參數(shù)中的變量依次提取并計算結果追加在數(shù)組后

這里有一個值得注意的地方:

let a = 5;
let b = 10;

tag`Hello ${ a + b } ${ a * b } world `;
// 等同于
tag(["Hello ", " ", " world "], 15, 50);

當變量出現(xiàn)在參數(shù)的最后時,參數(shù)數(shù)組中的最后一個元素將會是一個空字符串""

2.字符串的新增方法

2-1.String.raw()

該方法返回一個斜杠都被轉義(即斜杠前面再加一個斜杠)的字符串挥萌,往往用于模板字符串的處理方法绰姻。

String.raw`Hi\n${2+3}!`
// 實際返回 "Hi\\n5!",顯示的是轉義后的結果 "Hi\n5!"

String.raw`Hi\u000A!`;
// 實際返回 "Hi\\u000A!"引瀑,顯示的是轉義后的結果 "Hi\u000A!"

我們看到的打印出的結果是轉義之后的

String.raw`Hi\\n`
// 返回 "Hi\\\\n"

String.raw`Hi\\n` === "Hi\\\\n" // true

如果寫成正常函數(shù)的形式狂芋,它的第一個參數(shù),應該是一個具有raw屬性的對象伤疙,且raw屬性的值應該是一個數(shù)組银酗,對應模板字符串解析后的值。

// `foo${1 + 2}bar`
// 等同于
String.raw({ raw: ['foo', 'bar'] }, 1 + 2) // "foo3bar"
//`s${1 + 2}\n5`
//等同于
String.raw({ raw: ['s', '\\n5'] }, 1 + 2) // "s3\n5"

在大多數(shù)情況下, String.raw()是用來處理模版字符串的. 不要被上面復雜的參數(shù)要求嚇到徒像,因為像所有的 tag functions一樣黍特,你通常不需要把它看成一個普通函數(shù),你只需要把它放在模板字符串前面就可以了锯蛀,而不是在它后面加個括號和一堆參數(shù)來調用它灭衷,引擎會替你去調用它。

2-2.String.repeat()

repeat方法返回一個新字符串旁涤,表示將原字符串重復n次翔曲。參數(shù)如果是小數(shù),會被向下取整劈愚。

'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
'na'.repeat(2.9) // "nana"

如果repeat的參數(shù)是負數(shù)或者Infinity瞳遍,會報錯。
但是菌羽,如果參數(shù)是 0 到-1 之間的小數(shù)掠械,則等同于 0,這是因為會先進行取整運算。0 到-1 之間的小數(shù)猾蒂,取整以后等于-0均唉,repeat視同為 0。

'na'.repeat(Infinity)
// RangeError
'na'.repeat(-1)
// RangeError
'na'.repeat(-0.9) // ""

參數(shù)NaN等同于 0肚菠。如果repeat的參數(shù)是字符串舔箭,則會先轉換成數(shù)字。

'na'.repeat(NaN) // ""
'na'.repeat('na') // ""
'na'.repeat('3') // "nanana"

2-3.padStart()蚊逢,padEnd()

padStart()和padEnd()一共接受兩個參數(shù)层扶,第一個參數(shù)是字符串補全生效的最大長度,第二個參數(shù)是用來補全的字符串时捌。

如果用來補全的字符串與原字符串怒医,兩者的長度之和超過了最大長度,則會截去超出位數(shù)的補全字符串奢讨。

'abc'.padStart(10, '0123456789')
// '0123456abc'

如果省略第二個參數(shù),默認使用空格補全長度焰薄。

'x'.padStart(4) // '   x'
'x'.padEnd(4) // 'x   '

不管第二個參數(shù)是什么類型拿诸,都將先調用參數(shù)的toString方法將其轉為字符串之后進行拼接

'1'.padStart(10, 0) // "0000000001"
'1'.padStart(10, null) // "nullnulln1"
'1'.padStart(10, NaN) // "NaNNaNNaN1"
'1'.padStart(10, {}) // "[object O1"
'1'.padStart(10, []) // "1"
'1'.padStart(10, "") // "1"
'1'.padStart(10, undefined) // "         1"

注意:這里有兩個特殊的地方,當?shù)诙€參數(shù)為空數(shù)組時其返回值和參數(shù)為空字符串時的返回值相同塞茅,參數(shù)為undefined時亩码,返回值以空格進行填充其結果與不傳第二個參數(shù)的結果一致。

2-4.replaceAll()

它的用法與replace()相同野瘦,返回一個新字符串描沟,不會改變原字符串。

String.prototype.replaceAll(searchValue, replacement)

如果searchValue是一個不帶有g修飾符的正則表達式鞭光,replaceAll()會報錯吏廉。這一點跟replace()不同。

// 不報錯
'aabbcc'.replace(/b/, '_')

// 報錯
'aabbcc'.replaceAll(/b/, '_')

replaceAll()的第二個參數(shù)replacement是一個字符串惰许,表示替換的文本席覆,其中可以使用一些特殊字符串。

  • $&:匹配的子字符串汹买。
  • $`:匹配結果前面的文本佩伤。
  • $':匹配結果后面的文本。
  • $n:匹配成功的第n組內(nèi)容晦毙,n是從1開始的自然數(shù)生巡。這個參數(shù)生效的前提是,第一個參數(shù)必須是正則表達式见妒。
  • $$:指代美元符號$孤荣。
// $& 表示匹配的字符串,即`b`本身
// 所以返回結果與原字符串一致
'abbc'.replaceAll('b', '$&')
// 'abbc'

// $` 表示匹配結果之前的字符串
// 對于第一個`b`,$` 指代`a`
// 對于第二個`b`垃环,$` 指代`ab`
'abbc'.replaceAll('b', '$`')
// 'aaabc'

// $' 表示匹配結果之后的字符串
// 對于第一個`b`邀层,$' 指代`bc`
// 對于第二個`b`,$' 指代`c`
'abbc'.replaceAll('b', `$'`)
// 'abccc'

// $1 表示正則表達式的第一個組匹配遂庄,指代`ab`
// $2 表示正則表達式的第二個組匹配寥院,指代`bc`
'abbc'.replaceAll(/(ab)(bc)/g, '$2$1')
// 'bcab'

// $$ 指代 $
'abc'.replaceAll('b', '$$')
// 'a$c'

2.數(shù)值的擴展

2-1二進制和八進制表示法

ES6 提供了二進制和八進制數(shù)值的新的寫法,分別用前綴0b(或0B)和0o(或0O)表示涛目。

0b111110111 === 503 // true
0o767 === 503 // true

從 ES5 開始秸谢,在嚴格模式之中,八進制就不再允許使用前綴0表示霹肝,ES6 進一步明確估蹄,要使用前綴0o表示。

// 非嚴格模式
(function(){
  console.log(0o11 === 011);
})() // true

// 嚴格模式
(function(){
  'use strict';
  console.log(0o11 === 011);
})() // Uncaught SyntaxError: Octal literals are not allowed in strict mode.

轉成10進制可以用parseInt方法或者Number方法

2-2.Number.isFinite(), Number.isNaN()

ES6 在Number對象上沫换,新提供了Number.isFinite()和Number.isNaN()兩個方法臭蚁。

它們與傳統(tǒng)的全局方法isFinite()和isNaN()的區(qū)別在于,傳統(tǒng)方法先調用Number()將非數(shù)值的值轉為數(shù)值讯赏,再進行判斷垮兑,而這兩個新方法只對數(shù)值有效,Number.isFinite()對于非數(shù)值一律返回false, Number.isNaN()只有對于NaN才返回true漱挎,非NaN一律返回false系枪。

2-3.Number.parseInt(), Number.parseFloat()

ES6 將全局方法parseInt()和parseFloat(),移植到Number對象上面磕谅,行為完全保持不變私爷。

2-4.Number.isInteger()

Number.isInteger()用來判斷一個數(shù)值是否為整數(shù)。
如果對數(shù)據(jù)精度的要求較高膊夹,不建議使用Number.isInteger()判斷一個數(shù)值是否為整數(shù)衬浑。

Number.isInteger(5E-324) // false
Number.isInteger(5E-325) // true

上面代碼中,5E-325由于值太小,會被自動轉為0,因此返回true新锈。\

Number.isInteger(3.0000000000000002) // true

上面代碼中,Number.isInteger的參數(shù)明明不是整數(shù)拓诸,但是會返回true。原因就是這個小數(shù)的精度達到了小數(shù)點后16個十進制位麻昼,轉成二進制位超過了53個二進制位奠支,導致最后的那個2被丟棄了。

Number.isInteger() // false
Number.isInteger(null) // false
Number.isInteger('15') // false
Number.isInteger(true) // false

如果參數(shù)不是數(shù)值抚芦,Number.isInteger返回false倍谜。

2-5.Number.EPSILON

ES6 在Number對象上面迈螟,新增一個極小的常量Number.EPSILON。根據(jù)規(guī)格尔崔,它表示 1 與大于 1 的最小浮點數(shù)之間的差答毫。
對于 64 位浮點數(shù)來說,大于 1 的最小浮點數(shù)相當于二進制的1.00..001季春,小數(shù)點后面有連續(xù) 51 個零洗搂。這個值減去 1 之后,就等于 2 的 -52 次方载弄。

Number.EPSILON === Math.pow(2, -52)
// true
Number.EPSILON
// 2.220446049250313e-16
Number.EPSILON.toFixed(20)
// "0.00000000000000022204"

Number.EPSILON實際上是 JavaScript 能夠表示的最小精度耘拇。誤差如果小于這個值,就可以認為已經(jīng)沒有意義了宇攻,即不存在誤差了惫叛。
引入一個這么小的量的目的,在于為浮點數(shù)計算逞刷,設置一個誤差范圍嘉涌。我們知道浮點數(shù)計算是不精確的。

function withinErrorMargin (left, right) {
  return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2);
}

0.1 + 0.2 === 0.3 // false
withinErrorMargin(0.1 + 0.2, 0.3) // true

1.1 + 1.3 === 2.4 // false
withinErrorMargin(1.1 + 1.3, 2.4) // true

2-6.安全整數(shù)和 Number.isSafeInteger()

JavaScript 能夠準確表示的整數(shù)范圍在-253到253之間(不含兩個端點)夸浅,超過這個范圍洛心,無法精確表示這個值。

Math.pow(2, 53) // 9007199254740992

9007199254740992  // 9007199254740992
9007199254740993  // 9007199254740992

Math.pow(2, 53) === Math.pow(2, 53) + 1
// true

實際使用這個函數(shù)時题篷,需要注意。驗證運算結果是否落在安全整數(shù)的范圍內(nèi)厅目,不要只驗證運算結果番枚,而要同時驗證參與運算的每個值。

Number.isSafeInteger(9007199254740993)
// false
Number.isSafeInteger(990)
// true
Number.isSafeInteger(9007199254740993 - 990)
// true
9007199254740993 - 990
// 返回結果 9007199254740002
// 正確答案應該是 9007199254740003
9007199254740993 === 9007199254740992
// true

上面代碼中损敷,9007199254740993不是一個安全整數(shù)葫笼,但是Number.isSafeInteger會返回結果,顯示計算結果是安全的拗馒。這是因為路星,這個數(shù)超出了精度范圍,導致在計算機內(nèi)部诱桂,以9007199254740992的形式儲存洋丐。
所以,如果只驗證運算結果是否為安全整數(shù)挥等,很可能得到錯誤結果友绝。下面的函數(shù)可以同時驗證兩個運算數(shù)和運算結果。

function trusty (left, right, result) {
  if (
    Number.isSafeInteger(left) &&
    Number.isSafeInteger(right) &&
    Number.isSafeInteger(result)
  ) {
    return result;
  }
  throw new RangeError('Operation cannot be trusted!');
}

trusty(9007199254740993, 990, 9007199254740993 - 990)
// RangeError: Operation cannot be trusted!

trusty(1, 2, 3)
// 3

2-7.Math.trunc()

Math.trunc方法用于去除一個數(shù)的小數(shù)部分肝劲,返回整數(shù)部分迁客。

Math.trunc(4.1) // 4
Math.trunc(4.9) // 4
Math.trunc(-4.1) // -4
Math.trunc(-4.9) // -4
Math.trunc(-0.1234) // -0

對于非數(shù)值郭宝,Math.trunc內(nèi)部使用Number方法將其先轉為數(shù)值。

Math.trunc('123.456') // 123
Math.trunc(true) //1
Math.trunc(false) // 0
Math.trunc(null) // 0

對于空值和無法截取整數(shù)的值掷漱,返回NaN粘室。

Math.trunc(NaN);      // NaN
Math.trunc('foo');    // NaN
Math.trunc();         // NaN
Math.trunc(undefined) // NaN

值得注意的是與Math.floor方法并不相同,當參數(shù)值小于0時,其表現(xiàn)與Math.ceil一致

Math.trunc(-1.6) //-1
Math.floor(-1.6); //-2
Math.ceil(-1.6)  // -1

2-8.Math.sign()

Math.sign方法用來判斷一個數(shù)到底是正數(shù)卜范、負數(shù)衔统、還是零。對于非數(shù)值先朦,會先將其轉換為數(shù)值缰冤。

它會返回五種值。

  • 參數(shù)為正數(shù)喳魏,返回+1棉浸;
  • 參數(shù)為負數(shù),返回-1刺彩;
  • 參數(shù)為 0迷郑,返回0;
  • 參數(shù)為-0创倔,返回-0;
  • 其他值嗡害,返回NaN。

如果參數(shù)是非數(shù)值畦攘,會自動轉為數(shù)值霸妹。對于那些無法轉為數(shù)值的值,會返回NaN知押。

Math.sign('')  // 0
Math.sign(true)  // +1
Math.sign(false)  // 0
Math.sign(null)  // 0
Math.sign('9')  // +1
Math.sign('foo')  // NaN
Math.sign()  // NaN
Math.sign(undefined)  // NaN

2-9.Math.cbrt()

Math.cbrt()方法用于計算一個數(shù)的立方根叹螟。對于非數(shù)值,Math.cbrt()方法內(nèi)部也是先使用Number()方法將其轉為數(shù)值台盯。

Math.cbrt(-1) // -1
Math.cbrt(0)  // 0
Math.cbrt(1)  // 1
Math.cbrt(2)  // 1.2599210498948732
Math.cbrt('8') // 2
Math.cbrt('hello') // NaN

2-10.Math.clz32()

Math.clz32()方法將參數(shù)轉為 32 位無符號整數(shù)的形式罢绽,然后返回這個 32 位值里面有多少個前導 0。

Math.clz32(0) // 32
Math.clz32(1) // 31
Math.clz32(1000) // 22
Math.clz32(0b01000000000000000000000000000000) // 1
Math.clz32(0b00100000000000000000000000000000) // 2

左移運算符(<<)與Math.clz32方法直接相關静盅。

Math.clz32(0) // 32
Math.clz32(1) // 31
Math.clz32(1 << 1) // 30
Math.clz32(1 << 2) // 29
Math.clz32(1 << 29) // 2

對于小數(shù)良价,Math.clz32方法只考慮整數(shù)部分。對于空值或其他類型的值蒿叠,Math.clz32方法會將它們先轉為數(shù)值明垢,然后再計算。

Math.clz32(3.2) // 30
Math.clz32(3.9) // 30

Math.clz32() // 32
Math.clz32(NaN) // 32
Math.clz32(Infinity) // 32
Math.clz32(null) // 32
Math.clz32('foo') // 32
Math.clz32([]) // 32
Math.clz32({}) // 32
Math.clz32(true) // 31

2-11.Math.imul()

Math.imul方法返回兩個數(shù)以 32 位帶符號整數(shù)形式相乘的結果栈虚,返回的也是一個 32 位的帶符號整數(shù)袖外。

Math.imul(2, 4)   // 8
Math.imul(-1, 8)  // -8
Math.imul(-2, -2) // 4

如果只考慮最后 32 位,大多數(shù)情況下魂务,Math.imul(a, b)與a * b的結果是相同的曼验,即該方法等同于(a * b)|0的效果(超過 32 位的部分溢出)泌射。之所以需要部署這個方法,是因為 JavaScript 有精度限制鬓照,超過 2 的 53 次方的值無法精確表示熔酷。這就是說,對于那些很大的數(shù)的乘法豺裆,低位數(shù)值往往都是不精確的拒秘,Math.imul方法可以返回正確的低位數(shù)值。

(0x7fffffff * 0x7fffffff)|0 // 0
Math.imul(0x7fffffff, 0x7fffffff) // 1

上面這個乘法算式臭猜,返回結果為 0躺酒。但是由于這兩個二進制數(shù)的最低位都是 1,所以這個結果肯定是不正確的蔑歌,因為根據(jù)二進制乘法羹应,計算結果的二進制最低位應該也是 1。這個錯誤就是因為它們的乘積超過了 2 的 53 次方次屠,JavaScript 無法保存額外的精度园匹,就把低位的值都變成了 0。Math.imul方法可以返回正確的值 1劫灶。

2-12.Math.fround()

Math.fround方法返回一個數(shù)的32位單精度浮點數(shù)形式裸违。

對于32位單精度格式來說,數(shù)值精度是24個二進制位(1 位隱藏位與 23 位有效位)本昏,所以對于 -224 至 224 之間的整數(shù)(不含兩個端點)供汛,返回結果與參數(shù)本身一致。

Math.fround(0)   // 0
Math.fround(1)   // 1
Math.fround(2 ** 24 - 1)   // 16777215

如果參數(shù)的絕對值大于 224涌穆,返回的結果便開始丟失精度紊馏。

Math.fround(2 ** 24)       // 16777216
Math.fround(2 ** 24 + 1)   // 16777216

Math.fround方法的主要作用,是將64位雙精度浮點數(shù)轉為32位單精度浮點數(shù)蒲犬。如果小數(shù)的精度超過24個二進制位,返回值就會不同于原值岸啡,否則返回值不變(即與64位雙精度值一致)原叮。

// 未丟失有效精度
Math.fround(1.125) // 1.125
Math.fround(7.25)  // 7.25

// 丟失精度
Math.fround(0.3)   // 0.30000001192092896
Math.fround(0.7)   // 0.699999988079071
Math.fround(1.0000000123) // 1

對于 NaN 和 Infinity,此方法返回原值巡蘸。對于其它類型的非數(shù)值奋隶,Math.fround 方法會先將其轉為數(shù)值,再返回單精度浮點數(shù)悦荒。

Math.fround(NaN)      // NaN
Math.fround(Infinity) // Infinity

Math.fround('5')      // 5
Math.fround(true)     // 1
Math.fround(null)     // 0
Math.fround([])       // 0
Math.fround({})       // NaN

2-13.Math.hypot()

Math.hypot方法返回所有參數(shù)的平方和的平方根唯欣。
如果參數(shù)不是數(shù)值,Math.hypot方法會將其轉為數(shù)值搬味。只要有一個參數(shù)無法轉為數(shù)值境氢,就會返回 NaN蟀拷。

Math.hypot(3, 4);        // 5
Math.hypot(3, 4, 5);     // 7.0710678118654755
Math.hypot();            // 0
Math.hypot(NaN);         // NaN
Math.hypot(3, 4, 'foo'); // NaN
Math.hypot(3, 4, '5');   // 7.0710678118654755
Math.hypot(-3);          // 3

3.對數(shù)方法

3-1.Math.expm1()

Math.expm1(x)返回 ex - 1,即Math.exp(x) - 1萍聊。

Math.expm1(-1) // -0.6321205588285577
Math.expm1(0)  // 0
Math.expm1(1)  // 1.718281828459045

3-2.Math.log1p()

Math.log1p(x)方法返回1 + x的自然對數(shù)问芬,即Math.log(1 + x)。如果x小于-1寿桨,返回NaN此衅。

Math.log1p(1)  // 0.6931471805599453
Math.log1p(0)  // 0
Math.log1p(-1) // -Infinity
Math.log1p(-2) // NaN

3-3.Math.log10()

Math.log10(x)返回以 10 為底的x的對數(shù)。如果x小于 0亭螟,則返回 NaN挡鞍。

Math.log10(2)      // 0.3010299956639812
Math.log10(1)      // 0
Math.log10(0)      // -Infinity
Math.log10(-2)     // NaN
Math.log10(100000) // 5

3-4.Math.log2()

Math.log2(x)返回以 2 為底的x的對數(shù)。如果x小于 0预烙,則返回 NaN墨微。

Math.log2(3)       // 1.584962500721156
Math.log2(2)       // 1
Math.log2(1)       // 0
Math.log2(0)       // -Infinity
Math.log2(-2)      // NaN
Math.log2(1024)    // 10
Math.log2(1 << 29) // 29

雙曲函數(shù)方法

ES6 新增了 6 個雙曲函數(shù)方法。

  • Math.sinh(x) 返回x的雙曲正弦(hyperbolic sine)
  • Math.cosh(x) 返回x的雙曲余弦(hyperbolic cosine)
  • Math.tanh(x) 返回x的雙曲正切(hyperbolic tangent)
  • Math.asinh(x) 返回x的反雙曲正弦(inverse hyperbolic sine)
  • Math.acosh(x) 返回x的反雙曲余弦(inverse hyperbolic cosine)
  • Math.atanh(x) 返回x的反雙曲正切(inverse hyperbolic tangent)

4.指數(shù)運算符

ES2016 新增了一個指數(shù)運算符(**)默伍。

2 ** 2 // 4
2 ** 3 // 8

這個運算符的一個特點是右結合欢嘿,而不是常見的左結合。多個指數(shù)運算符連用時也糊,是從最右邊開始計算的炼蹦。

// 相當于 2 ** (3 ** 2)
2 ** 3 ** 2
// 512

指數(shù)運算符可以與等號結合,形成一個新的賦值運算符(**=)狸剃。

let a = 1.5;
a **= 2;
// 等同于 a = a * a;

let b = 4;
b **= 3;
// 等同于 b = b * b * b;

5.BigInt 數(shù)據(jù)類型

JavaScript 所有數(shù)字都保存成 64 位浮點數(shù)掐隐,這給數(shù)值的表示帶來了兩大限制。一是數(shù)值的精度只能到 53 個二進制位(相當于 16 個十進制位)钞馁,大于這個范圍的整數(shù)虑省,JavaScript 是無法精確表示的,這使得 JavaScript 不適合進行科學和金融方面的精確計算僧凰。二是大于或等于2的1024次方的數(shù)值探颈,JavaScript 無法表示,會返回Infinity训措。

// 超過 53 個二進制位的數(shù)值伪节,無法保持精度
Math.pow(2, 53) === Math.pow(2, 53) + 1 // true

// 超過 2 的 1024 次方的數(shù)值,無法表示
Math.pow(2, 1024) // Infinity

ES2020 引入了一種新的數(shù)據(jù)類型 BigInt(大整數(shù))绩鸣,來解決這個問題怀大,這是 ECMAScript 的第八種數(shù)據(jù)類型。BigInt 只用來表示整數(shù)呀闻,沒有位數(shù)的限制化借,任何位數(shù)的整數(shù)都可以精確表示。

const a = 2172141653n;
const b = 15346349309n;

// BigInt 可以保持精度
a * b // 33334444555566667777n

// 普通整數(shù)無法保持精度
Number(a) * Number(b) // 33334444555566670000

為了與 Number 類型區(qū)別捡多,BigInt 類型的數(shù)據(jù)必須添加后綴n蓖康。
BigInt 同樣可以使用各種進制表示铐炫,都要加上后綴n。

1234 // 普通整數(shù)
1234n // BigInt
typeof 123n // 'bigint'

// BigInt 的運算
1n + 2n // 3n

0b1101n // 二進制
0o777n // 八進制
0xFFn // 十六進制

BigInt 與普通整數(shù)是兩種值钓瞭,它們之間并不相等驳遵。也無法用BigInt與普通整數(shù)進行運算

42n === 42 // false
123n-1 //Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions

BigInt 可以使用負號(-),但是不能使用正號(+)山涡,因為會與 asm.js 沖突堤结。

-42n // 正確
+42n // 報錯

5-1.BigInt 對象

JavaScript 原生提供BigInt對象,可以用作構造函數(shù)生成 BigInt 類型的數(shù)值鸭丛。轉換規(guī)則基本與Number()一致竞穷,將其他類型的值轉為 BigInt。
BigInt()構造函數(shù)必須有參數(shù)鳞溉,而且參數(shù)必須可以正常轉為數(shù)值瘾带,下面的用法都會報錯。參數(shù)如果是小數(shù)熟菲,也會報錯看政。

BigInt(123) // 123n
BigInt('123') // 123n
BigInt(false) // 0n
BigInt(true) // 1n

new BigInt() // TypeError
BigInt(undefined) //TypeError
BigInt(null) // TypeError
BigInt('123n') // SyntaxError
BigInt('abc') // SyntaxError

BigInt(1.5) // RangeError
BigInt('1.5') // SyntaxError

上面代碼中,尤其值得注意字符串123n無法解析成 Number 類型抄罕,所以會報錯允蚣。
BigInt 對象繼承了 Object 對象的兩個實例方法。

  • BigInt.prototype.toString()
  • BigInt.prototype.valueOf()

它還繼承了 Number 對象的一個實例方法呆贿。

  • BigInt.prototype.toLocaleString()

此外嚷兔,還提供了三個靜態(tài)方法。

  • BigInt.asUintN(width, BigInt): 給定的 BigInt 轉為 0 到 2width - 1 之間對應的值做入。
  • BigInt.asIntN(width, BigInt):給定的 BigInt 轉為 -2width - 1 到 2width - 1 - 1 之間對應的值冒晰。
  • BigInt.parseInt(string[, radix]):近似于Number.parseInt(),將一個字符串轉換成指定進制的 BigInt竟块。
const max = 2n ** (64n - 1n) - 1n;

BigInt.asIntN(64, max)
// 9223372036854775807n
BigInt.asIntN(64, max + 1n)
// -9223372036854775808n
BigInt.asUintN(64, max + 1n)
// 9223372036854775808n

上面代碼中壶运,max是64位帶符號的 BigInt 所能表示的最大值。如果對這個值加1n浪秘,BigInt.asIntN()將會返回一個負值前弯,因為這時新增的一位將被解釋為符號位。而BigInt.asUintN()方法由于不存在符號位秫逝,所以可以正確返回結果。

如果BigInt.asIntN()和BigInt.asUintN()指定的位數(shù)询枚,小于數(shù)值本身的位數(shù)违帆,那么頭部的位將被舍棄。

const max = 2n ** (64n - 1n) - 1n;

BigInt.asIntN(32, max) // -1n
BigInt.asUintN(32, max) // 4294967295n

上面代碼中金蜀,max是一個64位的 BigInt刷后,如果轉為32位的畴,前面的32位都會被舍棄。

下面是BigInt.parseInt()的例子尝胆。

// Number.parseInt() 與 BigInt.parseInt() 的對比
Number.parseInt('9007199254740993', 10)
// 9007199254740992
BigInt.parseInt('9007199254740993', 10)
// 9007199254740993n

上面代碼中丧裁,由于有效數(shù)字超出了最大限度,Number.parseInt方法返回的結果是不精確的含衔,而BigInt.parseInt方法正確返回了對應的 BigInt煎娇。

對于二進制數(shù)組,BigInt 新增了兩個類型BigUint64Array和BigInt64Array贪染,這兩種數(shù)據(jù)類型返回的都是64位 BigInt缓呛。DataView對象的實例方法DataView.prototype.getBigInt64()和DataView.prototype.getBigUint64(),返回的也是 BigInt杭隙。

5-2.轉換規(guī)則

可以使用Boolean()哟绊、Number()和String()這三個方法,將 BigInt 可以轉為布爾值痰憎、數(shù)值和字符串類型票髓。
另外,取反運算符(!)也可以將 BigInt 轉為布爾值铣耘。

Boolean(0n) // false
Boolean(1n) // true
Number(1n)  // 1
String(1n)  // "1"

!0n // true
!1n // false

上面代碼中洽沟,注意最后一個例子,轉為字符串時后綴n會消失涡拘。

5-3.數(shù)學運算

數(shù)學運算方面玲躯,BigInt 類型的+、-鳄乏、*這四個二元運算符跷车,與 Number 類型的行為一致。除法運算/會舍去小數(shù)部分橱野,返回一個整數(shù)朽缴。

9n / 5n
// 1n

幾乎所有的數(shù)值運算符都可以用在 BigInt,但是有兩個例外水援。

  • 不帶符號的右移位運算符>>>
  • 一元的求正運算符+

上面兩個運算符用在 BigInt 會報錯密强。前者是因為>>>運算符是不帶符號的,但是 BigInt 總是帶有符號的蜗元,導致該運算無意義或渤,完全等同于右移運算符>>。后者是因為一元運算符+在 asm.js 里面總是返回 Number 類型奕扣,為了不破壞 asm.js 就規(guī)定+1n會報錯薪鹦。

BigInt 不能與普通數(shù)值進行混合運算。

1n + 1.3 // 報錯

上面代碼報錯是因為無論返回的是 BigInt 或 Number,都會導致丟失精度信息池磁。比如(2n**53n + 1n) + 0.5這個表達式奔害,如果返回 BigInt 類型,0.5這個小數(shù)部分會丟失地熄;如果返回 Number 類型华临,有效精度只能保持 53 位,導致精度下降端考。

同樣的原因雅潭,如果一個標準庫函數(shù)的參數(shù)預期是 Number 類型,但是得到的是一個 BigInt跛梗,就會報錯寻馏。

// 錯誤的寫法
Math.sqrt(4n) // 報錯

// 正確的寫法
Math.sqrt(Number(4n)) // 2

上面代碼中,Math.sqrt的參數(shù)預期是 Number 類型核偿,如果是 BigInt 就會報錯诚欠,必須先用Number方法轉一下類型,才能進行計算漾岳。

asm.js 里面轰绵,|0跟在一個數(shù)值的后面會返回一個32位整數(shù)。根據(jù)不能與 Number 類型混合運算的規(guī)則尼荆,BigInt 如果與|0進行運算會報錯左腔。

1n | 0 // 報錯

5-4.其他運算

BigInt 對應的布爾值,與 Number 類型一致捅儒,即0n會轉為false液样,其他值轉為true。

if (0n) {
  console.log('if');
} else {
  console.log('else');
}
// else

上面代碼中巧还,0n對應false鞭莽,所以會進入else子句。

比較運算符(比如>)和相等運算符(==)允許 BigInt 與其他類型的值混合計算麸祷,因為這樣做不會損失精度澎怒。

0n < 1 // true
0n < true // true
0n == 0 // true
0n == false // true
0n === 0 // false

BigInt 與字符串混合運算時,會先轉為字符串阶牍,再進行運算喷面。

'' + 123n // "123"

ES6參考鏈接https://es6.ruanyifeng.com/#docs/intro

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市走孽,隨后出現(xiàn)的幾起案子惧辈,更是在濱河造成了極大的恐慌,老刑警劉巖磕瓷,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盒齿,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機县昂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陷舅,“玉大人倒彰,你說我怎么就攤上這事±痴觯” “怎么了待讳?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長仰剿。 經(jīng)常有香客問我创淡,道長,這世上最難降的妖魔是什么南吮? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任琳彩,我火速辦了婚禮,結果婚禮上部凑,老公的妹妹穿的比我還像新娘露乏。我一直安慰自己,他們只是感情好涂邀,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布瘟仿。 她就那樣靜靜地躺著,像睡著了一般比勉。 火紅的嫁衣襯著肌膚如雪劳较。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天浩聋,我揣著相機與錄音观蜗,去河邊找鬼。 笑死赡勘,一個胖子當著我的面吹牛嫂便,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闸与,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼毙替,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了践樱?” 一聲冷哼從身側響起厂画,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎拷邢,沒想到半個月后袱院,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年忽洛,在試婚紗的時候發(fā)現(xiàn)自己被綠了腻惠。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡欲虚,死狀恐怖集灌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情复哆,我是刑警寧澤欣喧,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站梯找,受9級特大地震影響唆阿,放射性物質發(fā)生泄漏。R本人自食惡果不足惜锈锤,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一驯鳖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧牙咏,春花似錦臼隔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至丁寄,卻和暖如春氨淌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伊磺。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工盛正, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人屑埋。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓豪筝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親摘能。 傳聞我的和親對象是個殘疾皇子续崖,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容