How to update original this when cloning with extend - javascript

I'm trying to clone some objects using the jquery extend method. However, after cloning my object, I realized that some methods of the cloned object were modifying values from the original object so I thought both objects properties may be pointing at the same variable.
After running some tests, I figured that the properties of my cloned object got copied correctly... including the local self variable (which is used to hold the reference to the original this of the class instance). Since the cloned self is still pointing at the original instance, the methods referring to that variable are targeting the properties of the original instance instead of it's own instance:
var Animal = function() {
var self = this;
this.sound = "";
this.talk = function(){
alert(self.sound);
};
};
var dog = new Animal();
dog.sound = "Woof";
dog.talk(); //Woof as expected
var cat = $.extend(true, {}, dog);
cat.sound = "Meow";
cat.talk(); //Woof... but Meow was expected
The extend method behavior does make sense... but is there a generic way to make sure the self variable refers to the new cloned object? By generic, I mean that the self variable may have a different name (that, _this, etc) and that I would like to avoid adding custom methods to every class just to update the self variable.
You should also keep in mind that the self variable is private (and there's many good reasons to keep it like this) so this mean you can't set it outside the instance.

As a matter of fact, you don't need the var self = this construct for this use case.
Just made a small test here: http://jsfiddle.net/quwdeafd/
Take a look at the scope of this.
Isn't that what you were looking for?
var Animal = function() {
this.sound = "";
this.talk = function(){
console.log(this); //Logs Animal the first time, object the second
console.log(this.sound); //Logs Woof and meow
};
};
var dog = new Animal();
dog.sound = "Woof";
dog.talk();
var cat = $.extend(true, {}, dog);
cat.sound = "Meow";
cat.talk();
Small remark: usually it's custom to put this method on the prototype of the object:
Animal.prototype.talk = function(){
console.log(this);
console.log(this.sound);
};
Because it makes the method immediately available without needing to be initialized on every instantiation.

As adeneo pointed out, the problem is at another level. Even if the extend is often referred to as a cloning method, it's wasn't made for this purpose. The problem mentioned in this question is a good example of it's limitations.
For the record, I stopped using the extend method for cloning purpose and I solved my problem by replacing it with a cloning method taken from this SO answer.

Related

Adding a constructor to a property of a 'parent' object

Is it ok to do this?
var MyObj = function() {};
var MyObj.prototype.thing = function() {};
MyObj.SubObj = function() {}
MyObj.SubObj.prototype.thing = function() {}
var ins = new MyObj();
var another = new MyObj.SubObj();
In this code MyObj acts like a parent class because I've assigned MyObj.SubObj to be another constructor function with it's own prototype chain.
Is it ok to nest a constructor off of another constructor like this?
It's perfectly okay to do it, but it doesn't do anything special. In particular, there's no kind of inheritance relationship between MyObj and MyObj.subobj, nor are the MyObj.prototype.thing and MyObj.subobj.prototype.thing functions in any way linked.
I also wouldn't call it nesting. The only relationship here is that subobj is a property of the function MyObj. It's not nested within it in any kind of scope way...
But it's perfectly fine to do it, as an organizational thing (for instance, to avoid lots of global symbols), provided inheritance isn't meant to be implied.
Side note: The overwhelming convention in JavaScript is that constructor functions like these use initially-capped CamelCasing, to distinguish them from normal functions (using non-capped camelCasing). Earlier you had myobj and subobj. You've changed the first to MyObj, but if following this convention, you'd change subobj to SubObj as well (just FWIW).

Javascript what is the use of defining constructor in prototype?

I am looking for a best clarification on my doubt. I do have a function, and from the function i am calling a method, it works fine.
example:
function Car(){
this.name = 'car';
}
function Ferari(){}
Ferari.prototype = new Car;
Ferari.prototype.value = 122;
var fa = new Ferari;
console.log(fa.constructor, fa.name);
from the output in console i am getting my constructor is 'Car'. I changed the constructor as follows:
Ferari.prototype.constructor = Ferari;
now the output in console for constructor is 'Ferari' - it's fine.
can any one tell me what is the use of declaring constructor?
Is that a best practice?
In case if I am not declaring the constructor what is the issue i will be getting?
what are the ways for declaring constructors?
any one detail me the above questions?
Live Demo
Questions:
can any one tell me what is the use of declaring constructor?
Is that a best practice?
In case if I am not declaring the constructor what is the issue i will be getting?
what are the ways for declaring constructors?
Answers:
[A1] in some scenarios, it is necessary to find out the instance's real constructor, especially inheritance level is deep. e.g. https://github.com/chennanfei/ThinkMVC/blob/master/thinkmvc.js#L737. In a word, to know the exact construtor of instances is helpful for some cases.
[A2] As Johan pointed out,
Ferari.prototype = Object.create(Ferari.prototype);
Ferari.prototype.constructor = Ferari;
[A3] I don't think you will get issues unless you use it obviously.
[A4] Your code indicates the general way. I think following way works, too.
var Cart = function() {...}
To answer Johan's question in the comment, I added more here. (text's size is limited in comment.)
here is a little complex case. Suppose the 'class' Base provides a method 'setProtoValue' which allows instances to set/update the properties of their prototype. Classes A and B inherit from Base. When A's instances call the method 'setValue', of course we don't hope affect all B's instances. So we need know the exact constructor of A. In following example, if we don't reset A.prototype.constructor, all Base instances including B will be affected which is unexpected.
var Base = function() {};
Base.prototype.setProtoValue = function(key, value) {
this.constructor.prototype[key] = value;
};
var A = function() {};
A.prototype = Object.create(Base.prototype);
A.prototype.constructor = A;
var B = function() {};
B.prototype = Object.create(Base.prototype);
B.prototype.constructor = B;
Well, as you can see if you don't declare the constructor to be Ferrari, the superclass constructor (so that's Car) will be used. Unless that's what you want, keep the redeclaration of constructor.
See example:
function Car(){
console.log('car');
}
function Ferari(){
console.log('ferrari');
}
Ferari.prototype = new Car;
//Ferari.prototype.constructor = Ferari;
var fa = new Ferari();
console.log(fa.constructor);
Comment the redeclaration of Ferari to see the difference.
If you do Ferari.prototype = new Car;, the Car constructor will be called regardless of whether if you create an instance of Ferari or not.
With that in mind, I suggest the following change:
function Car(){
console.log('car');
}
function Ferari(){
Car.apply(this, arguments); // Call the base class constructor manually
console.log('ferrari');
}
Ferari.prototype = Object.create(Ferari.prototype);
Ferari.prototype.constructor = Ferari;
var fa = new Ferari();

