Javascript: better way to add dynamic methods? - javascript

I'm wondering if there's a better way to add dynamic methods to an existing object. Basically, I am trying to assemble new methods dynamically and then append them to an existing function.
This demo code works.
builder = function(fn, methods){
//method builder
for(p in methods){
method = 'fn.' + p + '=' + methods[p];
eval(method);
}
return fn;
}
test = {}
test = builder(test, {'one':'function(){ alert("one"); }','two':'function(){ alert("two"); }'} );
test.one();
test.two();

You don't need to eval them each time.
You can create existing function objects, then assign them as properties to your objects.
var methods = {
'increment': function() { this.value++; },
'display' : function() { alert(this.value); }
};
function addMethods(object, methods) {
for (var name in methods) {
object[name] = methods[name];
}
};
var obj = { value: 3 };
addMethods(obj, methods);
obj.display(); // "3"
obj.increment();
obj.display(); // "4"
The canonical, object-oriented way however, is to use constructors and prototypes, but this isn't really dynamic in that each object you construct will have the same methods:
function MyObj(value) {
this.value = value;
};
MyObj.prototype.increment = function() {
this.value++;
};
MyObj.prototype.display = function() {
alert(this.value);
}
var obj = new MyObj(3);
obj.display(); // "3"
obj.increment();
obj.display(); // "4"

