es6新增的js基本資料型別有哪些

青灯夜游
發布: 2022-10-17 17:53:42
原創
2865 人瀏覽過

es6新增的基本資料類型:1、Symbol類型,表示獨一無二的值,即Symbol實例是唯一、不可變的;它的產生是因為要用來唯一的標記,進而用作非字串形式的物件屬性,是確保物件屬性使用唯一標識符,不會發生屬性衝突的危險。 2.BigInt類型,提供對任意長度整數的支持,主要是為了表達大於「2^53-1」的整數。

es6新增的js基本資料型別有哪些

本教學操作環境:windows7系統、ECMAScript 6版、Dell G3電腦。

基本資料類型 也稱為原始資料類型,包括String、Number、Boolean、undefined、null、Symbol、BigInt,其中Symbol#和BigInt 為ES6新增。

Symbol 類型

Symbol 是 ECMAScript6 中引入的一種新的資料類型,表示獨特的值。 Symbol 是原始值(基礎資料型別),且 Symbol 實例是唯一、不可變的。它的產生是因為要用來唯一的標記,進而用作非字串形式的物件屬性,是確保物件屬性使用唯一標識符,不會發生屬性衝突的危險。

在ES6 之前,物件的鍵只能是字串類型,但是這樣有個問題,就是會造成鍵名命名衝突,後者覆寫前者,這個時候就需要一個唯一值來充當鍵名,Symbol 橫空出世。

1、概念

#symbol 是一種基本資料類型,Symbol()函數會傳回symbol 類型的值,該類型具有靜態屬性和靜態方法。但是它不是建構函數,不能用 new Symbol()來創建。

let symbol = Symbol();
typeof symbol; // "symbol"
登入後複製

Symbol 作為物件屬性時,當在物件內部時,必須要用方括號括起來,不用方括號括起來代表的是字串。

let s = Symbol();
let obj = {
  [s]: "Jack",
};
obj[s]; // "Jack"
obj.s; // undefined
登入後複製

而且當要取該屬性的值時,不能用點運算符,因為點運算符後面同樣是字串類型。

建立 Symbol 資料型別時,都是 Symbol()這麼創建的​​,當列印出來時,都為 Symbol(),這樣很難區別各個 Symbol 類型的變數是什麼意思。所以在 Symbol 函數內可以接收一個字串的參數,表示該定義 Symbol 類型變數的描述。

let s1 = Symbol("a");
console.log(s1); // Symbol(a)
s1.toString(); // "Symbol(a)"
登入後複製

如果 Symbol 類型接收的一個物件類型的話,那就會先呼叫其內部的 toString 方法,將其變成一個字串,然後才產生一個 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 類型的變數是不能和其他變數參與運算的,而且只能轉為 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

##當給Symbol 新增描述時,可以透過Symbol.prototype.description 來取得該描述。

let s = Symbol("Jack");
s.description; // 'Jack'
登入後複製

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

我開始看到這兩個方法時,我以為是兩個遍歷的方法。

  • Symbol.for(key):使用給定的 key 搜尋現有的 symbol,如果找到則傳回該 symbol。否則將使用給定的 key 在全域 symbol 註冊表中建立一個新的 symbol。

  • Symbol.keyFor(sym):從全域 symbol 註冊表中,為給定的 symbol 擷取一個 key。

  • let s1 = Symbol.for("foo");
    let s2 = Symbol.for("foo");
    s1 === s2; // true
    登入後複製
Symbol.for 會搜尋有沒有以該參數作為名稱的 Symbol 值。如果有,就回傳這個 Symbol 值,否則就新建一個以該字串為名稱的 Symbol 值,並將其註冊到全域。所以由其創建的兩個相同描述的值會相等。這種創建就和普通的Symbol()有著截然不同的結果了:

let s1 = Symbol("foo");
let s2 = Symbol("foo");
s1 === s2; // false
登入後複製

因為不管怎樣Symbol()返回的都是一個全新的值,換句話說Symbol()產生的值沒有註冊在全域中,所以傳回的值都是全新的,而Symbol.for()會在先在全域中查找,有就回傳這個值,沒有則會建立新的值,但新的值也是掛載在全域中的。

Symbol.keyFor(sym)是在全域中尋找是否有該 Symbol 值,有則傳回該描述。

let s1 = Symbol.for("Jack");
Symbol.keyFor(s1); // 'Jack'
let s2 = Symbol("Rose");
Symbol.keyFor(s2); // undefined
登入後複製

因為 s2 沒有掛載在全域中,所以 Symbol.keyFor()找不到它,故回傳 undefined。

4、內建的 Symbol 屬性#

除了定义自己使用的 Symbol 值以外,ES6 还提供了 13(有可能今后会更多 ?) 个内置的 Symbol 值,指向语言内部使用的方法。

4.1 Symbol.asyncIterator

