溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

es6新增的js基本數(shù)據(jù)類型怎么用

發(fā)布時(shí)間:2022-10-18 09:39:05 來源:億速云 閱讀:181 作者:iii 欄目:web開發(fā)

這篇“es6新增的js基本數(shù)據(jù)類型怎么用”文章的知識點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“es6新增的js基本數(shù)據(jù)類型怎么用”文章吧。

es6新增的基本數(shù)據(jù)類型:1、Symbol類型,表示獨(dú)一無二的值,即Symbol實(shí)例是唯一、不可變的;它的產(chǎn)生是因?yàn)橐脕砦ㄒ坏臉?biāo)記,進(jìn)而用作非字符串形式的對象屬性,是確保對象屬性使用唯一標(biāo)識符,不會發(fā)生屬性沖突的危險(xiǎn)。2、BigInt類型,提供對任意長度整數(shù)的支持,主要是為了表達(dá)大于“2^53-1”的整數(shù)。

本教程操作環(huán)境:windows7系統(tǒng)、ECMAScript 6版、Dell G3電腦。

基本數(shù)據(jù)類型 也稱為原始數(shù)據(jù)類型,包括String、Number、Boolean、undefined、null、Symbol、BigInt,其中SymbolBigInt為ES6新增。

Symbol 類型

Symbol 是 ECMAScript6 中引入的一種新的數(shù)據(jù)類型,表示獨(dú)一無二的值。Symbol 是原始值(基礎(chǔ)數(shù)據(jù)類型),且 Symbol 實(shí)例是唯一、不可變的。它的產(chǎn)生是因?yàn)橐脕砦ㄒ坏臉?biāo)記,進(jìn)而用作非字符串形式的對象屬性,是確保對象屬性使用唯一標(biāo)識符,不會發(fā)生屬性沖突的危險(xiǎn)。

在 ES6 之前,對象的鍵只能是字符串類型,但是這樣有個(gè)問題,就是會造成鍵名命名沖突,后者覆蓋前者,這個(gè)時(shí)候就需要一個(gè)唯一值來充當(dāng)鍵名,Symbol 橫空出世。

1、概念

symbol 是一種基本數(shù)據(jù)類型,Symbol()函數(shù)會返回 symbol 類型的值,該類型具有靜態(tài)屬性和靜態(tài)方法。但是它不是構(gòu)造函數(shù),不能用 new Symbol()來創(chuàng)建。

let symbol = Symbol();
typeof symbol; // "symbol"

Symbol 作為對象屬性時(shí),當(dāng)在對象內(nèi)部時(shí),必須要用方括號括起來,不用方括號括起來代表的是字符串。

let s = Symbol();
let obj = {
  [s]: "Jack",
};
obj[s]; // "Jack"
obj.s; // undefined

而且當(dāng)要取該屬性的值時(shí),不能用點(diǎn)運(yùn)算符,因?yàn)辄c(diǎn)運(yùn)算符后面同樣是字符串類型。

創(chuàng)建 Symbol 數(shù)據(jù)類型時(shí),都是 Symbol()這么創(chuàng)建的,當(dāng)打印出來時(shí),都為 Symbol(),這樣很難區(qū)別各個(gè) Symbol 類型的變量是什么意思。所以在 Symbol 函數(shù)內(nèi)可以接收一個(gè)字符串的參數(shù),表示該定義 Symbol 類型變量的描述。

let s1 = Symbol("a");
console.log(s1); // Symbol(a)
s1.toString(); // "Symbol(a)"

如果 Symbol 類型接收的一個(gè)對象類型的話,那就會先調(diào)用其內(nèi)部的 toString 方法,將其變?yōu)橐粋€(gè)字符串,然后才生成一個(gè) Symbol 值。

let arr = [1, 2, 3];
let s1 = Symbol(arr);
console.log(s1); // Symbol(1,2,3)
let obj = {
  toString: () => "abc",
};
let s2 = Symbol(obj);
console.log(s2); // Symbol(abc)

