1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
| class Todo { constructor (name) { this.name = name || 'Untitled'; this.done = false; } // class method are not enumerable by defalt do () { this.done = true; return this; } undo () { this.done = false; return this; } }
// // object mixin // // Object.assign only assigns enumerable properties // const Coloured = { // setColourRGB ({r, g, b}) { // this.colourCode = {r, g, b}; // return this; // }, // getColourRGB () { // return this.colourCode; // } // }; // Object.assign(Todo.prototype, Coloured); // const todo = new Todo('test'); // todo.setColourRGB({r: 1, g: 2, b: 3})
/* 数据描述符默认值 { configurable: false, enumerable: false, value: undefined, writable: false } 存取描述符默认值 { get: undefined, set: undefined, value: false, writable: false } */ // functional mixin const shared = Symbol("shared"); function FunctionalMixin (behaviour) { // the methods defined in a mixin are enumerable by default const instanceKeys = Reflect.ownKeys(behaviour) .filter(key => key !== shared); const sharedBehaviour = behaviour[shared] || {}; const sharedKeys = Reflect.ownKeys(sharedBehaviour); const typeTag = Symbol("isA"); function mixin (target) { for (let property of instanceKeys) Object.defineProperty(target, property, { value: behaviour[property] }); target[typeTag] = true; return target; } for (let property of sharedKeys) Object.defineProperty(mixin, property, { value: sharedBehaviour[property], enumerable: sharedBehaviour.propertyIsEnumerable(property) }); // for instanceof check Object.defineProperty(mixin, Symbol.hasInstance, {value: (instance) => !!instance[typeTag]}); return mixin; } FunctionalMixin.shared = shared;
const Coloured = FunctionalMixin({ setColourRGB ({r, g, b}) { this.colourCode = {r, g, b}; return this; }, getColourRGB () { return this.colourCode; }, [FunctionalMixin.shared]: { RED: { r: 255, g: 0, b: 0 }, GREEN: { r: 0, g: 255, b: 0 }, BLUE: { r: 0, g: 0, b: 255 }, } }); Coloured(Todo.prototype) const urgent = new Todo("finish blog post"); urgent.setColourRGB(Coloured.RED); urgent.getColourRGB() //=> {"r":255,"g":0,"b":0} urgent instanceof Todo // true urgent instanceof Coloured //=> true let obj = {}; obj instanceof Coloured //=> false
|