Symbol.asyncIterator 符号指定了一个对象的默认异步迭代器。如果一个对象设置了这个属性,它就是异步可迭代对象,可用于 for await...of 循环。换句话说一个异步可迭代对象内部必须有 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!"
  }
})();
登入後複製

当执行 for await...of 时,就会执行该变量中 Symbol.asyncIterator 属性值。

4.2、Symbol.hasInstance

Symbol.hasInstance 用于判断某对象是否为某构造器的实例。因此你可以用它自定义 instanceof 操作符在某个类上的行为。换句话说当判断一个实例是否为一个类的实例时,其实就是执行该类里面的 Symbol.hasInstance 属性。

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

4.3、Symbol.isConcatSpreadable

内置的 Symbol.isConcatSpreadable 符号用于配置某对象作为 Array.prototype.concat()方法的参数时是否展开其数组元素。

// 默认情况下
let arr = [1, 2, 3];
let brr = [4, 5, 6];
arr.concat(brr); // [1, 2, 3, 4, 5, 6]
// 设置了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]]
登入後複製

将数组的 Symbol.isConcatSpreadable 属性设置为 false 后,使用 concat 方法时该数据就不会展开。

对于类数组而言,默认数组使用 concat 方法该类数组是不展开的,我们可以给类数组的 Symbol.isConcatSpreadable 设置为 true,这样就可以展开了,并且完成了类数组转换为数组,这样类数组转数组又多了一个方法。

// 默认情况下
function foo(x, y) {
  let arr = [].concat(arguments);
  console.log(arr); //[Arguments(2)]
}
foo(1, 2);
// 设置了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 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。

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

[...myIterable]; // [1, 2, 3]
登入後複製

对象进行 for...of 循环时,会调用 Symbol.iterator 方法,

4.5、Symbol.match

Symbol.match 指定了匹配的是正则表达式而不是字符串。String.prototype.match() 方法会调用此函数。换句话说就是当 str.match()执行时如果该属性存在,就会返回该方法的返回值。

class foo {
  [Symbol.match](string) {
    return string;
  }
}
"Jack".match(new foo()); // 'Jack'
登入後複製

除上述之外,MDN 还提出了该属性另外一个功能:此函数还用于标识对象是否具有正则表达式的行为。比如, String.prototype.startsWith(),String.prototype.endsWith() 和 String.prototype.includes() 这些方法会检查其第一个参数是否是正则表达式,是正则表达式就抛出一个 TypeError。现在,如果 match symbol 设置为 false(或者一个 假值),就表示该对象不打算用作正则表达式对象。

"/bar/".startsWith(/bar/); // TypeError: First argument to String.prototype.startsWith must not be a regular expression
// 当设置为false之后
var re = /foo/;
re[Symbol.match] = false;
"/foo/".startsWith(re); // true
"/baz/".endsWith(re); // false
登入後複製

4.6、Symbol.matchAll

Symbol.matchAll 返回一个迭代器,该迭代器根据字符串生成正则表达式的匹配项。此函数可以被 String.prototype.matchAll() 方法调用。

"abc".matchAll(/a/);
// 等价于
/a/[Symbol.matchAll]("abc");
登入後複製

4.7、Symbol.replace

Symbol.replace 这个属性指定了当一个字符串替换所匹配字符串时所调用的方法。String.prototype.replace() 方法会调用此方法。

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 指定了一个搜索方法,这个方法接受用户输入的正则表达式,返回该正则表达式在字符串中匹配到的下标,这个方法由以下的方法来调用 String.prototype.search()。

String.prototype.search(regexp);
// 等价于
regexp[Symbol.search](this);
// 例子
class Search1 {
  [Symbol.search](str) {
    return `${str} Word`;
  }
}
"Hello".search(new Search1()); // Hello Word
登入後複製

4.9、Symbol.species

Symbol.species 是个函数值属性,其被构造函数用以创建派生对象,换句话说 species 访问器属性允许子类覆盖对象的默认构造函数。

我们举个例子:

// 默认情况下
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 的实例,brr 为 arr 的衍生物,所以 brr 是 MyArray 的实例,并且由于原型链的缘故,brr 也是 Array 的实例。如果此时,我们只想让 brr 为 Array 的实例,那 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
// 默认情况下
class MyArray extends Array {
  static get [Symbol.species]() {
    return this;
  }
}
登入後複製

值得注意的是,定义 Symbol.species 属性时,前面必须声明是静态的 static 并且要运用 get 取值器。

4.10、Symbol.split

Symbol.split 指向 一个正则表达式的索引处分割字符串的方法。 这个方法通过 String.prototype.split() 调用。