Symbol 類型的變量是不能和其他變量參與運(yùn)算的,而且其只能轉(zhuǎn)為 String 類型和 Boolean 類型。

let s = Symbol();
console.log("1" + s); // TypeError: Cannot convert a Symbol value to a string
s.toString(); // "Symbol()"
Boolean(s); // true
Number(s); // TypeError: Cannot convert a Symbol value to a number

2、Symbol.prototype.description

當(dāng)給 Symbol 添加描述時(shí),可以通過 Symbol.prototype.description 來獲取該描述。

let s = Symbol("Jack");
s.description; // 'Jack'

3、Symbol.for(key)和 Symbol.keyFor(sym)

最開始看到這兩個(gè)方法時(shí),我以為是兩個(gè)遍歷的方法。

  • Symbol.for(key):使用給定的 key 搜索現(xiàn)有的 symbol,如果找到則返回該 symbol。否則將使用給定的 key 在全局 symbol 注冊表中創(chuàng)建一個(gè)新的 symbol。

  • Symbol.keyFor(sym):從全局 symbol 注冊表中,為給定的 symbol 檢索一個(gè) key。

let s1 = Symbol.for("foo");
let s2 = Symbol.for("foo");
s1 === s2; // true

Symbol.for 會搜索有沒有以該參數(shù)作為名稱的 Symbol 值。如果有,就返回這個(gè) Symbol 值,否則就新建一個(gè)以該字符串為名稱的 Symbol 值,并將其注冊到全局。所以由其創(chuàng)建的兩個(gè)相同描述的值會相等。這種創(chuàng)建就和普通的 Symbol()有著截然不同的結(jié)果了:

let s1 = Symbol("foo");
let s2 = Symbol("foo");
s1 === s2; // false

因?yàn)椴还茉鯓?Symbol()返回的都是一個(gè)全新的值,換句話說 Symbol()生成的值沒有注冊在全局中,所以返回的值都是全新的,而 Symbol.for()會在先在全局中查找,有就返回這個(gè)值,沒有則創(chuàng)建新的值,但新的值也是掛載在全局中的。

Symbol.keyFor(sym)是在全局中查找是否有該 Symbol 值,有則返回該描述。

let s1 = Symbol.for("Jack");
Symbol.keyFor(s1); // 'Jack'
let s2 = Symbol("Rose");
Symbol.keyFor(s2); // undefined

因?yàn)?s2 沒有掛載在全局中,所以 Symbol.keyFor()找不到它,故返回 undefined。

4、內(nèi)置的 Symbol 屬性

除了定義自己使用的 Symbol 值以外,ES6 還提供了 13(有可能今后會更多 ?) 個(gè)內(nèi)置的 Symbol 值,指向語言內(nèi)部使用的方法。

4.1 Symbol.asyncIterator

Symbol.asyncIterator 符號指定了一個(gè)對象的默認(rèn)異步迭代器。如果一個(gè)對象設(shè)置了這個(gè)屬性,它就是異步可迭代對象,可用于 for await...of 循環(huán)。換句話說一個(gè)異步可迭代對象內(nèi)部必須有 Symbol.asyncIterator 屬性。

const myAsyncIterable = new Object();
myAsyncIterable[Symbol.asyncIterator] = async function* () {
  yield "hello";
  yield "async";
  yield "iteration!";
};

(async () => {
  for await (const x of myAsyncIterable) {
    console.log(x);
    // expected output:
    //    "hello"
    //    "async"
    //    "iteration!"
  }
})();

當(dāng)執(zhí)行 for await...of 時(shí),就會執(zhí)行該變量中 Symbol.asyncIterator 屬性值。

4.2、Symbol.hasInstance

