I'm not very well aquainted with javascript inheritance, and I'm trying to make one object inherit from another, and define its own methods:
function Foo() {}
Foo.prototype = {
getColor: function () {return this.color;},
};
function FooB() {}
FooB.prototype = new Foo();
FooB.prototype = {
/* other methods here */
};
var x = new FooB().getColor();
However, the second one overwrites the first one(FooB.prototype = new Foo() is cancelled out). Is there any way to fix this problem, or am I going in the wrong direction?
Thanks in advance, sorry for any bad terminology.
Each object can only have one prototype, so if you want to add to the prototype after inheriting (copying) it, you have to expand it instead of assigning a new prototype. Example:
function Foo() {}
Foo.prototype = {
x: function(){ alert('x'); },
y: function(){ alert('y'); }
};
function Foo2() {}
Foo2.prototype = new Foo();
Foo2.prototype.z = function() { alert('z'); };
var a = new Foo();
a.x();
a.y();
var b = new Foo2();
b.x();
b.y();
b.z();
One solution would be:
function FooB() {}
var p = new Foo();
p.methodA = function(){...}
p.methodB = function(){...}
p.methodC = function(){...}
...
FooB.prototype = p;
Update: Regarding expanding with an existing object. You can always copy the existing properties of one object to another one:
FooB.prototype = new Foo();
var proto = {
/*...*/
};
for(var prop in proto) {
FooB.prototype[prop] = proto[prop];
}
As long as proto is a "plain" object (i.e. that does not inherit from another object) it is fine. Otherwise you might want to add if(proto.hasOwnProperty(prop)) to only add non-inherited properties.
You can use an extend function which copies the new members to the prototype object.
function FooB() {}
FooB.prototype = new FooA();
extend(FooB.prototype, {
/* other methods here */
});
extend
/**
* Copies members from an object to another object.
* #param {Object} target the object to be copied onto
* #param {Object} source the object to copy from
* #param {Boolean} deep whether the copy is deep or shallow
*/
function extend(target, source, deep) {
for (var i in source) {
if (deep || Object.hasOwnProperty.call(source, i)) {
target[i] = source[i];
}
}
return target;
}
Related
I just cleared my mind on JavaScript objects and my question is really simple for most of the people here. I feel comfortable with the JavaScript object literal notation like:
var Obj = {
/**
* #type {string}
*/
name: '',
/**
* setName
* Set the `name` property.
*
* #param param
*/
set setName (param) {
this.name = param;
}
};
The only limit I found is that if I want to create two completely separate objects in the same page, with this notation I can't.
var a = Obj;
a.setName = "John";
var b = Obj;
b.setName = "Peter";
// OUTPUT
// a.name -> Peter
// b.name -> Peter
Set var whatever = Obj is just useless, 'cause it doesn't instantiate n separate objects and it just overwrites the code above. Using new keyword such as var a = new Obj doesn't work neither (probably I'm using it in the wrong way?). The solution I came up with is returning the object inside a function, like:
function Obj() {
return {
/**
* #type {string}
*/
name: '',
/**
* setName
* Set the `name` property.
*
* #param param
*/
set setName (param) {
this.name = param;
}
}
}
This way I can create two different objects and correctly access to their properties and methods:
var a = Obj();
a.setName = "John";
var b = Obj();
b.setName = "Peter";
// OUTPUT
// a.name -> John
// b.name -> Peter
So, my question are:
Is what I've done conceptually right?
Is there a more correct/efficient way to achieve it?
Your concept of a function that returns an Object instance is valid, but your implementation is very brittle because it is only set up to work with specific properties. Read on for more details on various ways to create instances and a more flexible way to return objects...
var a = Obj; doesn't create a new object. It just assigns a the memory address of the existing object Obj.
var myObj = {}; // Object instance is created and memory location is stored in myObj
var a = myObj; // No new object is created. a and myObj point to the same object
console.log("Are 'a' and 'myObj' both pointing to the same object?", a === myObj); // true
If you want to design a single object and then make more of that object, you need to be able to create "instances" of an object. You can't do that directly with an object literal:
var myObj = {
someProp:10
};
var myNewObj = new myObj(); // Fails because an object literal can't be instantiated
But, you can do it with the Object.create() method, which takes your Obj concept to fruition:
// Object instance is created and memory location is stored in myObj
var myObj = {
someProp: "default",
// "Methods" are just properties with functions as their value
someMethod: function(input){
// The || syntax that follows allows for a default value for the method
// if no argument is passed to the method.
this.name = input || "default";
}
};
// Create a new Object instance and set myObj as the prototype of the instance.
// This means that the new instance will inherit from that prototype:
var a = Object.create(myObj);
console.log(a.someProp); // "default";
a.someProp = "something specific";
a.someMethod("Test");
myObj.someMethod();
console.log(a.name, myObj.name); // "Test" "default"
console.log(a.someProp, myObj.someProp); // "something specific", "default"
Instances can be explicitly made with the new operator and a constructor function:
function foo(){
this.someProp = "something";
}
var a = new foo(); // Unique instance of foo
var b = new foo(); // Separate and distinct instance of foo
a.someProp = 10;
b.someProp = 20;
console.log(a.someProp, b.someProp); // 10 20
Or, the new operator and a class:
class foo{
constructor(val) {
this.someProp = val;
}
}
var a = new foo(10); // Unique instance of foo
var b = new foo(20); // Separate and distinct instance of foo
console.log(a.someProp, b.someProp); // 10 20
Have you tried with Object.create() ?
var b = { setName : "Mongo" };
a = Object.create(b);
a.setName = "John";
b.setName = "Peter";
console.log(a.setName);
console.log(b.setName);
Here is a simple example of what I want :
var ConstBuilder = function() {
var constructor = function() {} ;
constructor.prototype = {} ;
return constructor ;
} ;
ConstBuilder.prototype = {
add : function(name, value) {
this.prototype[name] = value ;
}
} ;
var A = new ConstBuilder() ;
A.add('test', function() {
console.log('test') ;
}) ;
var a = new A() ;
a.test() ;
This code will fail as A is not an instance of ConstBuilder (because A comes from a returned var constructor = function() {} and won't have the methods defined in its prototype (add).
But this would be useful to modify the super constructor's prototype to have things like :
ConstBuilder.prototype.remove = function(name) {
delete this.prototype[name] ;
} ;
A.remove('test') ;
a.test ; // undefined
Is there a way to have a function as an instance of another ? So this function may implicitely "inherit" all the methods defined in its constructor's prototype.
Or if you have other suggestions, I aim to build modulable constructors - as instances with prototypes are.
Please make sure you have understood the difference between the .prototype property and the internal inheritance-prototype.
The code will fail as A is not an instance of ConstBuilder. Is there a way to have a function as an instance of another?
A is, as every constructor needs to be, a Function. So if you just define your add and remove methods on the Function.prototype, it will work:
Function.prototype.add = function(name, value) {
this.prototype[name] = value;
};
Function.prototype.remove = function(name) {
delete this.prototype[name];
};
function A() {}
A.add('test', function(){console.log('test');});
var a = new A();
a.test(); // test
A.remove('test');
a.test; // undefined
There is no possibility however to let a function inherit from something else than Function.prototype - see Can a JavaScript object have a prototype chain, but also be a function?. If you don't want to modify the native Function.prototype object, you still can use the mixin pattern:
var Constr = (function() {
function add(name, value) {
this.prototype[name] = value;
}
function remove(name) {
delete this.prototype[name];
}
return function mixin(c) {
c.add = add;
c.remove = remove;
return c;
};
})();
var A = Constr(function() {…});
A.add("test", …);
var a = new A();
a.test(); // test
I aim to build modulable constructors
You could use the builder pattern, as you just have seem to tried.
function ConstBuilder() {
this.prototype = {};
};
ConstBuilder.prototype = {
add: function(name, value) {
this.prototype[name] = value;
},
remove: function(name) {
delete this.prototype[name];
},
getConstructor: function() {
var constructor = function() {};
constructor.prototype = this.prototype;
this.prototype.constructor = constructor;
return constructor;
}
};
var A = new ConstBuilder().add('test', function() {
console.log('test');
}).getConstructor();
var a = new A();
a.test(); // test
To remove functions later, you would need to save a reference to the builder.
I think that you are looking for an example of how to do JavaScript's "prototypical inheritance". When JavaScript looks for a property on an object, it first checks the object itself. Next it checks the prototype. However, since everything in JavaScript is an object and the prototype is an object
function Root(){}
Root.prototype.fromRoot = function() { console.log("I'm on Root's prototype."); };
function Child(){}
Child.prototype = new Root();
Child.prototype.fromChild = function() { console.log("I'm on Child's prototype."); };
var r = new Root();
var c = new Child();
r.fromRoot(); // works
c.fromRoot(); // works
c.fromChild(); // works
r.fromChild(); // fails
function a (x,y,construct)
{
if (!construct) return;
this.x=x;
this.y=y;
}
a.prototype.methoda=function ()
{
return x+y;
}
function b (x,y,d,e)
{
a.call (this,x,y,true) //--- this would inherit all own Objects and Properties of a and become own properties of b
this.d=d;
this.e=e;
}
b.prototype=new a (); //--- this would only inherit the prototype, construct becomes false and isnt worked through, which if not would result in adding propertiy x and y to prototype instead of directly to instance of b,
b.prototype.constructor=b;
var test=new b (1,2,3,4);
b.methoda ();
second way
function a (x,y)
{
if (arguments.callee.doNotConstruct) return;
this.x=x;
this.y=y;
}
a.prototype.methoda=function ()
{
return x+y;
}
function b (x,y,d,e)
{
a.call (this,x,y) //--- this would inherit all own Objects and Properties of a and become own properties of b
this.d=d;
this.e=e;
}
a.doNotConstruct=true;
b.prototype=new a (); //--- this would only inherit the prototype, construct becomes false and isnt worked through, which if not would result in adding propertiy x and y to prototype instead of directly to instance of b,
a.doNotConstruct=false;
b.prototype.constructor=b;
var test=new b (1,2,3,4);
b.methoda ();
put this in a function
function prototypeInheritance (inheritor,parent)
{
parent.doNotConstruct=true;
inheritor=new parent ();
inheritor.prototype.constructor=inheritor;
inheritor.parent=parent;
parent.doNotConstruct=false;
}
you can call the parent property with (arguments.callee.parent) in the inheritor constructor and you can check doNotConstruct with arguments.callee.doNotConstruct in the parent constructor
I have a JavaScript object defined like so:
var Object = (function () {
function Object() {
this.id = RandomNumber();
}
// Custom Object.prototype / Object impementations here...
return Object;
})();
The problem is that once this has been constructed, it loses original functionality like Object.defineProperty etc.
The idea is that I want to extend the basic functionality of Object, not re-write or overwrite the existing prototype.
How can this be achieved?
EDIT: Just to be clear, I know I can do this without affecting the original functionality:
Object.prototype.foo = function() { }
but I need to specifically add functionality to Object's constructor, i.e.
function Object() { this.id = 0; }
The new functionality must not overwrite the original Functionality.
Use the .prototype to add a property:
Object.prototype.specialMethod = function () {
// Your method's code
};
And you'd use it like:
var a = {};
a.specialMethod();
Although I would discourage adding a property to the Object's prototype, because it is enumerable and will mess up looping, and will be inherited by all objects, and objects that inherit from Object, which is basically everything.
You could actually use the Object.defineProperty method you mention:
Object.defineProperty(Object.prototype, "specialMethod", {
enumerable: false, // The important one, to avoid looping problems
configurable: false,
writable: false,
value: function () {
// Your method's code
}
});
Do as Ian wrote. If you also want to check it the method already exists use
if (Object.prototype.specialMethod == null) Object.prototype.specialMethod = function() { ... };
In order to extend this object you should create another object that has its prototype assigned a new instance of Object.
var Object = (function () {
function Object() {
this.id = 5;
}
Object.prototype.speak = function(prop){
alert(this[prop]);
}
return Object;
})();
function ExtendsObject(prop){
this.someProperty = prop;
}
ExtendsObject.prototype = new Object();
var xObj = new ExtendsObject("derived");
xObj.speak("id");
xObj.speak("someProperty");
Working Example: http://jsfiddle.net/RbCcA/
If you want to stick with the self executing functions here is the example rewrote:
var Object = (function () {
function Object() {
this.id = 5;
}
Object.prototype.speak = function(prop){
alert(this[prop]);
}
return Object;
})();
var ExtendsObject = (function(){
function ExtendsObject(prop){
this.someProperty = prop;
}
ExtendsObject.prototype = new Object();
return ExtendsObject;
})();
var xObj = new ExtendsObject("derived");
xObj.speak("id");
xObj.speak("someProperty");
Working Example: http://jsfiddle.net/RbCcA/1/
I do question the use of self executing functions in this situation. They are usually used to encapsulate and shield internals, however in the code example they are being exposed by returning the object from the SEF. Returning the object and storing it in a global variable just re-exposes the object, allowing its prototype and properties to be manipulated. Maybe there are private variables you have not mentioned, but as stated I find the SEFs unnecessary.
I find this is most recommended way to do inheritance in javascript.
function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
}
what if I already have methods in child's prototype, aren't they will overwrite, shouldn't we preserve them.
function extend(Child, Parent) {
var c = child.prototype;
var oldProto = new C();
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
for(var i in oldProto ){
Child.prototype[i] = oldProto[i]
}
}
I'm not sure if this is any good to you, but it's well important to remember: prototypes are not the same things as classes. What you're doing is trying to make JS behave like a traditional OO language, which is trying to teach a dolphin to dance ballet, or forcing a tiger to become vegan: Admirable, but destined to end in tears.
I can't really see why you'd want to use the extend function to do whatever it is you're trying to do. Why not simply use this:
function Parent()
{};
function Child()
{};
//augment parent proto
Parent.prototype.parentMethod1 = function()
{};
//set Child's proto to Parent
Child.prototype = new Parent();
Child.prototype.constructor = Child;
//Then augment the Child's prototype
Child.prototype.childMethod1 = function()
{};
var foo = new Child();
foo.parentMethod1();//works
foo.childMethod1();//works, too
IMO, this solves the problem entirely. Sure, it's a tad more verbose, but OOP always is.
The pattern you're trying to achieve is called multiple inheritance. And it's highly not recommended for the use because of the issue you're experiencing, called diamond problem. Just use mixin pattern instead.
The code below is the one of the best I have seen for doing inheritance in JavaScript.
Object.create(proto [, propertiesObject ]) is discussed on MDN here.
Below, Jon defines a base empty object called ExtendBase then adds a function property called extend which is not enumerable which takes as its argument a single new object.
That object should contain enumerable properties such as methods and data that will be added to the base object.
He gets all the enumerable properties from the passed object, then creates an array of the necessary descriptors to pass into Object.create using those properties' names. He then uses the parent object as the prototype and resultant descriptors as new properties to be added to the child object directly in the Object.create() call.
As you can see, you can use an object argument with properties, including methods, to extend a parent without losing that passed object's properties with the result being a child object with the parent as the prototype and the enumerable objects of the passed object added directly to the child.
However, this maintains a clean prototype chain while intending to extend parent objects using other objects which are created sanely to extend the parent into a new child in a way that makes sense:
Live sample here (Press F12 in Chrome for console output, or use FireBug in FireFox, etc.)
JavaScript:
// Original Author: FireFly - Jonas Höglund - ##javascript channel
// on irc.freenode.net - see THANKS File. Updated to private data
// members and passable initial parameters by Scott Sanbar
///////////////
// Library code
///////////////
var ExtendBase = {};
Object.defineProperty(ExtendBase, 'extend', {
enumerable:false, value:function (obj) {
'use strict';
var descs = {};
Object.getOwnPropertyNames(obj).forEach(function (key) {
descs[key] = Object.getOwnPropertyDescriptor(obj, key)
});
return Object.create(this, descs);
}
});
///////////////
// Sample Usage
///////////////
function PersonObj(nam) {
return {
name:new function () {
var name = nam;
this.set = function (value) {
name = value;
};
this.get = function () {
return name;
}
},
// A person can tell you its name.
talk:function () {
return "Hello, I'm " + this.name.get();
}
}
}
;
function WorkingPersonObj(occ) {
return {
occupation:new function () {
var occupation = occ;
this.set = function (value) {
occupation = value;
};
this.get = function () {
return occupation;
}
},
// A working person also tells you their occupation when they talk.
talk:function () {
return Person.talk.call(this) + " and I am a " + this.occupation.get();
}
}
}
;
var hush = {
hush:function () {
return "I am supposed to be quiet";
}
};
var Person = ExtendBase.extend(new PersonObj('Harry'));
var WorkingPerson = Person.extend(new WorkingPersonObj('wizard'));
var wp1 = WorkingPerson.extend(hush);
console.log(wp1.talk()); // "Hello, I'm Harry and I am a wizard"
console.log(wp1.hush()); // "I am supposed to be quiet"
wp1.name.set("Elijah");
wp1.occupation.set("prophet");
console.log(wp1.talk()); // "Hello, I'm Elijah and I am a prophet"
console.log(wp1.name.get());
console.log(wp1.occupation.get());
If I have an object that I want to "inherit" methods from a "super object" to ensure consitency. They will be intermingling variables. REVISED
ParentObj = function()
{
var self = this;
this.interval = null
this.name = "";
this.timeout = 1000;
this.stop = function()
{
clearInterval(self.interval);
};
this.start = function()
{
self.log("Starting up");
setTimeout(function(){
self.getData(true);
self.interval = setInterval(function(){
self.getData();
}, self.timeout)
}, 1000);
};
this.log = function(msg)
{
require("sys").log(self.name + ": " + msg);
};
this.getData = function(override)
{
if(override || self.interval)
{
/**
* Allow
*/
self.log(new Date());
}
else
{
self.log("Unable to override and no interval");
}
}
}
ChildObj = function()
{
var self = this;
this.name = "Child";
this.timeout = 500;
this.start();
setTimeout(function(){
self.stop();
}, 2000);
}
ChildObj.prototype = new ParentObj();
var c = new ChildObj();
This doesn't seem to work correctly, specifically it not seeing the self.interval and is unable to clear it.
I'm open to other JavaScript inheritance methods, if they exist, but I really need to start encapsulating stuff off into the parent. There are three or four functions that are identical, but being changed at times and this means I have to run through a dozen files to make the change, rather then simply altering the parent.
Working through some of the suggestions I've tried to more clearly define what sort of functionality I'm going for. Ideally all the "children" will have a couple of unique settings (name, interval, config settings) and a getData() method while the parent manages starting, stopping, logging, and anything else.
'Clone' an object by making the object the prototype of a throwaway function and calling that function with 'new'.
Clone the parent constructor's prototype, and set the result as the prototype of the child class.
...
/**
* Extend a constructor with a subtype
* #param {Function} superCtor Constructor of supertype
* #param {Function} subCtor Constructor of subtype
* #return {Function} Constructor of subtype
*/
var extend = (function(){
return function (superCtor, subCtor) {
var oldProto=subCtor.prototype;
subCtor.prototype=clone(superCtor.prototype);
return merge(subCtor.prototype, oldProto).constructor=subCtor;
}
function Clone(){}
/**
* Clone an object
* #param {Object} obj Object to clone
* #return {Object} Cloned object
*/
function clone (obj) { Clone.prototype=obj; return new Clone() }
/**
* Merge two objects
* #param {Object} dst Destination object
* #param {Object} src Source object
* #return {Object} Destination object
*/
function merge (dst, src) {
for (var p in src) if (src.hasOwnProperty(p)) dst[p]=src[p];
return dst;
}
}());
Using this inheritance method, you can only mingle variables "upstream." Your child object will be able to see the public properties of its prototype, but the prototype cannot see the properties of its children. It must be self-contained.
(EDIT: I just noticed you're also using "self" without declaring it in sobj.)
sobj = function()
{
var self = this;
self.close = function()
{
clearInterval(self.interval);
}
self.interval = null;
}
cobj = function()
{
var self = this;
self.interval = setInterval(function(){ /* Do something */}, 1000);
}
// set cobj.prototype - see explanation below
For how to properly set the prototype (and an in-depth look at how inheritance works in JS), I refer you to Douglas Crockford's book JavaScript: The Good Parts.
He has actually posted how to properly set the prototype on his site. Be sure to use the version that does not touch Object.prototype, as many scripts (jQuery for starters) will break if you change it.
First thing, I don't think that var this.interval is okay. var keyword is used to define a variable, but in your case you are referencing an object.
Second, if you want to declare "interval" as a method of your cobj, you have to wrap the body of the function in a function.
So, this way it works for me:
var sobj = function()
{
this.close = function()
{
clearInterval(this.interval);
}
}
var cobj = function()
{
this.initInterval = function(){ this.intervalid = setInterval(function(){ alert("test")}, 5000)};
this.intervalid = null;
}
cobj.prototype = new sobj();
var inst = new cobj();
inst.initInterval();
After I've defined the constructor functions, I create an actual instance of a "cobj" object and then call "initInterval" to initialize the "setInterval".
UPD: updated the code per #MooGoo's comment.