Namespacing and function declaration types - javascript

I'm currently starting to work on existing project. We have global namespace object FOO and a helper to create a nice namespace:
var FOO = FOO || {};
//...
FOO.namespace = function (name) {
var parts = name.split('.'),
parent = FOO,
i;
// strip redundant leading global
if (parts[0] === "FOO") {
parts = parts.slice(1);
}
for (i = 0; i < parts.length; i += 1) {
// create a property if it doesn't exist
if (typeof parent[parts[i]] === "undefined") {
parent[parts[i]] = {};
}
parent = parent[parts[i]];
}
return parent;
};
Because there are many submodules spread out over different files being worked on from different people I noticed different patterns on declaring new submodules.
A: direct creation
FOO.modulename = {
someMethod: function (param) {
// ...
}
}
B: Local alias with direct assignment
var modulename = FOO.namespace('modulename');
modulename.someMethod = function (param) {
// ...
}
C: Objectliteral assignment to submodule
var modulename = FOO.namespace('modulename');
FOO.modulename = {
someMethod: function (param) {
// ...
}
}
Now, A is obviously not the right way but what about the other options (and I guess i will discover at least 3 more ways to do it). They all achive the same thing and all work, but which method is the most "correct" one?

Related

Automatically generate stubbed modules in node.js

I'm moving my JavaScript test code from Jest to Mocha. One nice feature of Jest is that it automatically generated stubs for your modules. These stubs implement the same API as the originals, but all their functions return undefined. Exported classes are also stubbed, i.e. they have all the same methods as the original, but the return undefined:
// mymodule.js
var MyClass = function() { this.foo = 42; };
MyClass.prototype.getFoo = function() { return this.foo; };
module.exports = {
myclass: MyClass,
myfunction: function() { return 42; }
};
// __tests__/mymodule-test.js
var mm = require('../mymodule'); // Jest auto-mocks this module.
describe('test', function() {
it('functions and constructors are mocked', function() {
expect(mm.myfunction()).toEqual(undefined); // function is stubbed
var mc = new mm.myclass();
expect(mc.getFoo()).toEqual(undefined); // fn on prototype is stubbed.
});
});
For various reasons, I'm moving over to MochaJS but I'd like to keep this stubbing behavior. I can inject stubs for modules using proxyquire. But I need to define the stubs myself.
What I'd like is a function which which takes a Node module and returns something like the Jest auto-mocked version of the module. Jest's code to do this is in moduleMocker.js. I've written some code of my own to do this (included below). But it's quite tricky and doesn't feel like code I should be writing.
Is there a standard library for doing this?
Here's what I've written:
// stubber.js
var U = require('underscore');
function replaceFunctionsWithStubs(rootObj) {
var replacedObjs = []; // array of [original, replacement] pairs.
function previousReplacement(obj) {
for (var i = 0; i < replacedObjs.length; i++) {
if (replacedObjs[i][0] == obj) {
return replacedObjs[i][1];
}
}
return null;
}
function replacer(obj) {
var t = typeof(obj);
if (t != 'function' && t != 'object') {
// Simple data.
return obj;
}
// Return previous mock to break circular references.
var prevRep = previousReplacement(obj);
if (prevRep) return prevRep;
if (t == 'function') {
var f = function() {};
replacedObjs.push([obj, f]);
if (!U.isEmpty(obj.prototype)) {
// This might actually be a class. Need to stub its prototype, too.
var newPrototype = replacer(obj.prototype);
for (var k in newPrototype) {
f.prototype[k] = newPrototype[k];
}
}
// Stub any properties the function might have.
for (var k in obj) {
f[k] = replacer(obj[k]);
}
return f;
} else if (typeof(obj) == 'object') {
// TODO: Do I need to handle arrays differently?
var newObj = {};
replacedObjs.push([obj, newObj]);
for (var k in obj) {
newObj[k] = replacer(obj[k]);
}
return newObj;
} else {
return obj; // string, number, null, undefined, ...
}
}
return replacer(rootObj);
}
module.exports = function(m) {
return replaceFunctionsWithStubs(m);
};