Symbol.hasInstance 用于判斷某對象是否為某構(gòu)造器的實(shí)例。因此你可以用它自定義 instanceof 操作符在某個(gè)類上的行為。換句話說當(dāng)判斷一個(gè)實(shí)例是否為一個(gè)類的實(shí)例時(shí),其實(shí)就是執(zhí)行該類里面的 Symbol.hasInstance 屬性。

class Fu {
  [Symbol.hasInstance](num) {
    return num === 1;
  }
}
1 instanceof new Fu(); // true
2 instanceof new Fu(); // false

4.3、Symbol.isConcatSpreadable

內(nèi)置的 Symbol.isConcatSpreadable 符號用于配置某對象作為 Array.prototype.concat()方法的參數(shù)時(shí)是否展開其數(shù)組元素。

// 默認(rèn)情況下
let arr = [1, 2, 3];
let brr = [4, 5, 6];
arr.concat(brr); // [1, 2, 3, 4, 5, 6]
// 設(shè)置了Symbol.isConcatSpreadable后
let arr = [1, 2, 3];
let brr = [4, 5, 6];
brr[Symbol.isConcatSpreadable] = false;
arr.concat(brr); // [1, 2, 3, [4, 5, 6]]

將數(shù)組的 Symbol.isConcatSpreadable 屬性設(shè)置為 false 后,使用 concat 方法時(shí)該數(shù)據(jù)就不會展開。

對于類數(shù)組而言,默認(rèn)數(shù)組使用 concat 方法該類數(shù)組是不展開的,我們可以給類數(shù)組的 Symbol.isConcatSpreadable 設(shè)置為 true,這樣就可以展開了,并且完成了類數(shù)組轉(zhuǎn)換為數(shù)組,這樣類數(shù)組轉(zhuǎn)數(shù)組又多了一個(gè)方法。

// 默認(rèn)情況下
function foo(x, y) {
  let arr = [].concat(arguments);
  console.log(arr); //[Arguments(2)]
}
foo(1, 2);
// 設(shè)置了Symbol.isConcatSpreadable為true后
function foo(x, y) {
  arguments[Symbol.isConcatSpreadable] = true;
  let arr = [].concat(arguments);
  console.log(arr); //[1, 2]
}
foo(1, 2);

4.4、Symbol.iterator

Symbol.iterator 為每一個(gè)對象定義了默認(rèn)的迭代器。該迭代器可以被 for...of 循環(huán)使用。

const myIterable = {};
myIterable[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};

[...myIterable]; // [1, 2, 3]

對象進(jìn)行 for...of 循環(huán)時(shí),會調(diào)用 Symbol.iterator 方法,

4.5、Symbol.match

Symbol.match 指定了匹配的是正則表達(dá)式而不是字符串。String.prototype.match() 方法會調(diào)用此函數(shù)。換句話說就是當(dāng) str.match()執(zhí)行時(shí)如果該屬性存在,就會返回該方法的返回值。

class foo {
  [Symbol.match](string) {
    return string;
  }
}
"Jack".match(new foo()); // 'Jack'

除上述之外,MDN 還提出了該屬性另外一個(gè)功能:此函數(shù)還用于標(biāo)識對象是否具有正則表達(dá)式的行為。比如, String.prototype.startsWith(),String.prototype.endsWith() 和 String.prototype.includes() 這些方法會檢查其第一個(gè)參數(shù)是否是正則表達(dá)式,是正則表達(dá)式就拋出一個(gè) TypeError?,F(xiàn)在,如果 match symbol 設(shè)置為 false(或者一個(gè) 假值),就表示該對象不打算用作正則表達(dá)式對象。

"/bar/".startsWith(/bar/); // TypeError: First argument to String.prototype.startsWith must not be a regular expression
// 當(dāng)設(shè)置為false之后
var re = /foo/;
re[Symbol.match] = false;
"/foo/".startsWith(re); // true
"/baz/".endsWith(re); // false

4.6、Symbol.matchAll

Symbol.matchAll 返回一個(gè)迭代器,該迭代器根據(jù)字符串生成正則表達(dá)式的匹配項(xiàng)。此函數(shù)可以被 String.prototype.matchAll() 方法調(diào)用。

"abc".matchAll(/a/);
// 等價(jià)于
/a/[Symbol.matchAll]("abc");

4.7、Symbol.replace

Symbol.replace 這個(gè)屬性指定了當(dāng)一個(gè)字符串替換所匹配字符串時(shí)所調(diào)用的方法。String.prototype.replace() 方法會調(diào)用此方法。

String.prototype.replace(searchValue, replaceValue);
// 等同于
searchValue[Symbol.replace](this, replaceValue);
// 例子
class Replace1 {
  constructor(value) {
    this.value = value;
  }
  [Symbol.replace](string) {
    return `s/${string}/${this.value}/g`;
  }
}

console.log("foo".replace(new Replace1("bar"))); // "s/foo/bar/g"

4.8、Symbol.search

Symbol.search 指定了一個(gè)搜索方法,這個(gè)方法接受用戶輸入的正則表達(dá)式,返回該正則表達(dá)式在字符串中匹配到的下標(biāo),這個(gè)方法由以下的方法來調(diào)用 String.prototype.search()。

String.prototype.search(regexp);
// 等價(jià)于
regexp[Symbol.search](this);
// 例子
class Search2 {
  [Symbol.search](str) {
    return `${str} Word`;
  }
}
"Hello".search(new Search2()); // Hello Word

4.9、Symbol.species

Symbol.species 是個(gè)函數(shù)值屬性,其被構(gòu)造函數(shù)用以創(chuàng)建派生對象,換句話說 species 訪問器屬性允許子類覆蓋對象的默認(rèn)構(gòu)造函數(shù)。

我們舉個(gè)例子:

// 默認(rèn)情況下
class MyArray extends Array {}
let arr = new MyArray(1, 2, 3);
let brr = arr.map((item) => item);
brr instanceof MyArray; // true
brr instanceof Array; // true

類 MyArray 繼承于 Array,arr 為 MyArray 的實(shí)例,brr 為 arr 的衍生物,所以 brr 是 MyArray 的實(shí)例,并且由于原型鏈的緣故,brr 也是 Array 的實(shí)例。如果此時(shí),我們只想讓 brr 為 Array 的實(shí)例,那 Symbol.species 屬性值就派上用場了。

class MyArray extends Array {
  static get [Symbol.species]() {
    return Array;
  }
}
let arr = new MyArray(1, 2, 3);
let brr = arr.map((item) => item);
brr instanceof MyArray; // false
brr instanceof Array; // true
// 默認(rèn)情況下
class MyArray extends Array {
  static get [Symbol.species]() {
    return this;
  }
}

值得注意的是,定義 Symbol.species 屬性時(shí),前面必須聲明是靜態(tài)的 static 并且要運(yùn)用 get 取值器。

4.10、Symbol.split

Symbol.split 指向 一個(gè)正則表達(dá)式的索引處分割字符串的方法。 這個(gè)方法通過 String.prototype.split() 調(diào)用。

String.prototype.split(separator, limit);
// 等價(jià)于
separator[Symbol.split](this, limit);
// 例子
class Split1 {
  [Symbol.split](str) {
    return `${str} Word`;
  }
}
"Hello".split(new Split1()); // Hello Word

4.11、Symbol.toPrimitive

Symbol.toPrimitive 是一個(gè)內(nèi)置的 Symbol 值,它是作為對象的函數(shù)值屬性存在的,當(dāng)一個(gè)對象轉(zhuǎn)換為對應(yīng)的原始值時(shí),會調(diào)用此函數(shù)。該函數(shù)在調(diào)用時(shí),會傳遞一個(gè)字符串參數(shù) hint,表示要轉(zhuǎn)換到的原始值的預(yù)期類型。字符串 hint 的類型有三種:'number', 'string', 'default'。