mhmh - I may be a bit late, but anyway:
new Function(argName1,...,argNameN, body)
for example:
x = new Function("y","return y*5");
x(3)
not much better than eval, though.
(it's a pity, but strings are used as code-description, not something more structured as in LISP)

If you need an object dynamically based on specific types... For instance:
var logTypes = ["fatal", "error", "warning", "info", "trace", "debug", "profile"];
Then you can keep a reference of the "this" object output and use it inside the methods.
function CustomLogger () {
var outter = this;
// creating the logger methods for all the log types and levels
_.each(logTypes, function (logType) {
outter[logType] = function (msg) {
console.log("[%s] %s", logType, msg);
};
});
}
That way, you can get the new dynamic methods...
var logger = new CustomLogger();
logger.info("Super cool!");
This will output the following:
"[info] Super cool!"

Your example could be accomplished without strings:
builder = function(fn, methods){
//method builder
for(p in methods){
fn[p] = methods[p];
}
return fn;
}
test = {}
test = builder(test, {'one': function(){ alert("one"); },'two':function(){ alert("two"); }} );
test.one();
test.two();
I'm not sure how you are assembling these methods, but avoid using strings if you can. There is probably a better way.

Do you have to build the methods from a string? If not there are plenty of ways including adding the methods to an object prototype or the object definition directly. Most of all the common javascript libraries have methods for defining objects/methods on existing or creating "namespaces". Check out YUI/Prototype/jQuery etc for examples of how they implement.
Otherwise if you have to build from a string then evaling may be the best method for dynamically adding methods to an object definition.

Related

Unable to have get and set method in Object Constructor (not in class) in JavaScript? [duplicate]

I recently read about the fact that there is a possibility of defining getters/setters in JavaScript. It seems extremely helpful - the setter is a kind of 'helper' which can parse the value to be set first, before actually setting it.
For example, I currently have this code:
var obj = function(value) {
var test = !!value; // 'test' has to be a boolean
return {
get test() { return test },
set test(value) { test = !!value }
};
};
var instance = new obj(true);
This code always converts value to a boolean. So if you code instance.test = 0, then instance.test === false.
However, for this to work you have to actually return an object, which means that the new instance is not of type obj but just is a plain object. This means that changing the prototype of obj has no effect on instances. For example, this does not work - instance.func is undefined:
obj.prototype.func = function() { console.log(this.value); };
because instance is not of type obj. To get the prototype functions work, I guess I should not return a plain object, but rather not return anything so that instance would just be of type obj, like a regular constructor works.
The problem then is how to implement getters/setters? I can only find articles describing how to add these to an object, not as being part of the constructor of a custom type.
So how do I implement getters/setters in the constructor so as to be able to both use getters/setters and extending the prototype?
You can't do that.
You can set setter/getters for properties of objects though. I advice you use ES5 Object.defineProperties though. of course this only works in modern browsers.
var obj = function() {
...
Object.defineProperties(this, {
"test": {
"get": function() { ... },
"set": function() { ... }
}
});
}
obj.prototype.func = function() { ... }
var o = new obj;
o.test;
o.func();
Usually you want class methods. The answer by #Raynos on May 7, 2011 gets the job done, but it defines an instance method, not a class method.
The following illustrates a class definition with a the getter and setter being part of the class. This definition is a lot like the answer by #Raynos, but with two differences in the code: (1) The "defineProperties()" action has been moved out of the constructor. (2) The argument to "defineProperties()"as been changed from the instance object "this", to the constructor's prototype object.
function TheConstructor(side) {
this.side = side;
}
Object.defineProperties(TheConstructor.prototype, {
area: {
get: function() { return this.side * this.side; }
,set: function(val) { this.side = Math.sqrt(val); }
}
});
// Test code:
var anInstance = new TheConstructor(2);
console.log("initial Area:"+anInstance.area);
anInstance.area = 9;
console.log("modified Area:"+anInstance.area);
Which produces these results:
initial Area:4
modified Area:9
Although usually the distinction between class versus instance
definition is just a matter of style, there is a purpose to
good style, and there is a case where the distinction matters:
the memoized getter. The purpose for a memoized getter is
described here: Smart/self-overwriting/lazy getters
Define the getter at the class level when the memoized value is to
pertain to the entire class. For example, a configuration file
should be read only once; the resulting values should then apply
for the duration of the program. The following sample code
defines a memoized getter at the class level.
function configureMe() {
return 42;
}
Object.defineProperties(TheConstructor.prototype, {
memoizedConfigParam: {
get: function() {
delete TheConstructor.prototype.memoizedConfigParam;
return TheConstructor.prototype.memoizedConfigParam = configureMe();
}
,configurable: true
}
});
// Test code:
console.log("memoizedConfigParam:"+anInstance.memoizedConfigParam);
Produces:
memoizedConfigParam:42
As can be seen in the example, memoized getters have the
characteristic that the getter function deletes itself,
then replaces itself with a simple value that
(presumably) will never change.
Note that 'configurable' must be set to 'true'.
Define the getter at the instance level when the memoized value
depends upon the contents of instance. The definition moves
inside the constructor, and the object of attention is 'this'.
function TheConstructorI(side) {
this.side = side;
Object.defineProperties(this, {
memoizedCalculation: {
get: function() {
delete this.memoizedCalculation;
return this.memoizedCalculation = this.expensiveOperation();
}
,configurable: true
}
});
}
TheConstructorI.prototype.expensiveOperation = function() {
return this.side * this.side * this.side;
}
//Test code:
var instance2 = new TheConstructorI(2);
var instance3 = new TheConstructorI(3);
console.log("memoizedCalculation 2:"+instance2.memoizedCalculation);
console.log("memoizedCalculation 3:"+instance3.memoizedCalculation);
Produces:
memoizedCalculation 2:8
memoizedCalculation 3:27
If you want to guarantee (rather than presume) that the memoized
value will never be changed, the 'writable' attribute needs to
be changed. That makes the code a bit more complicated.
function TheConstructorJ(side) {
this.side = side;
Object.defineProperties(this, {
memoizedCalculation: {
get: function() {
delete this.memoizedCalculation;
Object.defineProperty( this, 'memoizedCalculation'
,{ value : this.expensiveOperation()
,writable : false
});
return this.memoizedCalculation;
}
,configurable: true
}
});
}
TheConstructorJ.prototype.expensiveOperation = function() {
return this.side * this.side * this.side;
}
//Test code:
var instanceJ = new TheConstructorJ(2);
console.log("memoizedCalculation:"+instanceJ.memoizedCalculation);
instanceJ.memoizedCalculation = 42; // results in error
Produces:
memoizedCalculation:8
>Uncaught TypeError: Cannot assign to read only property 'memoizedCalculation' of object '#<TheConstructorJ>'
The OP's original question, from March 7, 2011, presented basic
getter and setter syntax, noted that it worked on an object but
not on 'this', and asked how to define getters and setters within
a constructor. In addition to all the examples above, there is
also a "cheap-shot" way of doing it: create a new object within
the constructor, like the OP did, but then assign the object to
be a member within 'this'. So, the original code would look like
this:
var MyClass = function(value) {
var test = !!value; // 'test' has to be a boolean
this.data = {
get test() { return test },
set test(value) { test = !!value }
};
};
var instance = new MyClass(true);
// But now 'data' is part of the access path
instance.data.test = 0;
console.log(instance.data.test);
Produces:
false
Believe it or not, I have actually run into situations where
this "cheap-shot" is the best solution. Specifically, I used this
technique when I had records from several tables encapsulated within
a single class, and wanted to present a unified view as though
they were a single record called 'data'.
Have fun.
IAM_AL_X
Update for ES6 -- have a look at section 19.3.1 of Alex Rauschmayer's book Exploring ES6 http://exploringjs.com/es6/ch_maps-sets.html#sec_weakmaps-private-data which demonstrates how to use WeakMaps with getters and setters to hold private data. Combining with section 16.2.2.3 http://exploringjs.com/es6/ch_classes.html#leanpub-auto-getters-and-setters would result in something like
# module test_WeakMap_getter.js
var _MyClassProp = new WeakMap();
class MyClass {
get prop() {
return _MyClassProp.get( this );
}
set prop(value) {
_MyClassProp.set( this, value );
}
}
var mc = new MyClass();
mc.prop = 5 ;
console.log( 'My value is', mc.prop );
$ node --use_strict test_WeakMap_getter.js
My value is 5
function Obj(value){
this.value = !!value;
}
Obj.prototype = {
get test () {
return this.value;``
},
set test (value) {
this.value = !!this.value;
}
};
var obj = new Obj(true);
I know this might be extremely late but I figured out a different way to accomplish what you want and for the sake of people, like myself, googling for an answer to this here it is.
function Constructor(input){
this.input = input;
}
Object.__defineGetter__.call(Constructor.prototype, "value", function(){
return this.input * 2;
});
var test = new Constructor(5);
alert(test.value) // 10
I've tested this in chrome, safari, mobile safari, firefox and they all work (latest versions of course)
#Alex I see it as more option and more power, programming is art, #Nat share his finding with us, and for that I thank him. Maybe someone want to do it that way.
I'm sure the setter version is the same but just changing that g to a s.
i.g:
function Constructor(input){
this.input = input;
}
Object.__defineGetter__.call(Constructor.prototype, "value", function(){
return this.input * 2;
});
Object.__defineSetter__.call(Constructor.prototype, "bar", function(foo){
return this.input *= foo;
});
var test = new Constructor(5);
console.log(test.value); // 10
test.bar = 5;
console.log(test.input); //25
With that said, this feature is deprecated, advices to not to use in production coding.

reusable javascript objects, prototypes and scope

MyGlobalObject;
function TheFunctionICanUseRightAwaySingleForAllInstansesAndWithoutInstanse() {
function() {
alert('NO CONSTRUCTOR WAS CALLED');
}
};
The Long-named function must be callable from MyGlobalObject, which in turn must be available as a global (to window) variable in all times after script was loaded. It should support extensibility in accordance with latest standards.
I'm at architectural dilemma of how to built JS base for an application (almost 100% JS).
We need an object i.e. window.MyObject (like a module, like jQuery) so
It can be created with
VAR1
var MyGlobalObjConstructor = function(){
this.GlobalFunctionInObject = function(){
alert('called with MyGlobalObj.GlobalFunctionInObject()');
}
};
window.MyGlobalObj = new MyGlobalObjConstructor();
Is MyGlobalObj extensible? Can I create child objects, which will inherit current state of MyGlobalObj (extended functions/properties MyGlobalObj.NewFunc e.g.)? What is the main difference between using prototype (VAR3)?
By GlobaldFunction I mean single instance for all initialized/instantiated (possibly instantializable) instances..
Or with
VAR2
var MyGlobalObj = {
GlobalFunctionInObject: function...
GlobalFunctionInObject2: function...
};
MyGlobalObj.GlobalFunctionInObject();
// here I lose all hierarchy elements, no prototype,
// can I use GlobalFunctionInObject2 in GlobalFunctionInObject?
Or with
VAR3
var MyGlobalConstuctor = function(){} // already 'well-formed' object
MyGlobalConstuctor.prototype.GlobalFunctionInObject = function...
};
var MyGlobalObj = new MyGlobalConstuctor();
// so I'm sceptical to NEW, because I have ALREADY wrote my functions
// which I expect to be in memory, single instance of each of them,
// so creating MyObject2,3,4 with NEW MyGC() makes no sense to me.
// DO I REALLY HAVE TO USE "MyGlobalConstuctor.prototype." FOR EACH FUNCTION?!!!!
What's the difference defining MyGlobalObj as a function and as an object (result of func or VAR2)?
OR VAR4?
I see in Chrome Debugger both prototype and __proto__ special fields. I've read that that's OK, but why are they not saved in a single prototype?
So, what is the correct/optimal way to implement window.MyObject, so one could MyObject.MyFunction(); What are the differences (pro/contra) of variants 1 2 and 3?
Variation 1 - Mixin
function SomeType() {
var priv = "I'm private";
this.publ = "I'm public";
this.action = function() {
return priv + this.publ;
};
}
var obj = new SomeType();
With this method you are creating a new object every time you call new SomeType(), creating all its methods and adding all this method to the new object. Every time you create an object.
Pros
It looks like classical inheritance so it's easy to understand to Java-C#-C++-etc people.
It can have private variables per instance since you have one function closure per each object you create
It allows multiple inheritance, also known as Twitter-mixins or functional mixins
obj instanceof SomeType will return true
Cons
It consumes more memory as more objects you create because with each object you are creating a new closure and creating each of it's methods again.
Private properties are private, not protected, subtypes can't access them
No easy way to know if a object has some Type as superclass.
Inheritance
function SubType() {
SomeType.call(this);
this.newMethod = function() {
// can't access priv
return this.publ;
};
}
var child = new SubType();
child instanceof SomeType will return false there is no other way to know if child has SomeType methods than look if it has them one by one.
Variation 2 - Object literal with prototyping
var obj = {
publ: "I'm public",
_convention: "I'm public too, but please don't touch me!",
someMethod: function() {
return this.publ + this._convention;
}
};
In this case you are creating a single object. If you are going to need only one instance of this type it can be the best solution.
Pros
It's quick and easy to understand.
Performant
Cons
No privacy, every property is public.
Inheritance
You can inherit a object prototyping it.
var child = Object.create(obj);
child.otherMethod = function() {
return this._convention + this.publ;
};
If you are on a old browser you will need to garantee Object.create works:
if (!Object.create) {
Object.create = function(obj) {
function tmp() { }
tmp.prototype = obj;
return new tmp;
};
}
To know if a object is a prototype of another you can use
obj.isPrototypeOf(child); // true
Variation 3 - Constructor pattern
UPDATE: This is the pattern ES6 classes are sugar syntax of. If you use ES6 classes you are following this pattern under the hood.
class SomeType {
constructor() {
// REALLY important to declare every non-function property here
this.publ = "I'm public";
this._convention = "I'm public too, but please don't touch me!";
}
someMethod() {
return this.publ + this._convention;
}
}
class SubType extends SomeType {
constructor() {
super(/* parent constructor parameters here */);
this.otherValue = 'Hi';
}
otherMethod() {
return this._convention + this.publ + this.otherValue;
}
}
function SomeType() {
// REALLY important to declare every non-function property here
this.publ = "I'm public";
this._convention = "I'm public too, but please don't touch me!";
}
SomeType.prototype.someMethod = function() {
return this.publ + this._convention;
};
var obj = new SomeType();
You can re-assign the prototype insteadd of adding each method if you are not inheriting and remember to re-assign the constructor property:
SomeType.prototype = {
constructor: SomeType,
someMethod = function() {
return this.publ + this._convention;
}
};
Or use _.extend or $.extend if you have underscore or jquery in your page
_.extend(SomeType.prototype, {
someMethod = function() {
return this.publ + this._convention;
}
};
The new keyword under the hood simply does this:
function doNew(Constructor) {
var instance = Object.create(Constructor.prototype);
instance.constructor();
return instance;
}
var obj = doNew(SomeType);
What you have is a function than has no methods; it just has a prototype property with a list of functions, the new operator means to create a new object and use this function's prototype (Object.create) and constructor property as initializer.
Pros
Performant
Prototype chain will allow you to know if a object inherits from some type
Cons
Two-step inheritance
Inheritance
function SubType() {
// Step 1, exactly as Variation 1
// This inherits the non-function properties
SomeType.call(this);
this.otherValue = 'Hi';
}
// Step 2, this inherits the methods
SubType.prototype = Object.create(SomeType.prototype);
SubType.prototype.otherMethod = function() {
return this._convention + this.publ + this.otherValue;
};
var child = new SubType();
You may think it looks like a super-set of Variation 2... and you'll be right. It's like variation 2 but with a initializer function (the constructor);
child instanceof SubType and child instanceof SomeType will return both true
Curiosity: Under the hood instanceof operator does is
function isInstanceOf(obj, Type) {
return Type.prototype.isPrototypeOf(obj);
}
Variation 4 - Overwrite __proto__
When you do Object.create(obj) under the hood it does
function fakeCreate(obj) {
var child = {};
child.__proto__ = obj;
return child;
}
var child = fakeCreate(obj);
The __proto__ property modifies directly the object's hidden [Prototype] property. As this can break JavaScript behaviour, it's not standard. And the standard way is preferred (Object.create).
Pros
Quick and performant
Cons
Non-standard
Dangerous; you can't have a hashmap since the __proto__ key can change the object's prototype
Inheritance
var child = { __proto__: obj };
obj.isPrototypeOf(child); // true
Comment questions
1. var1: what happens in SomeType.call(this)? Is 'call' special function?
Oh, yes, functions are objects so they have methods, I will mention three: .call(), .apply() and .bind()
When you use .call() on a function, you can pass one extra argument, the context, the value of this inside the function, for example:
var obj = {
test: function(arg1, arg2) {
console.log(this);
console.log(arg1);
console.log(arg2);
}
};
// These two ways to invoke the function are equivalent
obj.test('hi', 'lol');
// If we call fn('hi', 'lol') it will receive "window" as "this" so we have to use call.
var fn = obj.test;
fn.call(obj, 'hi', 'lol');
So when we do SomeType.call(this) we are passing the object this to function SomeCall, as you remember this function will add methods to object this.
2. var3: With your "REALLY define properties" do you mean if I use them in functions? Is it a convention? Because getting this.newProperty without it being defined at the same level with other member functions is not a problem.
I mean any property your object will have that is not a function must be defined on the constructor, not on the prototype, otherwise you will face one of the more confusing JS problems. You can see it here, but it's outside of the focus of this question.
3. Var3: what happens if I don't re-assign constructor?
Actually you might not see the difference and this is what makes it a dangerous bug. Every function's prototype object has a constructor property so you can access the constructor from an instance.
function A() { }
// When you create a function automatically, JS does this:
// A.prototype = { constructor: A };
A.prototype.someMethod = function() {
console.log(this.constructor === A); // true
this.constructor.staticMethod();
return new this.constructor();
};
A.staticMethod = function() { };
It's not a best practice because not everybody knows about it, but sometimes it helps. But if you reassign the prototype...
A.prototype = {
someMethod = function() {
console.log(this.constructor === A); // false
console.log(this.constructor === Object); // true
this.constructor.staticMethod();
return new this.constructor();
}
};
A.prototype is a new object, a instance of Object than prototypes Object.prototype and Object.prototype.constructor is Object. Confusing, right? :P
So if you overwrite the prototype and don't reset the "constructor" property, it will refer to Object instead of A, and if you try to use the "constructor" property to access some static method you may get crazy.
I usually settle with returning an object with functions as properties:
var newCat = function (name) {
return {name: name, purr: function () {alert(name + ' purrs')}};
};
var myCat = newCat('Felix');
myCat.name; // 'Felix'
myCat.purr(); // alert fires
You can have inheritance by calling the newCat function and extend the object you get:
var newLion = function (name) {
var lion = newCat(name);
lion.roar = function () {
alert(name + ' roar loudly');
}
return lion;
}
If you want a global cats object:
var cats = (function () {
var newCat = function (name) {
return {
name: name,
purr: function () {
alert(name + ' is purring')
}
};
};
return {
newCat: newCat
};
}());
Now you can call:
var mySecondCat = cats.newCat('Alice');

Crockford's Prototypical Inheritance - Usage

I've been building a small JS framework for use at my job, and I'd like to employ Douglas Crockford's prototypical inheritance patterns. I think I get the general idea of how the prototype object works, but what isn't clear is the way in which I would use this pattern beyond the simplest example.
I'll flesh it out to the point that I understand it.
(function () {
'use strict';
var Vehicles = {};
Vehicles.Vehicle = function () {
this.go = function () {
//go forwards
};
this.stop = function () {
//stop
};
};
Vehicles.Airplane = Object.create(Vehicles.Vehicle());
}());
So now my Vehicles.Airplane object can go() and stop(), but I want more. I want to add takeOff() and land() methods to this object. I could just use ugly dot notation afterwards:
Vehicles.Airplane.takeOff = function () {
//take off stuff
}
But that seems wrong, especially if I were to add many methods or properties. The question asked at here seems to be very similar to mine, but the answer doesn't quite ring true for me. The answer suggests that I should build an object literal before using Object.create, and that I should pass that object literal into the create method. In the example code given, however, it looks like their new object inherits nothing at all now.
What I'm hoping for is some syntax similar to:
Vehicles.Airplane = Object.create(Vehicles.Vehicle({
this.takeOff = function () {
//takeOff stuff
};
this.land = function () {
//land stuff
};
}));
I know this syntax will break terribly with Object.create right now, because of course I'm passing Vehicle.Vehicle a function rather than an object literal. That's beside the point. I'm wondering in what way I should build new properties into an object that inherits from another without having to list them out one at a time with dot notation after the fact.
EDIT:
Bergi, after some anguished thought on the topic, I think I really want to go with what you described as the "Classical Pattern". Here is my first stab at it (now with actual code snippets rather than mocked up hypotheticals - You even get to see my crappy method stubs):
CS.Button = function (o) {
o = o || {};
function init(self) {
self.domNode = dce('a');
self.text = o.text || '';
self.displayType = 'inline-block';
self.disabled = o.disabled || false;
self.domNode.appendChild(ctn(self.text));
if (o.handler) {
self.addListener('click', function () {
o.handler(self);
});
}
}
this.setText = function (newText) {
if (this.domNode.firstChild) {
this.domNode.removeChild(this.domNode.firstChild);
}
this.domNode.appendChild(ctn(newText));
};
init(this);
};
CS.Button.prototype = Object.create(CS.Displayable.prototype, {
constructor: {value: CS.Button, configurable: true}
});
CS.Displayable = function (o) { // o = CS Object
o = o || {};
var f = Object.create(new CS.Element(o));
function init(self) {
if (!self.domAnchor) {
self.domAnchor = self.domNode;
}
if (self.renderTo) {
self.renderTo.appendChild(self.domAnchor);
}
}
//Public Methods
this.addClass = function (newClass) {
if (typeof newClass === 'string') {
this.domNode.className += ' ' + newClass;
}
};
this.addListener = function (event, func, capture) {
if (this.domNode.addEventListener) {
this.domNode.addEventListener(event, func, capture);
} else if (this.domNode.attachEvent) {
this.domNode.attachEvent('on' + event, func);
}
};
this.blur = function () {
this.domNode.blur();
};
this.disable = function () {
this.disabled = true;
};
this.enable = function () {
this.disabled = false;
};
this.focus = function () {
this.domNode.focus();
};
this.getHeight = function () {
return this.domNode.offsetHeight;
};
this.getWidth = function () {
return this.domNode.offsetWidth;
};
this.hide = function () {
this.domNode.style.display = 'none';
};
this.isDisabled = function () {
return this.disabled;
};
this.removeClass = function (classToRemove) {
var classArray = this.domNode.className.split(' ');
classArray.splice(classArray.indexOf(classToRemove), 1);
this.domNode.className = classArray.join(' ');
};
this.removeListener = function () {
//Remove DOM element listener
};
this.show = function () {
this.domNode.style.display = this.displayType;
};
init(this);
};
CS.Displayable.prototype = Object.create(CS.Element.prototype, {
constructor: {value: CS.Displayable, configurable: true}
});
I should be quite clear and say that it's not quite working yet, but mostly I'd like your opinion on whether I'm even on the right track. You mentioned "instance-specific properties and methods" in a comment in your example. Does that mean that my this.setText method and others are wrongly placed, and won't be available to descendant items on the prototype chain?
Also, when used, it seems that the order of declaration now matters (I can't access CS.Displayable.prototype, because (I think) CS.Button is listed first, and CS.Displayable is undefined at the time that I'm trying to reference it). Is that something I'll just have to man up and deal with (put things in order of ancestry in the code rather than my OCD alphabetical order) or is there something I'm overlooking there as well?
Vehicles.Airplane = Object.create(Vehicles.Vehicle());
That line is wrong. You seem to want to use new Vehicles.Vehicle - never call a constructor without new!
Still, I'm not sure which pattern you want to use. Two are coming to my mind:
Classical Pattern
You are using constructor functions just as in standard JS. Inheritance is done by inheriting the prototype objects from each other, and applying the parent constructor on child instances. Your code should then look like this:
Vehicles.Vehicle = function () {
// instance-specific properties and methods,
// initialising
}
Vehicles.Vehicle.prototype.go = function () {
//go forwards
};
Vehicles.Vehicle.prototype.stop = function () {
//stop
};
Vehicles.Airplane = function() {
// Vehicles.Vehicle.apply(this, arguments);
// not needed here as "Vehicle" is empty
// maybe airplane-spefic instance initialisation
}
Vehicles.Airplane.prototype = Object.create(Vehicles.Vehicle.prototype, {
constructor: {value:Vehicles.Airplane, configurable:true}
}); // inheriting from Vehicle prototype, and overwriting constructor property
Vehicles.Airplane.prototype.takeOff = function () {
//take off stuff
};
// usage:
var airplane = new Vehicles.Airplace(params);
Pure Prototypical Pattern
You are using plain objects instead of constructor functions - no initialisation. To create instances, and to set up inheritance, only Object.create is used. It is like having only the prototype objects, and empty constructors. instancof does not work here. The code would look like this:
Vehicles.Vehicle = {
go: function () {
//go forwards
},
stop: function () {
//stop
}
}; // just an object literal
Vehicles.Airplane = Object.create(Vehicles.Vehicle); // a new object inheriting the go & stop methods
Vehicles.Airplane.takeOff = function () {
//take off stuff
};
// usage:
var airplane = Object.create(Vehicles.Airplane);
airplane.prop = params; // maybe also an "init" function, but that seems weird to me
You got Object.create wrong. The first argument should be an object (maybe that's why people suggested you pass a literal).
In your first example, you're actually passing undefined:
Vehicles.Airplane = Object.create(Vehicles.Vehicle()); // the function call will
// return undefined
The following would work, but it's not very Crockford-ish:
Vehicles.Airplane = Object.create(new Vehicles.Vehicle());
The way I believe Crockford would do it (or, at least, wouldn't complain of):
var Vehicles = {};
Vehicles.Vehicle = {
go : function() {
// go stuff
},
stop : function() {
// go stuff
}
};
Vehicles.Airplane = Object.create(Vehicles.Vehicle, {
takeOff : {
value : function() {
// take-off stuff
}
},
land : {
value: function() {
// land stuff
}
}
});
Note that Vehicles.Vehicle is just a literal, which will be used as the prototype for other objects. When we call Object.create, we pass Vehicles.Vehicle as the prototype, and takeOff and land will be own properties of Vehicles.Airplane. You may then call Object.create again, passing Vehicles.Airplane as the prototype, if you want to create e.g. a Boeing.
The own properties passed as the second parameter are packed in an object that contains a representation of their property descriptors. The outer keys are the names of your properties/methods, and each one points to another object containing the actual implementation as the value. You may also include other keys like enumerable; if you don't they'll take the default values. You can read more about descriptors on the MDN page about Object.defineProperty.

What are some idiomatic ways to create custom Javascript objects

I am creating a custom object to be used in some internal applications where I work. I researched some ways to go about doing this - and this is what I came out with.
function ISGrader(text)
{
this.text = text;
this.printInfo = function(){
alert("Object working " + text);
}
this.putGrade = function(score)
{
alert(score);
}
}
I believe this shows constructor-type functionality, as well as some simple starter methods that I will build on.
Is the above good practice or is there another way that is more standard?
I prefer a pattern similar to the one below. You can think of it as a 4-step approach:
(function(parent) {
// 1. Declare private variables and functions that will be
// accessible by everybody within the scope of this
// function, but not outside of it.
var doSomethingAwesome = function() { .. }; // private function
var coolInteger = 42; // private variable
// 2. Create the constructor function
function ISGrader() {
..
}
// 3. Create shared public methods on the prototype object.
// These will be created only once, and shared between all objects
// which is more efficient that re-creating each method for each object.
ISGrader.prototype.printInfo = function() { .. };
ISGrader.prototype.putGrade = function(score) { .. };
// 4. Expose the constructor to the outside world.
parent.ISGrader = ISGrader;
})(window);
The reason why everything is enclosed inside a self-executing anonymous function is to ensure the private variables we create inside don't leak outside to the enclosing scope, and to basically keep things clean.
Another benefit of declaring the constructor like this is that you can change the parent object easily from say window to a further namespaced object by changing a single word.
I prefer this pattern (IIFE), but it is purely opinion:
var ISGrader = (function (text) {
// anything declared here is "private"
var printInfo = function() {
alert("Object working " + text);
};
var putGrade = function (score) {
alert(score);
};
// put "publicly" accesible things in the returned object
return {
text: text,
printInfo: printInfo,
putGrade: putGrade
};
})(text);
It is always recommended to do it using `prototype'. This way you can also inherit it's properties and create new one.
var ISGrader = function(text) {
this.text = text;
var _privateVar = text;
this.updatePrivateVar = function(newText) {
_privateVar = newText;
alert("private variable updated");
}
}
ISGrader.prototype.text = "";
ISGrader.prototype.printInfo = function() {
alert("Object working " + this.text);
}
ISGrader.prototype.putGrade = function(score) {
alert(score);
}
var isGrader = new ISGrader("hello");
isGrader.printInfo();
// Inherit and create a new definition
var ISGrader2 = function() {}
ISGrader2.prototype = new ISGrader();
var isGrader2 = new ISGrader("hello2");
isGrader2.printInfo();
isGrader2.updatePrivateVar("hello3");
demo : http://jsfiddle.net/rkspP/3/
While not really an answer, I recommend Douglas Crockford's book JavaScript: The Good Parts as it does a good job of introducing you to the "good parts" of the language and discusses the pros and cons of the different ways to create objects in JavaScript.
You can also review this resource if you're just looking for an explanation of member visibility in JavaScript objects: http://javascript.crockford.com/private.html
If you are planning on creating multiple ISGrader objects on a single page, it's more memory efficient to stick the functions in a prototype object assigned to ISGrader like this:
function ISGrader(text) {
this.text = text;
}
ISGrader.prototype = {
printInfo: function() {
alert("Object working " + this.text);
},
putGrade: function(score) {
alert(score);
}
}

Understanding Classes and Inheritance in Javascript - New Pattern

I'm designing an OOP inheritance pattern for many applications I'm building. Javascript has many ways of doing this, but I stumbled on a pattern I really like. But now I'm struggling with the need for a separation of classes and instances.
I have a base object called Root. And it has a main method called inherit. To create a new object you use
var Person = Root.inherit({
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
Then to create an "instance" you would
var sally = Person.inherit({
name : "sally",
height : "5'6"
});
sally can .talk() and she can walk() and she has a .name and a .height
You can make more people the same way.
If you want a constructor you use
var Person = Root.inherit({
_construct : function() {
// do things when this object is inherited from
},
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
It also has the ability to have init, when the object is first defined in code (singletons use this)
var Person = Root.inherit({
_init : function() {
// called at runtime, NOT called if an object is inherited from me
},
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
So as you can see, everything uses .inhert(). There are no classes and no instances really. Everything is an instance of something. The only real problem I found so far is that there is no concept of "type", but you can always just check for a method if you need to. Also you can't protect a 'class', as a 'class' can be changed during execution if the developer accidentally changed it, or meant to change it.
So my question is: Is there a need in javascript to have an explicitly and controlled separation of class structure and instances of the class? Are there any issues with treating every object as an instance?
No there's no need since Javascript is a Prototypal based language, meaning that classes are not involved. You are just creating clones of the objects.
http://en.wikipedia.org/wiki/Prototype-based_programming
As far as the concept of type, the type is object.
A good read for more info about this would be Javascript Patterns by Stoyan Stefanov he has several different creational patterns that address your concerns, including examples that implement Design Patterns from the gang of four's design patterns.
http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752
So my question is: Is there a need in javascript to have an explicitly and controlled separation of class structure and instances of the class? Are there any issues with treating every object as an instance?
Not really, if you're happy with it, it's fine.
The more normal form of JavaScript inheritance does much the same thing. You'll frequently see structures like this (severely cut down for brevity):
function Base() {
}
Base.prototype.foo = function() {
};
function Derived() {
}
Derived.prototype = new Base();
...and of course, new Base() is also how you create instances of Base. So your system is quite similar.
Again, the above is a sketch, not a full example. For one thing, usually you'd see construction and initialization separated out, so you don't literally see Derived.prototype = new Base() so much as something that creates an object with Base's prototype but without actually calling Base (which Derived would do later), but you get the idea. Granted that statement somewhat weakens the similarity with your system, but I don't think it breaks it at all.
At the end of the day, it's all about objects (instances), which are either used directly (your sally) or indirectly by providing features to other objects (Person, Root) by cloning or by setting them up as the prototype of the other object.
Javascript's inheritance is prototypical which means everything object is an instance. You actually have to do extra work to get the classical inheritance.
This is how I work in javascript
// this is class
function person(){
// data is member variable
this.name = null;
this.id = null;
//member functions
this.set_name = _set_name;
this.get_name = _get_name;
this.set_id = _set_id;
this.get_id = _get_id;
function _set_name(name){
this.name = name;
}
function _get_name(name){
return this.name;
}
function _set_id(id){
this.id = id;
}
function _get_id(id){
return this.id;
}
}
// this is instance
var yogs = new person();
yogs.set_id(13);
yogs.set_name("yogs");
hope it may help
Start with some basic object...
// javascript prototypes - callback example - javascript objects
function myDummyObject () {
that = this;
} // end function myDummyObject ()
// begin dummy object's prototype
myDummyObject.prototype = {
that : this,
// add a simple command to our dummy object and load it with a callback entry
say : function () {
var that = this;
console.log('speaking:');
that.cb.run("doSay");
}
} // end myDummyObject proto
extend with a sub prototype..
// here we addon the callback handler... universally self sufficient object
var cb = {
that : this, // come to papa ( a link to parent object [ myDummyObject ] )
jCallback : new Array(new Array()), // initialize a javascript 2d array
jCallbackID : -1, // stores the last callback id
add: function(targetFnc, newFunc) {
var that = this;
var whichID = that.jCallbackID++;
// target, addon, active
that.jCallback[that.jCallback.length] = { 'targetFunc' : targetFnc, 'newFunc' : newFunc, 'active' : true, 'id': whichID };
return whichID; // if we want to delete this later...
}, // end add
run: function(targetFnc) {
var that = this;
for(i=0;i <= that.jCallback.length - 1;i++) // go through callback list
if( that.jCallback[i]['targetFunc'] == targetFnc && that.jCallback[i]['active'] == true )
that.jCallback[i]['newFunc'](); // run callback.
}, // end run
remove: function (whichID) {
var that = this;
console.log('removing:' + whichID);
for(i=0;i <= that.jCallback.length - 1;i++) // go through callback list
if( that.jCallback[i]['id'] == whichID )
that.jCallback[i]['newFunc'](); // run callback.
} // end remove
}
// add the object to the dummy object...
myDummyObject.prototype.cb = cb;
Example:
var testing = new myDummyObject();
testing.cb.add('doSay', function () { console.log('test: 213123123'); } );
// test remove...
var testid = testing.cb.add('doSay', function () { console.log('test: 12sad31'); } );
testing.cb.remove(testid);
testing.cb.add('doSay', function () { console.log('test: asdascccc'); } );
testing.cb.add('doSay', function () { console.log('test: qweqwe'); } );
testing.cb.add('doSay', function () { console.log('test: d121d21'); } );
testing.cb.add('doSay', function () { console.log('test: wwww'); } );
testing.say();
This always seemed the easiest for me to understand... Just create a new instance of the inherited class and then loop through its variables and methods and add them to the main one.
var myPerson = new Person()
var myPerson.firstName = 'john';
var myPerson.lastName = 'smith';
var myPerson.jobTitle = 'Programmer';
var Person = function(){
//Use this to inherit classes
this._extendedClass = new Person_Job();
for(var i in this._extendedClass){
this[i] = this._extendedClass[i];
}
delete this._extendedClass;
this.firstName = '';
this.lastName = '';
}
var Person_Job = function() {
this.jobTitle = '';
}

Categories

Resources