Purpose of this Javascript prototype snippet

Sorry I can't phrase this better. But I ran across some code like the following:
MyObject.prototype = Object.create(MyObject.prototype);
MyObject.prototype.constructor = MyObject;
And I just can't seem to figure out what it does. MyObject is defined above it something like this:
function MyObject(options) {
this.someProp = someDefault;
this.otherProp = process(options.something);
// etc...
}
and it's always called as a constructor. I'm just wondering what benefit those first two lines provide and if it's a known pattern in Javascript.
I just can't seem to figure out what it does
It creates a new object that inherits from [the old] MyObject.prototype via Object.create and then overwrites MyObject.prototype with that. It also explicitly adds a .constructor property which actually should be existing already.
I'm just wondering what benefit those first two lines provide
None, unless before that snippet someone has corrupted the prototype (like MyObject.prototype = Object.prototype) and this is an attempt to fix it.
…and if it's a known pattern in Javascript.
Not like this. Using Object.create to set up the prototype chain for inheritance between constructor-defined "classes" is a known pattern, but then the constructors would be different on each side of the assignment.
The two lines of code provided seem to be an incorrect attempt of the use of prototypal inheritance, but I see where you're going with this and what you're trying to accomplish.
As we know, there are two ways in JavaScript to define objects that have properties and methods as members - the object literal notation and function notation. Using object literal notation, we don't have immediate access to the new keyword (think of this like using abstract classes in Java or C#). With function notation, we have access to the new keyword because the initial declaration of an object as a function serves as our constructor.
In ECMAScript 5, The Object object was given a method called create that provided developers a simple way to create a new object from an existing object declared with the object literal notation. (See documentation here). However, objects created in function notation have problems with this method because they are Function objects. The Object.create method is a great way to use simple inheritance, allowing access to the base properties and methods.
With function notation, once the new keyword is used, the result is not a function, but rather an object. For example, I can test this:
var Obj = function(){};
console.log(typeof Obj) // "function"
console.log(typeof new Object()); // "object"
Because of this, you can only inherit once (meaning the child object cannot be derived from):
var MyObject = new Object();
var anotherObj = new MyObject() // throws exception
To alleviate this problem, you need to follow three steps:
Create your child object in function notation (so you can create new instances of it using the new keyword and inherit from it).
Set the child object's prototype (an object) to the result of a new instance of the base object (which will be an object as well).
Set the constructor of the child object (which happens to be on the object's prototype) back to reference the Function of itself (which is a function prior to instantiation). If you don't do this, the constructor will remain an object, which cannot spawn new instances.
From here, you can create new instances of both the child and parent objects and derive from both, using the pattern. Here's a practical example:
var Vehicle = function(){};
Vehicle.prototype.start = function() {
return this.make + " " + this.model + " " + "started";
}
var Car = function(color, make, model) {
this.color = color;
this.make = make;
this.model = model;
}
Car.prototype = new Vehicle();
Car.prototype.constructor = Car;
var myCar = new Car("red", "chevy", "aveo");
myCar.start(); //"chevy aveo started"
I really don't see any benefit in doing that.
What it's doing is providing the new object with the previous objects methods. But it's coming from the same object...
Here is a good example of JS inheritance:
http://jsfiddle.net/aDCmA/2/
var App = (function(){
var Being = function() {
this.living = true;
this.breathes = function () {
return true;
};
};
var Robert = function() {
this.blogs = true;
this.getsBored = function () {
return "You betcha";
}
};
Robert.prototype = new Being();
return {
Being: Being,
Robert: Robert,
being: function(){ return new Being(); },
robert: function(){ return new Robert(); }
}
}());
Here is another question that is similar: inherit prototype methods from other classes without overriding own prototype methods
Credit to Robert Nyman for originally blogging about it: http://robertnyman.com/2008/10/06/javascript-inheritance-how-and-why/
Let's see line by line:
MyObject.prototype = Object.create(MyObject.prototype);
This redefines MyObject.prototype to an object that inherits from MyObject.prototype. This is unusual, because it makes no sense to inherit from itself.
MyObject.prototype.constructor = MyObject;
Since the previous line overwrote MyObject.prototype, this is just fixing the constructor property that was lost in the process.
I can think of one scenario where tht might be useful: if some code before that messed up with MyObject.prototype, for example assigning the prototype of another constructor to it:
MyObject.prototype = SomethingElse.prototype; // wrong way to do inheritance.
Then the code you posted would be an attempt to fix it.
This is perfectly valid Javascript.
Any javascript function (say Func)can be used as a constructor and the constructor invocation also requires a prototype property (i.e. F.prototype or the prototype associated with the function) . Thus (almost) every function has a prototype property. The value of this property (i.e. Func.prototype).
Now the value of this prototype associated with the function is an object itself that has a single non enumerable property called constructor. And the value of this constructor property is the function object (i.e. F itself).
Lets take an example.
Say I construct a function Func
var Func = function() {
//your definition
};
Now since this can be invoked as a constructor it has to have a prototype property Func.prototype lets call this proto.
proto = Func.prototype;
Now the prototype has a single property (that is non enumerable) called constructor. This constructor has a value that is equal to the function object itself.
Dont believe me check it like this
Func.prototype.constructor === Func // =>true
Will always return true for any function.
Now from the code you explained :
So basically these two lines
MyObject.prototype = Object.create(MyObject.prototype);
MyObject.prototype.constructor = MyObject;
are modifying the value of the prototye to have a constructor property with the value of MyObject that is defined. But that would have happened anyways in the normal course of things. But the reason could be that maybe the prototype of the object has been changed earlier from the class it has been inherited from. In that case would those two lines make sense.
Hope that helps :)

necessity of prototype declaration in every method

Is is necessary to have "prototype" appended to every method of class.. or namespace is enough in example below (for full example refer link below). I understand that it is good practice but do inheritance really require the keyword "prototype" declare in every method.. what is the real necessity inheritance
if(animal === undefined) var animal = {};
animal.Mammal.prototype.haveABaby=function(){
var newBaby=new Mammal("Baby "+this.name);
this.offspring.push(newBaby);
return newBaby;
}
animal.Mammal.prototype.toString=function(){
return '[Mammal "'+this.name+'"]';
}
http://phrogz.net/JS/classes/OOPinJS2.html
prototype has nothing to see with namespace.
You define a function on prototype so that all objects created with new Mammal() will have this function (method) :
Mammal.prototype.haveABaby=function(){
...
var phoque = new Mammal();
var d = phoque.haveABaby();
In this case, all instances will share the same function. If you'd had defined the function on your instance, you'd have used more memory (not necessarily significant), and instance creation would have been longer.
If you want, you may combine it with namespaces :
animal = animal || {}; // note the simplification
animal.Mammal.prototype.haveABaby=function(){
...
var phoque = new animal.Mammal();
var d = phoque.haveABaby();
But those are two different topics.
Here's a good description of the link between prototype and inheritance.
it's needed.
If you don't have prototype then the function only gets added to the current instance. Using prototype means that when you user the new keyword, the new object will also get a copy of the function.
ie:
Mammal.toString = function() {...};
would put the toString function on Mammal - but would NOT put a toString function on every instance of Mammal. e.g. using the above non-prototype declaration:
var aDog = new Mammal();
aDog.toString() //result in undefined

Is there a performance penalty associated with methods created in the constructor versus methods created on the prototype?

I can declare methods of an object in two ways:
The first way uses the self=this idiom.
function SelfIdiomExample(name){
var self = this;
self.sayHello = function (name){
alert("Hello, "+name);
}
}
Which is useful when you need a reference to the object in a method (for example if the method will be passed as a callback). The other way is to do it by modifying the prototype:
function PrototypeModExample(){
//pass
}
PrototypeModExample.prototype.sayHello = function(name){
alert("Hello, "+name);
}
Both have the same result:
var sieg = new SelfIdiomExample();
var pmeg = new PrototypeModExample();
sieg.sayHello("Barnaby");
pmeg.sayHello("Josephine");
While I understand the use case for the self=this idiom, I am wondering:
Is there a performance penalty to using the methods created in the constructor versus methods created on the prototype?
Well this here:
var self = this;
Is not something has performance implications at all. It's wicked fast as it's simply accessing a local variable. Even from nested funcitons, this is a very fast operation in JavaScript.
However, methods created in the constructor versus methods created on the prototype has a huge performance difference.
In this example:
var PrototypeModExample = function(){
this.name = "Joe";
};
PrototypeModExample.prototype.sayHello = function(){
alert("Hello, " + this.name);
};
var a = new PrototypeModExample();
var b = new PrototypeModExample();
console.log(a.sayHello === b.sayHello); // true
Every instance of the constructor gets access to the same function objects. Which can be proved by using the === operator to compare the function objects on two instances. It will only return true when they are the same object. So globally we now have 2 instances, but they share one function object for the implementation of the sayHello method. This means that function is already setup and created when you want to make a new instance.
In other words, for all instance obj.sayHello points to the same function object, which was created before any instances existed at all.
But this on the the other hand:
function SelfIdiomExample(name){
var self = this;
this.name = "Joe";
this.sayHello = function(){
alert("Hello, " + self.name);
}
}
var a = new SelfIdiomExample();
var b = new SelfIdiomExample();
console.log(a.sayHello === b.sayHello); // false
Works differently. Now we see that the === comparison is false. That's because a new function object was created for each instance. Creating this function takes time (it needs to be parsed) and memory (this unique version of that function needs to be stored). So when creating lots of these instances, this method will be both slower and consume more memory.
In other words, for all instance obj.sayHello points to a unique function object which was created when the instance itself was created.
So usually, the prototype method is preferred. Especially in cases where a large number of instance might exist, since each instance can share function objects for it's methods.
As always, you have to test in order to answer questions like this: http://jsperf.com/this-vs-self/2.
When you test, there appears to be not much difference (less than few percent with a slight advantage to self in some cases). One advantage to self is that it can be minimized better by changing it to a one character variable name and that is apparently why some frameworks use it.
In your example, I would say that the use of self is extranous and not neccessary. Normally folks only use self when a closure is used and the value of this in some callback is no longer what you want it to be like this:
counter.prototype.incrementWithDelay(delay) {
var self = this;
setTimeout(function() {
self.counter++;
}, delay);
}
But, if you just have a normal method, there is little reason to use self.
counter.prototype.set(val) {
this.counter = val;
}

Categories

Resources