Making private instance variable accessible to prototype methods enclosed in anonymous function

Background
I decided I would practice by making a simple calculator app in JS. The first step was to implement a stack class. I ran into some problems however in achieving data encapsulation with the revealing prototype pattern (?). Here's how it looks right now:
Stack "class":
var Stack = (function () {
var Stack = function() {
this.arr = []; // accessible to prototype methods but also to public
};
Stack.prototype = Object.prototype; // inherits from Object
Stack.prototype.push = function(x) {
this.arr.push(x);
};
Stack.prototype.pop = function() {
return this.arr.length ? (this.arr.splice(this.arr.length - 1, 1))[0] : null;
};
Stack.prototype.size = function() {
return this.arr.length;
};
Stack.prototype.empty = function() {
return this.arr.length === 0;
};
return Stack;
})();
Test code:
var s1 = new Stack();
var s2 = new Stack();
for(var j = 1, k = 2; j < 10, k < 11; j++, k++) {
s1.push(3*j);
s2.push(4*k);
}
console.log("s1:");
while(!s1.empty()) console.log(s1.pop());
console.log("s2:");
while(!s2.empty()) console.log(s2.pop());
The Problem
The only problem is that the arr is accessible. I would like to hide the arr variable somehow.
Attempts at a Solution
My first idea was to make it a private variable like Stack:
var Stack = (function () {
var arr = []; // private, but shared by all instances
var Stack = function() { };
Stack.prototype = Object.prototype;
Stack.prototype.push = function(x) {
arr.push(x);
};
// etc.
})();
But of course this approach doesn't work, because then the arr variable is shared by every instance. So it's a good way of making a private class variable, but not a private instance variable.
The second way I thought of (which is really crazy and definitely not good for readability) is to use a random number to restrict access to the array variable, almost like a password:
var Stack = (function() {
var pass = String(Math.floor(Math.pow(10, 15 * Math.random()));
var arrKey = "arr" + pass;
var Stack = function() {
this[arrKey] = []; // private instance and accessible to prototypes, but too dirty
};
Stack.prototype = Object.prototype;
Stack.prototype.push = function(x) {
this[arrKey].push(x);
};
// etc.
})();
This solution is... amusing. But obviously not what I want to do.
The last idea, which is what Crockford does, allows me to create a private instance member, but there's no way I can tell to make this visible to the public prototype methods I'm defining.
var Stack = (function() {
var Stack = function() {
var arr = []; // private instance member but not accessible to public methods
this.push = function(x) { arr.push(x); }; // see note [1]
}
})();
[1] This is almost there, but I don't want to have the function definitions within the var Stack = function() {...} because then they get recreated every time that an instance is created. A smart JS compiler will realize that they don't depend on any conditionals and cache the function code rather than recreating this.push over and over, but I'd rather not depend on speculative caching if I can avoid it.
The Question
Is there a way to create a private instance member which is accessible to the prototype methods? By somehow utilizing the 'bubble of influence' created by the enclosing anonymous function?
You could use a factory function that creates an instance for you:
function createStack() {
var arr = [];
function Stack() {
};
Stack.prototype = Object.prototype; // inherits from Object
Stack.prototype.push = function(x) {
arr.push(x);
};
Stack.prototype.pop = function() {
return arr.length ? (this.arr.splice(this.arr.length - 1, 1))[0] : null;
};
Stack.prototype.size = function() {
return arr.length;
};
Stack.prototype.empty = function() {
return arr.length === 0;
};
return new Stack();
}
You would be defining the class on every execution of the factory function, but you could get around this by changing this to define most of Stack outside the constructor function, like the parts that dont use arr could be further up the prototype chain. Personally I use Object.create instead of prototype now and I almost always use factory functions to make instances of these types of objects.
Another thing you could do is maintain a counter that keeps track of the instance and holds on to an array of arrays.
var Stack = (function() {
var data = [];
var Stack = function() {
this.id = data.length;
data[this.id] = [];
};
Stack.prototype = Object.prototype;
Stack.prototype.push = function(x) {
data[this.id].push(x);
};
// etc.
}());
Now you have the hidden data multi dimensional array, and every instance just maintains its index in that array. You have to be careful to manage the memory now though, so that when your instance isn't being used anymore you remove what's in that array. I don't recommend doing it this way unless you are disposing your data carefully.
The short answer here, is that you can't have all things, without sacrificing a little.
A Stack feels like a struct of some kind, or at very least, a data-type which should have either a form of peek or read-access, into the array.
Whether the array is extended or not, is of course up to you and your interpretation...
...but my point is that for low-level, simple things like this, your solution is one of two things:
function Stack () {
this.arr = [];
this.push = function (item) { this.arr.push(item); }
// etc
}
or
function Stack () {
var arr = [];
var stack = this;
extend(stack, {
_add : function (item) { arr.push(item); },
_read : function (i) { return arr[i || arr.length - 1]; },
_remove : function () { return arr.pop(); },
_clear : function () { arr = []; }
});
}
extend(Stack.prototype, {
push : function (item) { this._add(item); },
pop : function () { return this._remove(); }
// ...
});
extend here is just a simple function that you can write, to copy the key->val of objects, onto the first object (basically, so I don't have to keep typing this. or Class.prototype..
There are, of course, dozens of ways of writing these, which will all achieve basically the same thing, with modified styles.
And here's the rub; unless you do use a global registry, where each instance is given its own unique Symbol (or unique-id) at construction time, which it then uses to register an array... ...which of course, means that the key then needs to be publicly accessible (or have a public accessor -- same thing), you're either writing instance-based methods, instance-based accessors with prototyped methods, or you're putting everything you need in the public scope.
In the future, you will be able to do things like this:
var Stack = (function () {
var registry = new WeakMap();
function Stack () {
var stack = this,
arr = [];
registry[stack] = arr;
}
extend(Stack.prototype, {
push (item) { registry[this].push(item); }
pop () { return registry[this].pop(); }
});
return Stack;
}());
Nearly all bleeding-edge browsers support this, currently (minus the shorthand for methods).
But there are ES6 -> ES5 compilers out there (Traceur, for instance).
I don't think WeakMaps are supported in Traceur, as an ES5 implementation would require a lot of hoops, or a working Proxy, but a Map would work (assuming that you handled GC yourself).
This lends me to say that from a pragmatic standpoint, for a class as small as Stack you might as well just give each instance its own methods, if you really want to keep the array internal.
For other harmless, tiny, low-level classes, hiding data might be pointless, so all of it could be public.
For larger classes, or high-level classes, having accessors on instances with prototyped methods stays relatively clean; especially if you're using DI to feed in lower-level functionality, and the instance accessors are just bridging from the interface of the dependency, into the shape you need them to be, for your own interface.
A real solution
EDIT: It turns out this solution is basically the same as the one described here, first posted by HMR in a comment to my question above. So definitely not new, but it works well.
var Stack = (function Stack() {
var key = {};
var Stack = function() {
var privateInstanceVars = {arr: []};
this.getPrivateInstanceVars = function(k) {
return k === key ? privateInstanceVars : undefined;
};
};
Stack.prototype.push = function(el) {
var privates = this.getPrivateInstanceVars(key);
privates.arr.push(el);
};
Stack.prototype.pop = function() {
var privates = this.getPrivateInstanceVars(key);
return privates.arr.length ? privates.arr.splice(privates.arr.length - 1, 1)[0] : null;
};
Stack.prototype.empty = function() {
var privates = this.getPrivateInstanceVars(key);
return privates.arr.length === 0;
};
Stack.prototype.size = function() {
var privates = this.getPrivateInstanceVars(key);
return privates.arr.length;
};
Stack.prototype.toString = function() {
var privates = this.getPrivateInstanceVars(key);
return privates.arr.toString();
};
Stack.prototype.print = function() {
var privates = this.getPrivateInstanceVars(key);
console.log(privates.arr);
}
return Stack;
}());
// TEST
// works - they ARE separate now
var s1 = new Stack();
var s2 = new Stack();
s1.push("s1a");
s1.push("s1b");
s2.push("s2a");
s2.push("s2b");
s1.print(); // ["s1a", "s1b"]
s2.print(); // ["s2a", "s2b"]
// works!
Stack.prototype.push.call(s1, "s1c");
s1.print(); // ["s1a", "s1b", "s1c"]
// extending the Stack
var LimitedStack = function(maxSize) {
Stack.apply(this, arguments);
this.maxSize = maxSize;
}
LimitedStack.prototype = new Stack();
LimitedStack.prototype.constructor = LimitedStack;
LimitedStack.prototype.push = function() {
if(this.size() < this.maxSize) {
Stack.prototype.push.apply(this, arguments);
} else {
console.log("Maximum size of " + this.maxSize + " reached; cannot push.");
}
// note that the private variable arr is not directly accessible
// to extending prototypes
// this.getArr(key) // !! this will fail (key not defined)
};
var limstack = new LimitedStack(3);
limstack.push(1);
limstack.push(2);
limstack.push(3);
limstack.push(4); // Maximum size of 3 reached; cannot push
limstack.print(); // [1, 2, 3]
Cons: basically none, other than remembering a little extra code
Original solution
(The first method originally posted was substantially different from what is below, but through some careless editing I seem to have lost it. It didn't work as well anyway, so no real harm done.)
Here a new object/prototype is created with every instantiation, but it borrows much of the code from the static privilegedInstanceMethods. What still fails is the ability to do Stack.prototype.push.call(s1, val), but now that the prototype is being set on the object, I think we're getting closer.
var Stack = (function() {
var privilegedInstanceMethods = {
push: function(x) {
this.arr.push(x);
},
pop: function() {
return this.arr.length ? this.arr.splice(this.arr.length - 1, 1)[0] : null;
},
size: function() {
return this.arr.length;
},
empty: function() {
return this.arr.length === 0;
},
print: function() {
console.log(this.arr);
},
};
var Stack_1 = function() {
var Stack_2 = function() {
var privateInstanceMembers = {arr: []};
for (var k in privilegedInstanceMethods) {
if (privilegedInstanceMethods.hasOwnProperty(k)) {
// this essentially recreates the class each time an object is created,
// but without recreating the majority of the function code
Stack_2.prototype[k] = privilegedInstanceMethods[k].bind(privateInstanceMembers);
}
}
};
return new Stack_2(); // this is key
};
// give Stack.prototype access to the methods as well.
for(var k in privilegedInstanceMethods) {
if(privilegedInstanceMethods.hasOwnProperty(k)) {
Stack_1.prototype[k] = (function(k2) {
return function() {
this[k2].apply(this, arguments);
};
}(k)); // necessary to prevent k from being same in all
}
}
return Stack_1;
}());
Test:
// works - they ARE separate now
var s1 = new Stack();
var s2 = new Stack();
s1.push("s1a");
s1.push("s1b");
s2.push("s2a");
s2.push("s2b");
s1.print(); // ["s1a", "s1b"]
s2.print(); // ["s2a", "s2b"]
// works!
Stack.prototype.push.call(s1, "s1c");
s1.print(); // ["s1a", "s1b", "s1c"]
Pros:
this.arr is not directly accessible
method code is only defined once, not per instance
s1.push(x) works and so does Stack.prototype.push.call(s1, x)
Cons:
The bind call creates four new wrapper functions on every instantiation (but the code is much smaller than creating the internal push/pop/empty/size functions every time).
The code is a little complicated

NodeJS Module with config - instantiate from require or from module.exports

I'm developing a node.js module that has several functions.
The module itself will require some config to start (there will be defaults... that can be overridden - file paths for example)
What's the preferred approach when exporting a function?
Allowing it to be instantiated from a require statement, and pass in the config object (optional) to the constructor?
var MyModule = require('myModule);
var myModule = new MyModule({
name: "test name"
});
myModule.doThing(function(x){
});
Having this in the module:
module.exports = function MyModule(){
MyModule.prototype.config = {name: "default name"}
function doThing(cb){
//do stuff
cb();
}
}
Or, creating an instance from the exports statement in the module, then using it like this:
var myModule = require('myModule);
myModule.config = {name: "test name"}
myModule.doThing(function(x){
});
Instead, having this in the module:
module.exports = exports = MyModule();
function MyModule(){
MyModule.prototype.config = {name: "default name"}
function doThing(cb){
//do stuff
cb();
}
}
I’ll say let you users provide an object when instanciating, put the defaults in the prototype. You may also want to provide a configure function, this allows you (now or in the future) to validate keys/values, and your users to set configs after instanciation.
// Module
var Mod = module.exports = function Mod (opts) {
opts = (opts === Object(opts)) ? opts : {};
// This allows users to instanciate without the `new` keyword
if (! (this instanceof Mod)) {
return new Mod(opts);
}
// Copy user provided configs to this.config
for (var key in opts) if ({}.hasOwnProperty.call(opts, key)) {
this.config[key] = opts[key];
}
};
Mod.prototype.config = {
foo : 'foo',
bar : 'bar'
};
Mod.prototype.configure = function configure (key, val) {
this.config[key] = val;
return this;
};
// Usage
const Mod = require('/path/to/mod');
var i1 = new Mod;
var i2 = Mod();
var i3 = new Mod({
foo: 'bar'
});
var i4 = Mod({
foo: 'bar'
});
i4.configure('bar', 'baz');
var i5 = (new Mod).configure('bar', 'baz');
EDIT
As Jake Sellers noted in the comments, this isn’t standard API pattern in CommonJS modules.
A better solution would be to export a function that returns whatever object you’re creating.
More importantly, I should not advise to put the config in the prototype, ever. Doing this makes the config object shared by all children. As such any modification on it will also affect all children. Shame on me, I wasn’t a beginner when I wrote this crap. Double thanks Jake ;)
A better implementation:
// Keep defaults private
var defaults = {
foo : 'foo',
bar : 'bar'
};
// Construct
var Mod = function Mod (opts) {
opts = (opts === Object(opts)) ? opts : {};
// This allows users to instanciate without the `new` keyword
if (! (this instanceof Mod)) {
return new Mod(opts);
}
this.config = {};
// Copy user provided configs to this.config or set to default
for (var key in defaults) if (defaults.hasOwnProperty(key)) {
if ({}.hasOwnProperty.call(opts, key)) {
this.config[key] = opts[key];
}
else {
this.config[key] = defaults[key];
}
}
};
// Let the user update configuration post-instanciation
Mod.prototype.configure = function configure (key, val) {
this.config[key] = val;
return this;
};
// Export a function that creates the object
exports.createMod = function createMod (opts) {
return new Mod(opts);
};
// Export the constructor so user is able to derive from it
// or check instanceof
exports.Mod = Mod;
// USAGE
var mod = require('/path/to/mod');
var i1 = mod.createMod({ foo : 'bar' });
i1.configure('bar', 'baz');
It depends on whether you want the users of your module be able to use exactly one pre-defined instance (the one that you create on module.exports) or if you want them to be able to create their own instances (then you need to export the constructor as a function, not its return value).
If you go and write a constructor, I'd opt for the second option (let the user create the instances) - except if it's a singleton object you are providing.

Static variables with John Resig's simple class pattern?

I'm referring to this article.
In it, he defines a function that looks something like this:
function makeClass() {
return function _class() {
if(this instanceof _class) {
if(typeof this.init === 'function') {
this.init.apply(this, arguments);
}
} else {
throw new Error('Constructor called as a function');
}
};
}
And then you can use it with something like this:
var MyClass = makeClass();
MyClass.prototype = {
init: function(width, height) { ... },
clear: function(ctx) {... },
draw: function(ctx) { ... }
}
But now I want to initialize some static variables that should be shared across all instances. How do I do that?
Well, the easiest approach is to define a static variable as a prototype property:
MyClass.prototype.xxx: 3, // ...
var t1 = new MyClass();
console.log(t1.xxx); // 3
... but it won't behave as static properties in other languages usually do:
var t2 = new MyClass();
t2.xxx = 5;
console.log(t1.xxx); // still 3 :(
The other way around is to use the fact that properties might be attached to functions as well:
MyClass.xxx = 3;
... but that narrows the ways we can use this property (it can't be called by t1.xxx from the previous examples).
There's another way, though. One can define static properties as variables, local to init method, accessible by methods, defined... in this init method as well. ) Like this.
init: function() {
var xxx = 3;
MyClass.prototype.getXXX = function() {
return xxx;
};
MyClass.prototype.setXXX = function(newXXX) {
xxx = newXXX;
}
}
Then all one can use this property simply by this:
var t1 = new MyClass();
var t2 = new MyClass();
console.log(t1.getXXX()); // 3
console.log(t2.getXXX()); // 3
t1.setXXX(5);
console.log(t1.getXXX()); // 5 now
console.log(t2.getXXX()); // 5 as well, behold the power of closures!
And here's a fiddle used.
UPDATE: this approach is better be used, I suppose, when we need to work with a (sort of) container of the static class data, that is to be shared by all objects - but we don't know exactly what can actually be stored in this container. Then we use just two functions - getStatic and setStatic - to store and retrieve data by string keys or some other identifiers. It may seem a bit confusing, and it is, but I think it may be worth an effort. )
Just add it to MyClass itself.
MyClass.myVariable = 42;
It's not really static in the Java/C# sense, but gives you the same effect.
I "solved" this problem by using a naming convention.
I wanted the convenience of the Class.extend({ }) syntax, but also a way to declare "static" properties within it.
I opted for a leading underscore to declare a static property, although you could do whatever you liked.
Usage:
var myClass = Class.extend({
_staticProperty: 1337
, instanceProperty: 'foo'
, instanceMethod: function() { }
, ctor: function() {
this.base();
}
});
note I've renamed init and this._super() from the original code
And the code:
/* Simple JavaScript Inheritance
* Modified by Andrew Bullock http://blog.muonlab.com to add static properties
* By John Resig http://ejohn.org/
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function () {
var initializing = false, fnTest = /xyz/.test(function () { xyz; }) ? /\bbase\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function () { };
// Create a new Class that inherits from this class
Class.extend = function (prop) {
var base = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// The dummy class constructor
function Class() {
// All construction is actually done in the ctor method
if (!initializing && this.ctor)
this.ctor.apply(this, arguments);
}
// Copy static properties from base
for (var name in this) {
if (name.substr(0, 1) == '_')
Class[name] = this[name];
}
// Copy the properties over onto the new prototype
for (name in prop) {
// Check if we're overwriting an existing function
if (typeof prop[name] == "function" && typeof base[name] == "function" && fnTest.test(prop[name])) {
prototype[name] = (function(name, fn) {
return function() {
var tmp = this.base;
// Add a new .base() method that is the same method
// but on the super-class
this.base = base[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this.base = tmp;
return ret;
};
})(name, prop[name]);
} else if (name.substr(0, 1) == '_') {
Class[name] = prop[name];
} else {
prototype[name] = prop[name];
}
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
If you don't care about browser support, you could also use a WeakMap of constructor/static properties pairs. Here's the idea: http://jsfiddle.net/DfNNU/2/. This requires MyClass.prototype.constructor, which you should not discard. So, you'd need to add back constructor: MyClass to the prototype.
var statics = (function() {
var map = new WeakMap;
return function(inst) {
var ctor = inst.constructor;
return map.get(ctor) || map.set(ctor, {});
};
})();
Use it like:
var a = function() {};
var b = function() {};
var inst1 = new a;
var inst2 = new a;
var inst3 = new b;
statics(inst1).foo = 123;
statics(inst3).foo = 456;
console.log( statics(inst1).foo ); // 123
console.log( statics(inst2).foo ); // 123
console.log( statics(inst3).foo ); // 456
I've modified John Resig's class to provide copy over the parent's static members to the new class, which adds this:
for (var name in this) {
if (!Class[name]) {
Class[name] = this[name];
}
}
Here's a fiddle.
// This is a modified version of John Resig's simple inheritence class to add copying of static methods
// The new code is the for loop commented with "add in the static members"
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function(){
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function(){};
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
//add in the static members
for (var name in this) {
if (!Class[name]) {
Class[name] = this[name];
}
}
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
function addText(text) {
document.getElementById('greetings').innerHTML = document.getElementById("greetings").innerHTML + '<br>' + text;
}
//parent class with a prototype method and two static methods
var Parent = Class.extend({
hello: function () {
addText('parent.hello');
}
});
Parent.static = function() {
addText('Parent.static');
}
Parent.overrideStatic = function() {
addText('Parent.overrideStatic');
}
//child class that overrides one of the parent's static methods
var Child = Parent.extend();
Child.overrideStatic = function() {
addText('Child.overrideStatic');
}
var parent = new Parent();
parent.hello();
Parent.static();
var child = new Child();
child.hello(); //should output parent.hello
Child.static(); //should output Parent.static
Child.overrideStatic();
<div id="greetings"></div>
Pass in an optional list of static members in the call to 'extend'. This method adds the static properties (if any) to a 'statics' attribute on the constructor function.
Code Changes
Changes as follows. These lines added just after the 'dummy class constructor' code:
if(staticProp) {
Class.statics = [];
for (var name in staticProp) {
!Class.statics[name] && (Class.statics[name] = staticProp[name]);
}
}
An additional argument 'staticProp' added when type is declared in order to allow introduction of static members at this stage:
Class.extend = function(prop,staticProp) {
A fiddle can be found here, includes some tests.
Usage Examples
Can define statics at type declaration time like so using the second optional constructor argument:
var A = Class.extend({},{myStatic:1});
Can access/define statics inside an instance method:
var B = Class.extend({test:function(){B.statics.myStatic=2;}});
Or from outside an instance:
A.statics.myStatic=3;
Example with requirejs:
Put Class.js in the baseUrl folder. Example new class definition. Not mandatory to name the file of the new class the same as the 'var C' (i.e. C.js) but probably better for readability so references to the C name within the class's methods are aligned to any external references to its static members:
define(['Class'],function($) {
var C = Class.extend({
init: function(params){
C.statics.myStatic++; // access static data
}
},{
myStatic: 123
});
return C;
});
Another class in D.js refers to static data in class C:
define(['Class', 'C'],function($,C) {
var D = Class.extend({
init: function(params){
C.statics.myStatic++; // static data of another class
}
},{});
return D;
});

Javascript inherance and use of super: is this possible?

if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {
}
F.prototype = o;
var f = new F();
if(f.init){
f.init();
};
return f;
};
}
var inherit = function(P, C) {
var i;
for(i in P) {
// if is the current parent
if(P.hasOwnProperty(i) === false) {
continue;
};
// define the uper property
C.uper = {};
// methods
if(typeof P[i] === 'function') {
// set as super
C.uper[i] = P[i];
// if child already defined, skip
if(typeof C[i] === 'function') {
continue;
};
C[i] = P[i];
}
// properties
else {
// if child already defined a property, skip
if(!(typeof C[i] === 'undefined')) {
continue;
};
C[i] = P[i];
}
}
return C;
}
var Parent1 = (function(){
var that = {};
// private var
var _name = 'Parent1';
// public var
that.lastName = 'LastName';
// public method
that.getName = function(){
// if this.uper.getName.call(this)
return _name + this.lastName;
// else
// return _name + that.lastName;
}
// return the literal object
return that;
}());
var Parent2 = {
// fake private var
_name: 'Parent2',
// public method
getName: function(){
// as we call this method with the call method
// we can use this
return this._name;
}
}
var Child1 = inherit(Parent1, (function(){
var that = {};
// overriden public method
that.getName = function(){
// how to call the this.uper.getName() like this?
return 'Child 1\'s name: ' + this.uper.getName.call(this);
}
that.init = function(){
console.log('init');
}
// return the literal object
return that;
}()));
var Child2 = inherit(Parent2, {
getName: function(){
// how to call the this.uper.getName() like this?
return 'Child 2\'s name: ' + this.uper.getName.call(this);
}
});
var child1 = Object.create(Child1);
// output: Child 1's name: Parent1LastName
console.log(child1.getName());
var child2 = Object.create(Child2);
// output: Child 2's name: Parent2
console.log(child2.getName());
// how to call the this.uper.getName() like this?
how to call the this.uper.getName() like this?
Yes
Javascript uses Prototypal inheritance. So essentially objects inherit Objects (and everything is an Object)
Here are a couple links that should help get the point across.
Javascript Module Pattern
Module Pattern In-depth
Here's the basic module pattern:
var MODULE = (function (my) {
my.anotherMethod = function () {
// added method...
};
return my;
}(MODULE));
Then you can do something like this to mimic inheritance:
var MODULE_TWO = (function (old) {
var my = {},
key;
for (key in old) {
if (old.hasOwnProperty(key)) {
my[key] = old[key];
}
}
var super_moduleMethod = old.moduleMethod;
my.moduleMethod = function () {
// override method on the clone, access to super through super_moduleMethod
};
return my;
}(MODULE));
This style of coding takes a bit of getting used to, but I definitely prefer it to classical inheritance at this point. If this code isn't making sense, check out the Douglas Crockford lectures and it should clarify most of it.
addressing the edit:
You can create different instantiations of these objects by using the new operator.
OR
I'd recommend using this little method which extends the Object Prototype (again if this doesn't make sense see the Douglas Crockford video). I forget the exact reasons why this is so heavily recommended by him, but at the very least it eliminates some confusion in that the new operator is a bit different than in classical languages. Needless to say using only using the new operator is insufficient.
What this function does is extends the Object prototype with a method create. It then...
Defines function F in a contained namespace.
Assigns the function F's prototype to the object that is passed
returns the newly constructed Object.
(outlined better by douglas crockford himself in the prototypal inheritance link)
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
newObject = Object.create(oldObject);
So using your code...
var a = Object.create(MODULE_TWO),
var b = Object.create(MODULE_TWO);
Answering based on your last edit, you could use something like this:
function Class(ctor, parent) {
var c = Function.prototype.call;
function clas() {
// expose the parent as super
this.super = parent;
ctor.apply(this, arguments);
}
// save the constructor
clas.constructor = ctor;
// provide a static constructor
clas.init = function() {
c.apply(parent.constructor, arguments);
};
// Setup the prototype
clas.prototype = parent ? parent.prototype : {};
// provide an extend method
clas.extend = function(methods) {
for(var i in methods) {
if (methods.hasOwnProperty(i)) {
clas.prototype[i] = methods[i];
}
}
return clas;
};
return clas;
}
Examples:
var Animal = Class(function(name) {
this.name = name;
});
var Cat = Class(function(name) {
this.super(name);
}, Animal).extend({
meow: function() {
console.log('Meow! My name is ' + this.name + '.');
}
});
new Cat('Neko').meow();
There are at least a trillion different ways to implement "Classes" in JavaScript, the more you want to hide the internals the more "magical" the code becomes, the above is very simple though.
You can (and probably need) customize this to fit your needs. But always keep in mind that there might be situations where a full blown Class emulation approach might not be the best one.
I already posted it as a comment, but in case you want to have everything hidden away for you, I've written a pretty feature rich, but still fast, Class library my own:
https://github.com/BonsaiDen/neko.js

Categories

Resources