Created
December 23, 2011 09:23
-
-
Save x7c1/1513704 to your computer and use it in GitHub Desktop.
mixin in javascript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // using node.js | |
| exports.mixin = new function(){ | |
| function mixin(klass, trait){ | |
| var new_class = function(){}; | |
| new_class.prototype = new function(){ | |
| var f = function(){} | |
| f.prototype = klass.prototype; | |
| return extend(new f, trait); | |
| }; | |
| return new_class; | |
| } | |
| return function(klass){ | |
| return [].slice.call(arguments, 1).reduce(mixin, klass); | |
| } | |
| } | |
| function extend(dst, src) { | |
| for (var key in src) { | |
| if (src.hasOwnProperty(key)) | |
| dst[key] = src[key]; | |
| } | |
| return dst; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // node example_test.js | |
| var assert = require('assert'); | |
| var mixin = require('./example.js').mixin; | |
| var TraitA = { | |
| getA: function(){ return "A" } | |
| }; | |
| var TraitB = { | |
| getB: function(){ return "B" } | |
| }; | |
| var ClassX = function(){} | |
| ClassX.prototype = { | |
| getX: function(){ return "X" } | |
| }; | |
| var ClassY = function(){} | |
| ClassY.prototype = { | |
| getY: function(){ return "Y" } | |
| }; | |
| var ClassX_with_A = mixin(ClassX, TraitA); | |
| var ClassX_with_A_B = mixin(ClassX_with_A, TraitB); | |
| var x = new ClassX_with_A_B; | |
| assert.equal(x.getX(), "X"); | |
| assert.equal(x.getA(), "A"); | |
| assert.equal(x.getB(), "B"); | |
| var ClassY_with_A_B = mixin(ClassY, TraitA, TraitB); | |
| var y = new ClassY_with_A_B; | |
| assert.equal(y.getY(), "Y"); | |
| assert.equal(y.getA(), "A"); | |
| assert.equal(y.getB(), "B"); | |
| ClassX_with_A_B.prototype.getAB = function(){ | |
| return "AB"; | |
| }; | |
| // method defined after "new" is callable | |
| assert.equal(x.getAB(), "AB"); | |
| // ClassX is not affected with | |
| // methods added to the prototype of newly generated class | |
| assert.equal(ClassX.prototype.getAB, undefined); | |
| ClassX.prototype.getX2_defined_dynamically = function(){ | |
| return "X2"; | |
| }; | |
| // method defined dynamically in original ClassX | |
| // is callable by prototype-chain | |
| assert.equal(x.getX2_defined_dynamically(), "X2"); | |
| TraitA.getA2_defined_dynamically = function(){ | |
| return "A2"; | |
| }; | |
| // cannot call a method defined after "new" in Trait (not cool) | |
| assert.equal(x.getA2_defined_dynamically, undefined); | |
| // can use original "instanceof" of javascript | |
| assert.equal(x instanceof ClassX, true); | |
| assert.equal(x instanceof ClassX_with_A, true); | |
| assert.equal(x instanceof ClassX_with_A_B, true); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment