javascript: separate function for methods or embedded in object? - javascript

This is just a simple question. Either way works. I prefer my first example, but I didn't know if doing it this way causes more memory to be allocated than the second example since we are calling "new" on the object....
Example 1
var post = function(){
var self = this;
self.div = $('<div></div>');
self.color = function(color){
this.div.css({background:color});
}
}
var p = new post();
p.color("#FFF");
Example 2
var post = function(){
self = this;
self.div = $('<div></div>');
}
var color = function(p, color){
p.div.css({background:color});
}
var p = new post();
color(p, "#FFF");
So, in the first example, the color function I believe will get recreated everytime a new post is called. What if I have a 100 new post(); calls. Is is less efficient than Example 2 where the function is only defined one time?
Does that make sense what I'm asking?

Yes, in Example 1 there will be a separate instance of the "color" function for every instance of a "post" object, whereas there will only be one instance of the function in Example 2. Clearly, if you plan to have a large number of "post" object instances then you are using more memory than you need to.
In JavaScript, the typical (or prototypical!) way of solving this problem using the best parts of your two examples is as follows (note that I am using "Post" with a capital "P", per convention of constructor functions which are intended for use with the new operator):
function Post() {
this.div = $('<div></div>');
}
Post.prototype.color = function(color) {
this.div.css({background:color});
}
var p = new Post();
p.color("#FFF");
When looking for a property on an object (e.g. "p.color" in our examples), if the property isn't defined directly on the instance then it is looked up as an attribute of the "prototype" of the function which constructed the object (e.g. "Post.prototype.color"). This also means you can define instance methods on the prototype and override them by assigning new functions on individual instance property names directly, if you want.
This way we still get the nice object-oriented syntax of calling "p.color(...)" and the benefit of only one function method instance which is shared by all "Post" instances.

Related

How to update original this when cloning with extend

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.

Weird moment of JS Inheritance

Here is my superclass:
function Element() {
var name;
this.setName(n) = func()...{};
this.getName() = func()..{return name};
}
My another child class:
Select = null;
...
Select =
function (n) {
if (typeof n !== "undefined")
this.setName(n);
...
}
Select.prototype = new Element();
Select.prototype.constructor = Select;
So, what kind of "weird moment" am I talking about? Here it is:
var e1 = new Select("element1");
e1.getName(); // return "element1"
var e2 = new Select(); // WITHOUT NAME
e2.getName(); // return "element1"!!! should be ""!
This is a fairly predictable behavior, but how to get around this?
Of course, i can make something like a this.clear() in Element, that will clear properties and put this method in Select function, but maybe there is a proper solution?
You should add this line Element.call(this, n) into Select. It's quite hard to explain and I feel grumpy because I don't like fake private properties in javascript, but well, I must provide some details in order for you to understand what you are currently doing, otherwise I will not be able to get to sleep.
So, doing new Element() creates a new context where name can live without disturbing anyone. Additionally, two new functions called setName and getName are created, and bound to the prototype object of Select.
From now on, if you create a new instance of Select, you can call these functions since they are available in the prototype of the instance. This actually happens doing new Select("element1"). Indeed, n is defined, so, setName is called from this, which refers to the instance.
But most importantly, calling setName with n set to "element1" will also set name to "element1". Then, if you create a second instance of Select, without defining n, setName is not called, so, name remains set to "element1", for both instances.
Why for both instances? Because both instances share the same setName method, the one bound to the prototype, and this method refers to a unique name variable - remember that Element was called only once.
Finally, why this new line Element.call(this, n) prevents name from being shared? Because each call to Element creates a new context, that is to say, a new name, a new setName and a new getName, and binds these two methods to the newly created instance.
Well, hope this is the morning for you, I would be sorry if you get into sleeping disorders by my fault...
As mentionned by Bergi and HMR, this way of creating the prototype - Child.prototype = new Parent - is out of fashion and will lead you to a dead end. Keep in mind that the prototype is kind of a template for creating instances. Knowing this and considering your code, we can make at least two observations :
As you know, a constructor is intended to initialize instances. In your case, the initialization process - what's inside Element - is unnecessarily executed since the goal is currently to set the template upon which instances will be created.
Let's say that name is required in new Element(name), otherwise your program crashes. What kind of name would you give to the prototype? This question is obviously useless, since you would not want to give a name to a template.
To bypass these problems you need a middleman as shown in the below code (copied from the link shared by Bergi). As you can see, the creation of the prototype is delegated to a "dummy" constructor which is empty. Doing so allows to resolve the two problems raised above.
function Dummy () {}
Dummy.prototype = Element.prototype;
Select.prototype = new Dummy();
Select.prototype.constructor = Select;
Alternatively, you could use the built-in Object.create() :
Select.prototype = Object.create(Element.prototype);
Select.prototype.constructor = Select;
Further reading :
https://stackoverflow.com/a/15461601/1636522
http://aaditmshah.github.io/why-prototypal-inheritance-matters/
You should use the prototype of Element so the variables are not shared between the instances:
function Element() {}
Element.prototype.setName = function(n) { this.name = n; };
Element.prototype.getName = function() { return this.name; };
In this case e2.getName() will return undefined.

Two different ways to make javascript objects

I am new to Javascript and now studying it...
var person = function() {
this.name = "name"
};
var person2 = function() {
var obj = {};
obj.name = "name";
return obj;
};
Let's suppose we have two functions shown above. It seems that objects can be created by using either of the functions. For example)
var p = new person();
var p2 = new person2();
My question is: What's difference between person vs person2? Are they exactly the same? If not which one is a more preferable way to use?
Thanks
The normal way of creating an object is the first way.
The second way will create two objects, and one will be discarded. One object will be created before the function is called, just as with the first method, but because the function returns another object the first object will be discarded and the returned object will be used instead.
An important difference between the methods is that the second one can't use a prototype. Anything that you put in the prototype of the function will be applied to the object that ends up being discarded.
The difference is in the way you use the functions.
The first one is intended to be used as a constructor, this being set to the newly created object. It is intended to be used in combination with the operator new, as follows:
var bill = new person();
This is just like a normal constructor as in typical OOP language.
The second one is intended to be used as a normal function (without new), e.g.:
var bill = person();
You can use this way of object creation in combination with the builder pattern.

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;
}

How can i create a JS Object that I can call any method on?

I want to create a javascript object that I can call any method on, without having to define them. Ideally i could call it as if it were a function, and it would call one function i've defined with the name of the function called as its argument.
So i would define an object with a callMethod(methodName) method, and when i called
thisObject.doAThing();
It would call thisObject.callMethod("doAThing");
is this possible in javascript?
No, that isn't possible. If a JavaScript object doesn't have a property then you can't treat the undefined value as a method.
In Firefox at least, you can use the magic method __noSuchMethod__ to accomplish your goal:
var o = {}
o.__noSuchMethod__ = function(id, args) { alert(id + args); }
o.foo(2,3) //will alert "foo" and "2,3"
Please note that this is not standard and is under consideration for removal, so it will not be added to V8.
Original Post (sorry, should have asked this question in q comments):
I'm having trouble seeing the point. If callMethod has access to a 'doAThing' method somewhere, why couldn't you just plug that in on instantiation of the object or whenever callMethod's sources had a new method added?
Not trying to badger you. Just trying to see if maybe somewhere in the mad mad mad world of the call/apply/prototype paradigm it's possible to accomodate what you're hoping to achieve some other way.
Edit added after this comment:
I want to create a proxy object that delegates its calls to another
object. – msfeldstein
Okay, prototype may be the answer then as it basically does act as a fallback for methods the object itself doesn't have. Every function has a prototype property that's just a plain vanilla object basically. When functions are used as constructors, methods and properties assigned to the constructor prototype become a fallback for constructor instances when you call properties on them that they don't have. You can add properties to that prototype object and they will effectively become available to instances that have already been created. So I'm thinking something like this in the case of associated objects:
//A js constructor is just a function you intend to invoke with the 'new' keyword
//use of 'this.property' will make that property public in the instance
//var effectively makes it private
//Constructors funcs differ from classes in that they don't auto-handle inheritance down to other constructors. You have to come up with a prototype merging scheme to do that.
function MyFacadeConstructor(){ //expected args are objects to associate
var i = arguments.length; //arguments is a collection of args all funcs have
while(i--){
var thisObj = arguments[i];
associateObjMethods(thisObj);
}
//makes it public method but allows function hoisting internally
this.associateObjMethods = associateObjMethods;
function associateObjMethods(obj){
for(var x in obj){
if(obj[x].constructor.name === 'Function'){ //normalize for <= IE8
MyFacadeConstructor.prototype[x] = obj[x];
//or if we literally want the other method firing in its original context
//MyFacadeConstructor.prototype[x] = function(arg){ obj[x](arg); }
//Not sure how you would pass same number of arguments dynamically
//But I believe it's possible
//A workaround would be to always pass/assume one arg
//and use object literals when multiple are needed
}
}
}
}
function FirstNameAnnouncer(){
this.alertFirst = function(){
alert('Erik');
}
}
var fNamer = new FirstNameAnnouncer();
var newFacade = new MyFacadeConstructor(fNamer);
//newFacade.alertFirst should work now;
newFacade.alertFirst();
//but we can also associate after the fact
function LastNameAnnouncer(){
this.alertLast = function(){ alert('Reppen'); }
}
var lNamer = new LastNameAnnouncer();
newFacade.associateObjMethods(lNamer);
//now newFacade.alertLast should work
newFacade.alertLast();
Now, if you want the context of the calling object to matter, I would recommend an event driven interface, which is something JS is very well suited to. Let me know if there's any aspects of the facade approach you're looking for that I haven't implemented here.
You can use Proxy object to intercept any method call.
function proxifyMethodCalls(obj) {
const handler = {
get(target, prop, receiver) {
return function (...args) {
console.log(`Intercepted '${prop}' with arguments ${JSON.stringify(args)}`);
target.callMethod(prop);
};
}
};
return new Proxy(obj, handler);
}
let obj = {
callMethod: (methodName) => {
console.log(`'callMethod' called with '${methodName}'`);
}
};
obj = proxifyMethodCalls(obj);
obj.doAThing(true);

Categories

Resources