Object protocol 物件協定
valueOf
- 多數情況下不要在
number
或string
以外的型別使用 +、-、*、/、** valueOf
方法會回傳基本型別,可在需要基本型別運算時使用;valueOf
在Date
實例可用於比較關係(>、<、>=、<=),但不建議用在 +、-、*、/、** 運算。// 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