String.prototype.split(separator, limit);
// 等价于
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 是一个内置的 Symbol 值,它是作为对象的函数值属性存在的,当一个对象转换为对应的原始值时,会调用此函数。该函数在调用时,会传递一个字符串参数 hint,表示要转换到的原始值的预期类型。字符串 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 是一个内置 symbol,它通常作为对象的属性键使用,对应的属性值应该为字符串类型,这个字符串用来表示该对象的自定义类型标签,通常只有内置的 Object.prototype.toString() 方法会去读取这个标签并把它包含在自己的返回值里。通俗点讲就是在 Object.prototype.toString()去判断自定义对象的数据类型时,返回的都是 object,可以通过这个属性来给自定义对象添加类型标签。

Object.prototype.toString.call('123'); // [object String]
...more
登入後複製

另外一些对象类型则不然,toString() 方法能识别它们是因为引擎为它们设置好了 toStringTag 标签:

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

当我们自己定义一个类时,调用 Object.prototype.toString()时,由于没有内部定义 toStringTag 标签,所以只能返回"[object Object]"

class Foo {}
Object.prototype.toString.call(new Foo()); // "[object Object]"
// 设置Symbol.toStringTag
class Foo {
  get [Symbol.toStringTag]() {
    return "Foo";
  }
}
Object.prototype.toString.call(new Foo()); // "[object Foo]"
登入後複製

4.13、Symbol.unscopabless

Symbol.unscopables 指用于指定对象值,其对象自身和继承的从关联对象的 with 环境绑定中排除的属性名称。说白了其属性就是控制,在 with 词法环境中哪些属性会被 with 删除。

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

这里简单的讲解一下 with 函数,with 主要是用来对对象取值的,举个简单的例子:

let obj = {};
with (obj) {
  let newa = a;
  let newb = b;
  console.log(newa + newb);
}
// 等价于
let newa = obj.a;
let newb = obj.b;
console.log(newa + newb);
登入後複製

with 的 优点: 当 with 传入的值非常复杂时,即当 object 为非常复杂的嵌套结构时,with 就使得代码显得非常简洁。 with 的缺点: js 的编译器会检测 with 块中的变量是否属于 with 传入的对象, 上述例子为例,js 会检测 a 和 b 是否属于 obj 对象,这样就会的导致 with 语句的执行速度大大下降,性能比较差。

回归正题,我们举个例子看一下 Symbol.unscopables 属性的作用。

let obj = {
  foo() {
    return 1;
  }
}
with(obj) {
  foo(); // 1
}
// 设置了Symbol.unscopables
let obj = {
  foo() {
    return 1;
  },
  get [Symbol.unscopables]() {
    return {
      foo: true
    }
  }
}
with(obj) {
  foo(); // Uncaught ReferenceError: foo is not defined
}
登入後複製

设置后报错的原因是因为with已经将obj中的foo方法删除了。

BigInt类型

BigInt 是一种特殊的数字类型,它提供了对任意长度整数的支持。

1、概述

BigInt 是一个新型的内置类型,主要是为了表达大于 2^53-1 的整数。

我们定义一个 BigInt 类型的数据时有两种方式,第一个是在数字后面加 n,另外一种是调用 BigInt()方法。

let theBigInt = 9007199254740991n;
let alsoHuge = BigInt(9007199254740991); // 9007199254740991n
登入後複製

当用 typeof 对其进行类型判断时,返回的是 bigint。

let theBigInt = 9007199254740991n;
typeof theBigInt; // bigint
登入後複製

2、运算

BigInt 支持以下的运算符,+、*-**% ,并且支持除了>>> (无符号右移)之外的 其他位运算符。

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 是不支持单目+运算符的。

+previousMaxSafe; // Uncaught TypeError: Cannot convert a BigInt value to a number
登入後複製

主要原因还是 BigInt 无法和 Number 类型直接运算,如果想要运算的话必须在同一个类型上,但是有一点值得注意的是,当 BigInt 转为 Number 类型时,有可能会丢失精度。

在比较运算符中,BigInt 和 Nunber 类型的之间不是严格相等的。

10n == 10; // true
10n === 10; // false
登入後複製

Number 和 BigInt 是可以进行比较的。

1n < 2; // true
2n > 1; // true
2n >= 2; // true
登入後複製

3、API

BigInt 拥有两个静态方法:

  • BigInt.asIntN(width, bigint):将 BigInt 值转换为一个-2^width-1 与 2^width-1-1 之间的有符号整数。

  • BigInt.asUintN(width, bigint):将一个 BigInt 值转换为 0 与 2^width-1 之间的无符号整数。

这两个方法均接受两个参数,width:可存储整数的位数。bigint:要存储在指定位数上的整数。

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

const max = 2n ** 64n - 1n;
BigInt.asUintN(64, max); // 18446744073709551615n
登入後複製

同时 BigInt 还拥有三个实例方法:

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

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

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

let bigint = 3500n;
bigint.toLocaleString(); // "3,500"
bigint.toString(); // "3500"
bigint.valueOf(); // 3500n
登入後複製

【相关推荐:javascript视频教程编程视频

以上是es6新增的js基本資料型別有哪些的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板