iT邦幫忙

第 12 屆 iThome 鐵人賽

0
Modern Web

從技術文章深入學習 JavaScript系列 第 26

Day 26 [其他04] ES6的Symbol竟然那么强大,面试中的加分点啊

文章選自

作者:xiaohesong

連接:https://juejin.im/post/6844903703242080263

原文連結:https://xiaohesong.gitbook.io/today-i-learn/front-end/es6/understanding-es6/symbol#basic

來源:掘金

甚麼是Symbol

Symbol是ES6加進來的,也是屬於基本類型(number、string....)

基本用法

可以發現Symbol類型可以當作對象的key

let foo = Symbol('bar')
console.log(typeof foo) // 'symbol'
let testObj = {}
testObj[foo] = '這樣可以設置!'
console.log(testObj);

https://ithelp.ithome.com.tw/upload/images/20210201/20124350wn530oMJ35.png

Symbol for

透過這個方法創建時會先在全局裡面尋找這個key的Symbol,如果存在則返回此Symbol,不存在則創建並進行全局註冊

// 用基本方法創建兩個相同key的Symbol會不一樣
let first = Symbol('不會一樣')
let second = Symbol('不會一樣')
console.log(first === second); // fasle

// 用此方法創建的則會一樣
let fooA = Symbol.for('居然會一樣')
let fooB = Symbol.for('居然會一樣')
console.log(fooA === fooB); // true

// 基礎方法跟Symbol.for當然也不一樣
let barA = Symbol('這樣也會不一樣')
let barB = Symbol.for('這樣也會不一樣')
console.log(barA === barB); // false

Symbol keyfor

返回用全局註冊Symbol的key

let fooA = Symbol.for("foo");
console.log(Symbol.keyFor(fooA)); // "foo"

let fooB = Symbol.for("foo");
console.log(Symbol.keyFor(fooB)); // "foo"

// 因為沒有透過Symbol.for進行全局註冊當然找不到
let notKeyCreated = Symbol("我居然會不存在!");
console.log(Symbol.keyFor(notKeyCreated)); // undefined

Symbol 不會被自動轉換

可以透過String轉型,不過講真的這樣做意義不大

let foo = Symbol('foo')

console.log(String(foo));
console.log(foo.toString())
console.log(foo + '');

https://ithelp.ithome.com.tw/upload/images/20210201/20124350jqizZV3zGj.png

對象裡Symbol key的獲取

let foo = Symbol('foo')
let obj = {
  // 注意我們要用Symbol當成key,需要要用方括號刮起來
  // 因為需要的是變量foo非字符串foo
  [foo]: 'foo'
}
console.log(Object.keys(obj)) // []
console.log(Object.getOwnPropertyNames(obj)) // []

// ES6新增的方法
console.log(Object.getOwnPropertySymbols(obj)) // [Symbol(foo)]

補充

let obj = {
  [foo]: 'foo'
}

這裡提到了我們要讓

注意我們要用Symbol當成key,需要用方括號刮起來
因為需要的是變量foo非字符串foo

所以以下設置也是為了此目的

let obj = {}
let foo = Symbol('foo')

obj.foo = 'foo'
obj[foo] = 'SymbolFoo'

console.log(obj);

https://ithelp.ithome.com.tw/upload/images/20210201/20124350P76Fxf9Zfv.png

Symbol.hasInstance

每一個函數內部都會有存在這個方法,主要判斷一個對象是否為構造函數的實例(即是instanceof)

function User() {}
const Mike = new User
console.log(Mike instanceof User) // true
// 使用函數內部的方法
console.log(User[Symbol.hasInstance](Mike)) // true

自定義instanceof

// 取自MDN
class Array1 {
  static [Symbol.hasInstance](instance) {
    return Array.isArray(instance);
  }
}

console.log([] instanceof Array1);
// expected output: true

Symbol.isConcatSpreadable

以下取自MDN:

內置的方法的參數時是否展開其數組元素。Symbol.isConcatSpreadable`符号用于配置某对象作为Array.prototype.concat

例子

let foo = ['a', 'b', 'c']
let = numeric = [1, 2, 3];

let fooAndNumericA = foo.concat(numeric);

console.log(fooAndNumericA); // 结果: ['a', 'b', 'c', 1, 2, 3]

// 
numeric[Symbol.isConcatSpreadable] = false;

let fooAndNumericB = foo.concat(numeric)
console.log(fooAndNumericB);

https://ithelp.ithome.com.tw/upload/images/20210201/20124350rNsKXOFP3F.png

Symbol.toPrimitive

對象的內置屬性,一個對象可以被轉換成原始值都是靠他幫忙

該函數被調用時,會被傳遞hint參數,代表預期想要轉換的類型

參數的值有三種

  1. number
  2. string
  3. default

string以及number 模式

number mode:

  • 首先調用valueOf,若是原始類型,那就返回。
  • 若非原始值,那麼就調用toString,如果是原始類型,那就返回
  • 如果都不存在,那麼就報錯

string mode 在字符串的情況下,行為略有不同(優先級從高到低)

  • 首先調用toString,如果是原始值,那麼就返回
  • 如果前面不是原始值,那麼就嘗試調用valueOf,如果是原始值,那麼就返回
  • 拋出錯誤

例子

此例子可以觀察Symbol.toPrimitive是如何干擾對象轉換成原始類型

// 以下改寫自MDN
// 沒有改寫 Symbol.toPrimitive 的對象
var fooA = {};
console.log(fooA / 1); // NaN
console.log(String(fooA)); // "[object Object]"
console.log(fooA + ""); // "[object Object]"

// 聲明一個新的對象,並更改了他的 Symbol.toPrimitive 屬性
var fooB = {
  [Symbol.toPrimitive](hint) {
    if (hint == "number") {
      return 'number';
    }
    if (hint == "string") {
      return "string";
    }
    return 'default';
  }
};
console.log(fooB / 1); // Nan
console.log(String(fooB)); // string
console.log(fooB + ""); // default


上一篇
Day 25 [模塊化] 前端模塊化:CommonJS,AMD,CMD,ES6
下一篇
Day 27 [其他05] 前端必知必会--操作URL的黑科技
系列文
從技術文章深入學習 JavaScript29

尚未有邦友留言

立即登入留言