讀書筆記: JavaScript技術手冊4 - 物件進階語法

Object protocol 物件協定

valueOf

  • 多數情況下不要在 numberstring 以外的型別使用 +、-、*、/、**
  • valueOf 方法會回傳基本型別,可在需要基本型別運算時使用;
  • valueOfDate 實例可用於比較關係(>、<、>=、<=),但不建議用在 +、-、*、/、** 運算。

      // ex0. 預設回傳instance本身
      let o = {};
      console.log(o.valueOf() === o);   // true
    
      // ex1. 回傳基本型別
      let n1 = { valueOf(){ reutrn 10; } };
      let n2 = { valueOf(){ reutrn 5; } };
      console.log(n1 + n2);   // 15
      console.log(n1 > n2);   // true
    
      // ex2. Date
      let t1 = new Date();
      let t2 = new Date(1397699040389);
      console.log(t1.value.Of());   // 1660055938634
      console.log(t2.value.Of());   // 1397699040389
    
      console.log(t1 > t2);   // true
      console.log(t1 - t2);   // 262356898245
      console.log(t1 + t2);   // 'Tue Aug 09 2022 22:38:58 GMT+0800 (GMT+08:00)Thu Apr 17 2014 09:44:00 GMT+0800 (GMT+08:00)'
    

toString()

  • 用於定義 primitive string

      let o1 = { toString(){ return 'o1'; } };
      let o2 = { toString(){ return 'o2'; } };
    
      console.log(o1 + o2);   // o1o2
      console.log({} + {});   // [object Object][object Object] (呼叫 valueOf 方法)
    


(ES6) Symbol

  • 用來建立具有特殊意義、獨一無二行為的規範型別
  • 不會同時有兩個相同的符號值
  • typeof Symbol() === 'symbol'
  • 宣告 符號值 = Symbol('指定說明文字')
    • .description 可查詢指定說明文字
    • .toString() 顯示 'Symbol('指定說明文字')'
  • 符號全域註冊表
  • 「指定說明文字」同時也是之後查表用的「鍵值

      let x = Symbol();
      let y = Symbol('Protocol.iterable');   // Protocol.iterable 只是說明文字
    
      console.log(Symbol('notSame').description);   // 'notSame'
      console.log(Symbol('notSame').toString());   // Symbol('notSame')
      console.log(Symbol('notSame') === Symbol('notSame'));   // false
    
      // 註冊表
      let iteratorSymbol = Symbol.for('Protocol.iterator');   // 建立的符號保存到註冊表
      console.log(Symbol.for('Protocol.iterator') === iteratorSymbol);   // true
      console.log(Symbol.keyFor(iteratorSymbol));   // 'Protocol.iterator'
    
  • getter應用

      let obj = {
          get [Symbol.for('x')](){
              return 10;
          }
      }
    
      console.log(obj[Symbol.for('x')]);   // 10
    

內建標準符號

Symbol.iterator

  • 代表用於迭代器的符號
  • iterator(迭代器)是有 next() 方法的物件
  • 可實作 next()throw()return()
  • 實作迭代器範例

      ex1. array
      let arr = [1, 2, 3];
      let arrIterator = arr[Symbol.iterator]();
      iterator.next();   // {value: 1, done: false}
    
      // ex2. range
      function range(start, end){
          let i = start;
          return{
              [Symbol.iterator]() {
                  return this;
              },
              next(){
                  if(i < end){
                      return {value: ++i, done: false};
                  }
                  return {value: undefined, done: true};
              },
              return(value){
                  console.log(value);
                  i = end;
                  return {value, done: true};
              }
          }
      }
    
      for(let n of range(1, 3)){
          console.log(n);
      }
    
      for(let n of range(2, 6)){
          console.log(n);
          break;   // 呼叫 return()
      }
    
  • Symbol定義的特性或方法都無法被 for..in 列舉

      let o = {
          [Symbol.iterator](){
              return this;
          }
      };
    
      for(let p in o){
          console.log(p);   // undefined, 不能被 for..in 列舉
      }
    
      console.log(Symbol.iterator in o);   // true
    
  • 可迭代物件解構範例(產生器還是方便)

      // iterabel object
      let arrayLike = {
          '0': 10,
          '1': 20,
          '2': 30,
          length: 3,
          *[Symbol.iterator](){
              for(let i = 0; i < this.length; ++i){
                  yield this[i];
              }
          }
      }
    
      for(let n of arrayLike){
          console.log(n);
      }
    
      let [x, y, z] = arrayLike;
      console.log(x, y, z);
    

    Symbol.toPrimitive

  • 定義取得基本型別的物件

      let o1 = {
          valueOf(){
              return 10;
          },
          [Symbol.toPrimitive](){
              return 100;
          }
      };
    
      let o2 = {
          valueOf(){
              return 20;
          },
          [Symbol.toPrimitive](){
              return 200;
          }
      };
    
      console.log(o1 + o2);   // 300