let obj =
  {
    [Symbol.toPrimitive](hint) {
      switch (hint) {
        case "number":
          return 123;
        case "string":
          return "123";
        case "default":
          return "default";
        default:
          throw new Error();
      }
    },
  } + obj; // 123
`${obj}`; // '123'
obj + ""; // "default"

4.12、Symbol.toStringTag

Symbol.toStringTag 是一個(gè)內(nèi)置 symbol,它通常作為對象的屬性鍵使用,對應(yīng)的屬性值應(yīng)該為字符串類型,這個(gè)字符串用來表示該對象的自定義類型標(biāo)簽,通常只有內(nèi)置的 Object.prototype.toString() 方法會去讀取這個(gè)標(biāo)簽并把它包含在自己的返回值里。通俗點(diǎn)講就是在 Object.prototype.toString()去判斷自定義對象的數(shù)據(jù)類型時(shí),返回的都是 object,可以通過這個(gè)屬性來給自定義對象添加類型標(biāo)簽。

Object.prototype.toString.call('123'); // [object String]
...more

另外一些對象類型則不然,toString() 方法能識別它們是因?yàn)橐鏋樗鼈冊O(shè)置好了 toStringTag 標(biāo)簽:

Object.prototype.toString.call(new Map()); // "[object Map]"
Object.prototype.toString.call(function* () {}); // "[object GeneratorFunction]"
Object.prototype.toString.call(Promise.resolve()); // "[object Promise]"
...more

當(dāng)我們自己定義一個(gè)類時(shí),調(diào)用 Object.prototype.toString()時(shí),由于沒有內(nèi)部定義 toStringTag 標(biāo)簽,所以只能返回"[object Object]"

class Foo {}
Object.prototype.toString.call(new Foo()); // "[object Object]"
// 設(shè)置Symbol.toStringTag
class Foo {
  get [Symbol.toStringTag]() {
    return "Foo";
  }
}
Object.prototype.toString.call(new Foo()); // "[object Foo]"

4.13、Symbol.unscopabless

Symbol.unscopables 指用于指定對象值,其對象自身和繼承的從關(guān)聯(lián)對象的 with 環(huán)境綁定中排除的屬性名稱。說白了其屬性就是控制,在 with 詞法環(huán)境中哪些屬性會被 with 刪除。

Array.prototype[Symbol.unscopabless];
// {
//   copyWithin: true,
//   entries: true,
//   fill: true,
//   find: true,
//   findIndex: true,
//   includes: true,
//   keys: true
// }

這里簡單的講解一下 with 函數(shù),with 主要是用來對對象取值的,舉個(gè)簡單的例子:

let obj = {};
with (obj) {
  let newa = a;
  let newb = b;
  console.log(newa + newb);
}
// 等價(jià)于
let newa = obj.a;
let newb = obj.b;
console.log(newa + newb);

with 的 優(yōu)點(diǎn): 當(dāng) with 傳入的值非常復(fù)雜時(shí),即當(dāng) object 為非常復(fù)雜的嵌套結(jié)構(gòu)時(shí),with 就使得代碼顯得非常簡潔。 with 的缺點(diǎn): js 的編譯器會檢測 with 塊中的變量是否屬于 with 傳入的對象, 上述例子為例,js 會檢測 a 和 b 是否屬于 obj 對象,這樣就會的導(dǎo)致 with 語句的執(zhí)行速度大大下降,性能比較差。

回歸正題,我們舉個(gè)例子看一下 Symbol.unscopables 屬性的作用。

let obj = {
  foo() {
    return 1;
  }
}
with(obj) {
  foo(); // 1
}
// 設(shè)置了Symbol.unscopables
let obj = {
  foo() {
    return 1;
  },
  get [Symbol.unscopables]() {
    return {
      foo: true
    }
  }
}
with(obj) {
  foo(); // Uncaught ReferenceError: foo is not defined
}

