I am trying to extend an object, and I want to modify a method of the first, not to override it. I don't think this is clear so here is an example:
var object1 = {
whatever : function(){
console.log('first object method');
}
}
var object2 = {
whatever : function(){
console.log('second object method');
}
}
var object = $.extend(true, object1, object2);
object.whatever();
This example will output second object method, but what I want is that it ouput first object method and second object method.
Is there a way to do this?
Javascript uses prototypal inheritance, so you can make object2 inherit object1's properties and methods by doing
object2.prototype=object1;
this means that object2 will inherit all the properties and methods of object1, and any overwritten methods can be accessed at object2.prototype.method()
so parent::whatever(); is equivalent to this.prototype.whatever(); when calling from the scope of object2.
var object1 = {
whatever : function(){
console.log('first object method');
}
}
var object2 = {
whatever : function(){
console.log('second object method');
this.prototype.whatever(); // Equivalent to parent::whatever();
}
}
object2.prototype=object1; // Makes object2 inherit object1's properties and methods
object2.whatever(); // "second object method" "first object method"
Related
What is the difference between creating an object using an inline object constructor and creating an object by immediately invoking a contructor? I have always done the latter as it free's me from having to call something like init() myself and feels like the right thing to do, but I keep seeing the object notation in other people's code and was wondering if there is another difference I am not seeing.
Example:
window.fooModule = {
init: function() {
this.bar = "cee";
doStuff();
},
doStuff: function() {
...
}
}
window.fooModule.init();
Example2:
window.fooModule = new function(){
this.bar = "Cee";
this.doStuff = function() {
...
}
this.doStuff();
}
In first notation variable fooModel is object created without constructor call, in second notation fooModel is object created with call of constructor as anonymous function, so when using new keyword constructor function is called and object is created from its prototype ( in this example no prototype is declared so it is standard object prototype).
Conclusion
Use second notation if Your object has to call some code
when is created, use first if not.
More about second notation
Second notation enables also using local ( private ) variables and functions inside constructor, because constructor give us own scope.
var obj=new function(){
var priv="Local scope variable";
var method=function(){
console.log("Local method");
};
this.doStuff=function(){
//here local methods and variables can be used
};
};
Second notation with constructor and new is more often used with standard constructor function declaration and prototype declaration. This is correct way if We need to create more then one object. Methods and every shared properties should be declared in prototype not in constructor.
var ExampleClass=function(bar){
//constructor
this.bar = bar;
};
ExampleClass.prototype.doStuff=function(){
};
Creating such object:
var a=new ExampleClass("A bar"); //a.bar is "A bar"
var b=new ExampleClass("B bar"); //b.bar is "B bar"
Objects a and b have the same prototype ( it saves memory ) but they can have different properties set in constructor.
OffTop
In javascript is so many possibilities to create objects, I have third example how run code in first notation:
window.fooModule = {
init: function() {
this.bar = "cee";
this.doStuff();
return this;//return this
},
doStuff: function() {
}
}.init();//run init after object notation
I create object and run init in one time.
let the 1st example return obj1 and 2nd example return obj2
obj1 will have [[Prototype]] is an object. This object has constructor property is "function Object()"
obj2 will have [[Prototype]] is an object. This object has constructor property is anonymous function.
The way in 2nd example is usually used to achieve something we call "singleton"
Bonus: This stuff is easy to confused, but if you want to dig deeper, here is a good post for you
https://zeekat.nl/articles/constructors-considered-mildly-confusing.html
There are objects and there are object definitions prototypes. Neither of your examples are object definitions prototypes.
window.fooModule = function(bar){
this.bar = bar;
(this.doStuff = something => {
console.log(this.bar,'is doing', something || 'something');
})();
};
[a,b]= [new fooModule('a'), new fooModule('b')];
If you simply want to create an object, then you can skip the new and this operator.
(window.fooModule = {
bar : 'Cee',
doStuff : something => {
console.log(foo.bar,'is doing', something || 'something');
}}).doStuff();
Say I have a constructor function in JavaScript, which I use to create my objects. How would I alter the "contents" of all the objects created by this function through a method call from this function. What I am wondering is, weather it is possible to invoke a method call upon the prototype, like we'd modify the prototype adding our own methods/properties.
For example:
function MyConstructor()
{
var privateVariable = "This is an ORIGINAL private variable";
this.publicVariable = "This is public";
this.modificationMethod = function(){
// I want to call this methode on the prototype
privateVariable = "I am now changed";
};
this.alertMe = function(){
alert(privateVariable);
};
}
var a = new MyConstructor();
a.alertMe(); // alerts This is an ORIGINAL private variable
a.modificationMethod();
a.alertMe(); // alerts I am now changed
This works when I want to change a single object, I invoke the method, it changes that single object. However, I want to change all the objects that are created by the constructor.
I know I can add new methods to it like this:
MyConstructor.prototype.foo = function(){
alert("foo");
}
a = new MyConstructor();
a.foo();
But it does not let me run the existing methods to change the properties, and throws an error:
MyConstructor.prototype.modificationMethod();
"modificationMethod is not a function"
EDIT: Updating the answer to reflect everything discussed in comments. I initially misunderstood the OP's issue.
Every object is linked to a prototype object. When trying to access a property that does not exist, JavaScript will look in the object's prototype object for that property and return it if it exists.
The prototype property of a function constructor refers to the prototype object of all instances created with that function when using new.
What that means is that prototype object is sort of a fallback mechanism when an object itself does not have the desired property.
The concept of private variables are in fact closures.
Prototype functions are defined outside of the constructor function scope, meaning they cannot access the "private properties".
However, it is possible to assign a closure to the prototype property itself, effectively making a private shared (static) variable.
function MyConstructor() {};
MyConstructor.prototype = (function() {
var extensions = {
foo: null,
test: function() {
alert("Test was extended");
}
};
return {
registerExtension: function(name, callback) {
extensions[name] = callback;
},
// in order to use the extensions object, you need a generic function such as invoke
invoke: function(name) {
if (typeof extensions[name] === 'function')
extensions[name].call(this);
}
};
}());
var a = new MyConstructor();
a.invoke('test'); //will alert
a.invoke('foo'); //will not alert (not a function)
a.registerExtension('foo', function() {
alert("foo is now extended as well");
});
a.invoke('test'); //will alert
a.invoke('foo'); //will alert
A simpler approach, if you don't mind for the extended functions to be visible (public), would be to directly extend the prototype.
function MyConstructor() {};
MyConstructor.prototype = {
foo: null,
test: function() {
alert("Test was extended");
}
};
var a = new MyConstructor();
a.test(); //will alert
//a.foo(); //will not alert (not a function)
MyConstructor.prototype.foo = function() {
alert("foo is now extended as well");
};
a = new MyConstructor();
a.test(); //will alert
a.foo(); //will alert
You can easily create an interface for prototype extension.
Object.prototype.registerExtension = function( name, func ){
this.prototype[ name ] = func;
};
// ...
MyConstructor.registerExtension( 'foo', function() {
alert("foo is now extended as well");
} );
In javascript, I have an object literal:
var objA = {
doStuff: function() {
// do objA stuff
}
}
I extend objA, and override the doStuff method:
var objB = _.extend(objA, {
doStuff: function() {
// do objB stuff
}
});
However, now when objB.doStuff() is called only objB stuff gets done.
I would like for both objA and objB stuff to be done. I tried the following:
var objB = _.extend(objA, {
doStuff: function() {
this.prototype.doStuff.call(this, arguments);
// do objB stuff
}
});
objB.__proto__ = objA;
However this doesn't work. I guess I don't understand how prototypal inheritance works when extending object literals. So, what is the right way to do this?
I would like for both objA and objB stuff to be done.
You have to call the method of objA explicitly:
var objB = _.extend({}, objA, {
doStuff: function() {
objA.doStuff.apply(this, arguments);
// do objB stuff
}
}, objA);
Note that I'm adding an empty object as first argument, so that first objA's properties are merged and then yours. For more info about how _.extend works, see the documentation.
Object Literals and Prototypal Inheritance?
Object literals currently don't provide a way to set the prototype. You can create an empty object with a specific prototype with Object.create and then merge other properties into it:
var objB = Object.create(objA);
// `merge` is a fictional function that copies properties from object to another
merge(objB, {
doStuff: function() { ... }
});
You can still only call objA's method by explicitly referencing it.
Note: This section probably has to be revised after ES6 is finalized and implement.
In ES6 you will probably be able to set the prototype via the __proto__ property name:
var objB = {
__proto__: objA,
doStuff: function() { }
};
or via Object.setPrototypeOf:
var objB = {...};
Object.setPrototypeOf(objB, objA);
Then you should be able to call objAs method via the super keyword:
var objB = {
__proto__: objA,
doStuff: function() {
super.doStuff();
}
};
Unserscore's _.extend function doesn't return a new object.
It returns the same object extended, with the new properties. So, your objA has the new doStuff function.
Instead, you may want to use _.clone and then rewrite doStuff on objB.
What you are doing in your example isn't actually inheritance, but simply creation and modification. To achieve inheritance in Javascript, it's not actually an OBJECT that you are extending, per se. It's a function. An object doesn't provide direct access to its prototype, a function does. So what you're after is likely something more like:
function ObjA() {
return this;
}
ObjA.prototype.doStuff = function() {
// do objA stuff
};
function ObjB() {
return this;
}
ObjB.prototype = new ObjA();
ObjB.prototype.doStuff = function() {
ObjA.prototype.doStuff.apply(this, arguments);
// do objB stuff
}
var objA = new ObjA(),
objB = new ObjB();
I want to inherit new object instance using prototype.
Test case:
var MyObj = function() {}
MyObj.prototype.objName = {}
// I want this to be a different object for each instance of MyObj
var o1 = new MyObj (),
o2 = new MyObj ();
o1.objName['a'] = 1;
o2.objName['a'] = 2;
alert(o1.objName['a']) // 2
alert(o1.objName === o2.objName) // true
This means that objects in prototype are not inherited as its copies but instead as its reference.
I know that normally you can do it like this.
var MyObj = function() {
this.objName = {}
}
var o1 = new MyObj(),
o2 = new MyObj();
alert(o1.objName === o2.objName) // false
This works fine, but in my case this is not an option. I really need to define objName outside the MyObj function.
I managed to "solve" the problem with this
MyObj.prototype.objName = function() {
if ( this._objName === undefined ) {
this._objName = {};
}
return this._objName;
}
var o1 = new MyObj(),
o2 = new MyObj();
o1.objName()['a'] = 1;
o2.objName()['a'] = 2;
alert(o1.objName()['a']) // 1
But this is not very pretty and the performance of this code is much worse.
Is there any way to solve this more elegantly ?
This means that objects in prototype are not inherited as its copies but instead as its reference.
Nothing on the prototype is copied - the whole concept of prototypical inheritance is that properties reference the shared properties of the prototype object. So if you want a property to be individual for each instance, you have to explicitly assign it to the object and shadow the prototype property; just as you're doing it with the _objName property in your code.
But this is not very pretty and the performance of this code is much worse.
If you want it pretty, move it to the constructor (or make the constructor look for something like an init method to call if exists, then you can create that init method on the prototype.
To make performance a little better, you can change the getter function to
MyObj.prototype.getObj = function() {
var obj = {};
this.getObj = function(){ return obj; }; // overwrite itself
return obj;
};
though it still has the function call overhead. For even more elegance, you can use a getter property (not supported in old browsers) that removes itself on the first access:
Object.defineProperty(MyObj.prototype, "objName", {
get: function() {
var obj = {};
Object.defineProperty(this, "objName", {
value: obj,
writable: true //?
});
return obj;
},
enumerable: true,
configurable: true
});
Now you can omit the function call parenthesis.
This means that objects in prototype are not inherited as its copies but instead as its reference.
Just to be clear. First of all in JavaScript all objects are passed by reference, not by value. Only primitives are passed by value.
Second, you're not actually "copying" or "passing" anything. When you set a prototype, you're creating a prototype's chain. It means that in your case:
var MyObj = function() {};
MyObj.prototype.objName = {} ;
var o1 = new MyObj ();
var o2 = new MyObj ();
Both o1 and o2 doesn't have any property called objName, and you can simply test it with:
console.log(Object.keys(o1)); // []
When JS see a code like o1.objName, as first thing checks if the object has this property, and if it has, use it. If not, start to looking in the prototype's chain, starting by the prototype of o1, that is MyObj.prototype: it found the properties objName, and returns it. If it didn't find it, then JS will continue to check the prototype of MyObj.prototype, and so on. So, here the point: MyObj.prototype it's an object: and you shared that object between o1 and o2. That's why the instance of objName is the same. It's exactly the same logic of having:
function objName(obj) {
return "objName" in obj ? obj.objName : O.objName;
}
var O = { objName: [] };
var foo = {};
var bar = {};
objName(foo).push(0);
objName(bar).push(1);
So, you can't put in prototype any object that is not meant to be shared across the objects creates using that prototype. I would say that shared states like that is also a bad practice that should be avoided, that's why in general prototype shouldn't have such property.
It's still not clear to me why you can't modify the constructor, but the point is: when you create the instance of your object, you have to "setup" it. Usually, calling the constructor, but any function is fine. This is made also when you want to support inheritance, and calling the "super" constructor to initialize your object.
Whats the difference between (via prototypes)
var Todo = {};
Todo.prototype.name = "...";
Todo.prototype.hello = function() { ... }
Vs (variables & functions "outside" object)
var Todo = {}
Todo.name = "..."
Todo.hello = function() { ... }
Or even the below : variables & functions in object
var Todo = {
name: "...",
hello = function() { ... }
}
Think it like
A property or a function declared with prototype is an instance member of Todo.
A property or a function declared without prototype is a static member of Todo.
The first one doesn't make sense as you are dealing with an object instance (({}) instanceof Object === true), it won't have a prototype property (Object does).
You may be inquiring about the difference between these two patterns...
var ObjA = function() {
this.method = function() {};
};
var ObjB = function() {};
ObjB.prototype.method = function() {};
jsFiddle.
The former will use more memory when instantiated - each object has their own method. The latter won't each have their own method, the method lives on the prototype object, which is the next in command on the prototype chain when its attempted to be accessed on the parent.
Todo.prototype is also an object, so the difference is if you declare property with prototype, then every object who created from this prototype will have the property, otherwise, the property is only for Todo the object self.
A significant difference between method #1 and #2 (which is almost identical to example #3) is on new keyword that you need to use if you extend your function via prototype, e.g.
var Todo1 = function() {};
Todo1.prototype.name = "Foobar";
var Todo2 = {name: "Foobar" }
var a = Todo1;
console.log(a.name); // no property retrieved
var b = Todo2;
console.log(b.name); // Foobar
var c = new Todo1;
console.log(c.name); // Foobar