設(shè)置后報(bào)錯(cuò)的原因是因?yàn)閣ith已經(jīng)將obj中的foo方法刪除了。

BigInt類型

BigInt 是一種特殊的數(shù)字類型,它提供了對任意長度整數(shù)的支持。

1、概述

BigInt 是一個(gè)新型的內(nèi)置類型,主要是為了表達(dá)大于 2^53-1 的整數(shù)。

我們定義一個(gè) BigInt 類型的數(shù)據(jù)時(shí)有兩種方式,第一個(gè)是在數(shù)字后面加 n,另外一種是調(diào)用 BigInt()方法。

let theBigInt = 9007199254740991n;
let alsoHuge = BigInt(9007199254740991); // 9007199254740991n

當(dāng)用 typeof 對其進(jìn)行類型判斷時(shí),返回的是 bigint。

let theBigInt = 9007199254740991n;
typeof theBigInt; // bigint

2、運(yùn)算

BigInt 支持以下的運(yùn)算符,+、*-、**% ,并且支持除了>>> (無符號右移)之外的 其他位運(yùn)算符。

let previousMaxSafe = BigInt(Number.MAX_SAFE_INTEGER); // 9007199254740991n
let maxPlusOne = previousMaxSafe + 1n; // 9007199254740992n
let maxMinusOne = previousMaxSafe - 1n; // 9007199254740990n
let multi = previousMaxSafe * 2n; // 18014398509481982n
let mod = previousMaxSafe % 10n; // 1n

值得注意的是,BigInt 是不支持單目+運(yùn)算符的。

+previousMaxSafe; // Uncaught TypeError: Cannot convert a BigInt value to a number

主要原因還是 BigInt 無法和 Number 類型直接運(yùn)算,如果想要運(yùn)算的話必須在同一個(gè)類型上,但是有一點(diǎn)值得注意的是,當(dāng) BigInt 轉(zhuǎn)為 Number 類型時(shí),有可能會丟失精度。

在比較運(yùn)算符中,BigInt 和 Nunber 類型的之間不是嚴(yán)格相等的。

10n == 10; // true
10n === 10; // false

Number 和 BigInt 是可以進(jìn)行比較的。

1n < 2; // true
2n > 1; // true
2n >= 2; // true

3、API

BigInt 擁有兩個(gè)靜態(tài)方法:

  • BigInt.asIntN(width, bigint):將 BigInt 值轉(zhuǎn)換為一個(gè)-2^width-1 與 2^width-1-1 之間的有符號整數(shù)。

  • BigInt.asUintN(width, bigint):將一個(gè) BigInt 值轉(zhuǎn)換為 0 與 2^width-1 之間的無符號整數(shù)。

這兩個(gè)方法均接受兩個(gè)參數(shù),width:可存儲整數(shù)的位數(shù)。bigint:要存儲在指定位數(shù)上的整數(shù)。

const max = 2n ** (64n - 1n) - 1n;
BigInt.asIntN(64, max); // 9223372036854775807n

const max = 2n ** 64n - 1n;
BigInt.asUintN(64, max); // 18446744073709551615n

同時(shí) BigInt 還擁有三個(gè)實(shí)例方法:

  • BigInt.prototype.toLocaleString():返回此數(shù)字的 language-sensitive 形式的字符串。覆蓋 Object.prototype.toLocaleString() 方法。

  • BigInt.prototype.toString():返回以指定基數(shù)(base)表示指定數(shù)字的字符串。覆蓋 Object.prototype.toString() 方法。

  • BigInt.prototype.valueOf():返回指定對象的基元值。 覆蓋 Object.prototype.valueOf() 方法。

let bigint = 3500n;
bigint.toLocaleString(); // "3,500"
bigint.toString(); // "3500"
bigint.valueOf(); // 3500n

以上就是關(guān)于“es6新增的js基本數(shù)據(jù)類型怎么用”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI