Performance issue when assigning the same function to multiple variables in JavaScript - javascript

[Edited] Important! Function is treated as object, not value. So this question is invalid because it is based on a wrong assumption. This edit serves as a note to avoid confusing anyone who read this question.
Let's say I have a function expression of foo
var foo = function() {
return this.member;
}
and I have the following class and instantiate many objects of it with "foo" as the callback function.
var simpleClass = function(callback) {
this.member = "I am an instance variable";
this.callback = callback;
}
var a = new simpleClass(foo);
var b = new simpleClass(foo);
var c = new simpleClass(foo);
.
.
.
Since in JavaScript arguments are passed by value, we are copying the value([Edited]actually it should be object) of foo to a, b, c and other variables' callback. If my understanding is correct, then foo will be copied n times, each occupying certain memory space for each object.
Base on this understanding, I have some performance questions regarding this situation:
Does copying functions to multiple variables harm the performance?
Since each copies of "foo" as simpleClass object's "callback" occupies space, if there are really many simpleClass object(e.g. in a DOM library I have thousands of DOM objects which has the same function css()), will it harm the performance significantly? Or most JavaScript engine has mechanism to tackle this situation and it generally won't harm at all?
In situation where potentially hundreds or thousands of object will be created. Is it always a good practice to put those shared functions to the prototype of an object?
Since all the object instance share the same class prototype, if we put the "foo" function to the prototype of simpleClass, then there should have only one copy of the "foo" and every object instance will just execute the prototype copy of "foo" when needed. Is this a good practice we should follow?
I try to search for similar keywords but couldn't find the right wordings to find the solution to this problem. Please correct my wordings if I make anything unclear. And of course if I have any misunderstandings please correct me too. I appreciate everyone's help.

I don't understand this well enough to give you an authoritative answer but I can say this:
then foo will be copied n times, each occupying certain memory space for each object.
This is incorrect. foo is a variable pointing to a function. foo is not the function, if you did var bar = foo, bar now also points to the function, the same function. So the function is not copied. A reference to the function is assigned to this.callback.
In situation where potentially hundreds or thousands of object will be created. Is it always a good practice to put those shared functions to the prototype of an object?
What is and isn't good practise in JavaScript is up for debate. Some people like to use class/prototype, other people use object literals. It's definitly true though that prototype can help reduce the memory footprint of your application. See it like this: if you're using prototype you're giving the JavaScript engine more information about the object, ie. that your object is similar to all these other objects. The JavaScript engine should be able to make optimizations based on that. I can't say too much about the exact numbers, it might vary wildly per vendor.
Your code sample is equivalent to this:
function foo() {}
function myClass() {
this.foo = foo;
}
var instance = new myClass();
If you used prototypes you'd write:
function myClass() {}
myClass.prototype.foo = function () {};
var instance = new myClass();
If you used object literals you'd have:
function foo() {};
function create_myClass() {
return {
foo: foo
};
}
var instance = create_myClass();
In all the cases above the function foo is never copied. In these cases below you do create a new copy of foo every time:
function myClass() {
this.foo = function () {}; // new copy every time
}
var instance = new myClass();
function create_myClass() {
return {
foo: function () {}; // new copy every time
};
}
As for performance. This is the tip I always give: don't start optimizing until you run into a measurable problem. Always measure with real data. Additionally, if you think your way of doing things is good then it's likely that JavaScript engine vendors will optimize for that method.

In javascript reference is copied not the object itself so you can't assign the value to callback to change the function from inside constructor. You your code all those object will share the function, look at this snipet:
var foo = function() {
return this.member;
}
var simpleClass = function(callback) {
this.member = "I am an instance variable";
this.callback = callback;
}
var a = new simpleClass(foo);
var b = new simpleClass(foo);
alert(a.callback === b.callback ? 'shared' : 'not shared');

Related

Difference In declaring Javascript objects

I have been reading a few different Javascript authors and each has their preferred way to declare properties on objects. None of the authors really explains the difference between these different ways. What are the differences and which way is the preferred declaration to us?
var One = function() {
var self = this;
self.foo = function() {};
return self;
}
var two = function() {
foo: function() {}
};
var three = function() {
var _foo = function() {};
three.foo = _foo;
}
tl;dr - See conclusion
Introduction
Declaring objects in javascript can be done many different ways, and from my point of view it all depends on how complex your project is.
The examples you proposed would be ways to declare variables within a complex project. You could even say for project maintainability and code quality the examples you proposed can be very interesting.
Part 1 - First example
Your first example you proposed was this function.
var One = function(){
var self = this;
self.foo = function(){};
return self;
}
Context: Global -> One()
Suppose we don't create an instance of One (not using new) This function has two objectives.
Attach the foo function to its parents context (usually window object = globally)
Return foo function
You could say you're killing two birds with one stone. While doing two things at once can be interesting, in the end it could really become a context problem.
Context is pretty much asking yourself, what does this refer to? Non instantiated functions inherit the parents context which is fine if none of those parents are instantiated themselves. If this is the case (meaning this != window object) and your primary goal was to attach foo globally well it just won't work.
Context: Self -> new One()
If you call this function with new, this will be different. this will refer to an instance of One. This is a lot more logical way.
In the end you could say that an instance of One will feel almost like an object.
Comparing with objects
I say almost mainly because what is the difference if One was:
var One_object = {
foo: function(){}
}
Well there isn't really, except you'll be more flexible with an object rather than an instance of a function.
//This will not work.
var a = new One();
a.titi = function(){
alert('titi');
}
//This will work
One_object.titi = function(){
alert('titi');
}
Improving the example
The only way that One as an instance can become interesting is if you declare multiple instances. Performance wise and memory wise it'll be more interesting.
var One = function(foo){
//auto instantiate it's self
if(!(this instanceof One)){
return new One(foo);
}
this.foo = foo || function(){};
}
Creating multiple instances of One with the same function probably defeats the purpose, so here is an example of how you could improve One.
var a = One(function(){
alert('instance one');
});
var b = One(function(){
alert('instance two');
});
Part 2 - Second example
var two = function() {
foo: function() {}l
};
Is actually wrong as I'm sure you've noticed from the comments. It should be instead:
var two = {
foo: function() {}
};
Where two is in fact an object and not a function.
This way of declaring variables/functions ensures that you are not overriding on a global scope any other function named "foo".
This can be very useful when you have a lot of js and you are declaring a lot of variables.
In this case, to access foo you need to simply call two.foo();
This is honestly my preferred way of declaring variables.
Variables are not scattered all across the js file.
They do not override any existing variables with the same name
It's clean and maintainable.
They can easily be moved around.
With this in mind, here is an example:
var options = {
foo: function(){
console.log('This is foo');
},
toto: function(){
console.log('This is titi');
}
};
var example = function(options){
options.foo();
options.toto();
}
example(options);
Part 3 - Barbaric
var three = function() {
var _foo = function() {};
three.foo = _foo;
}
A good standard when writing code is to keep the code readable. While this may work, it's not good practice. The main issue with writing Javascript is that it can easily become unreadable.. And in this case it feels barbaric (personal opinion).
Conclusion
As you've probably noticed example two is my preferred way (and to many others I know) in declaring Objects for the following reasons:
Structured
Organized
Easy to handle
Easy to maintain
Flexibility
No conflicts
Feel free to point out on anything I've missed.
In JavaScript you can declare "Objects" via several ways. The most easy way is:
var myObject = {}
from here on, adding methods or attributes is very easy as well:
myObject.myFirstMethod = function(){};
myObject.myFirstAttr = true;
myObject.mySecondAttr = "hello world!";
in this case, you would add those functions and attributes to your "myObject" Object. But there is a better and much cleaner way to do such stuff:
var myObject = function();
myObject.prototype.method1 = function(){};
myObject.prototype.method2 = functiion(){};
myObject.prototype.attr1 = true;
myObject.prototype.attr2 = "hello world!";
myObject.prototype.setAttr1 = function(value){
this.attr1 = value;
}
myObject.prototype.setAttr2 = function(value){
this.attr2 = value;
}
if you declared your Object this way, you can use
var myObjectInstance = new myObject();
this Object now has got every methods and attributes which you had defined in your prototype. more about prototypes:
http://www.w3schools.com/js/js_object_prototypes.asp
edit:
note that "this" in JavaScript means the "element", what called the actual method and NOT the object itself in any case...
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

Wrong bind techniques?

Did you ever think about what exactly bind does and if bind can be overused?
This is model of the object that is considered as a bad practise (example A):
var A = function() {
this.foo = "foo";
this.bar = function () {
console.log("bar");
};
};
This is same object written better:
var A = function() {
this.foo = "foo";
};
A.prototype.bar = function () {
console.log("bar");
};
Function bar is not declared over and over for each instance of A. Now look at the following snippet:
function origin() {
console.log(this.toString() + " is who I am");
};
var listOfBindedF = [];
var dummyObject = {};
for(var i = 0; i<100;i++) {
listOfBindedF.push(origin.bind(dummyObject));
}
With each bind usage, I declared new function didnt I? A lot of libs, frameworks and engines uses bind in its core. Not just for async calls, where it is really hard to go without bind, but literally everywhere, custom inheritance is good example.
I did short test to check it on my own.
Array with 100k length and full of references to origin eats
~465kB.
Array with 200k length, 100k references to origin and 100k
references to dummyObject eats ~1.1MB.
Array with 100k length full
of origin.bind(dummyObject) eats ~9.5MB.
So is there any bind performance impact on javascript apps we are doing with these frameworks/libs? Is the impact noticable? Isnt it similar to example A?
First off, this is a function declaration
function foo() {
}
and this is a function expression
var foo = function() {};
Your two As are different. Imagine the following code:
function A(foo) {
this.bar = function() {
console.log(foo);
};
}
This keeps foo private and still allows bar to access it, something not possible with the prototype version of A.
As for the memory issue: Each function object takes up some memory, obviously. A function expression always creates a new object. Creating 100 instances of A would create 100 function objects assigned to bar using your first example.
A function declaration creates an instance when its surrounding scope is entered. So 100 instances of A would still create 100 instances of bar in this case:
function A(foo) {
function bar() {
console.log(foo);
}
this.bar = bar;
}
bind also creates a new function object that needs even more memory (it has to store a reference to the original function, the value for this etc.)
Using bind has an impact, but I doubt that that will ever lead to performance problems in your app. FWIW: Calling bar in your first example for A is faster then calling it in your second one, because it's not necessary to go up the prototype chain.
Please note that bind can be used for currying as well, making it a versatile tool:
function log(message) {
console.log(message);
}
var logHello = log.bind(null, 'Hello');
logHello(); // prints 'Hello' to the console
Conclusion: Use the tool that's best suited for a task.

Get the object that calls a function belonging to one of its properties OR namespacing prototypes?

(Obviously I'm not sure what the title of this should be.)
I'd like to be able to modify the prototypes of native objects with minimal risk (because trust me; I have heard over and over again how it's a mortal javascript sin).
My train of thought goes something like this: I can greatly reduce the possibility of conflicts if I can add my custom functions to a single object on a prototype rather than directly adding them to the prototype itself.
If I have the code,
String.prototype.foo = function() {
//do stuff
};
...obviously the keyword this references the string that called it. However, if I do something like,
String.prototype.foo = {};
String.prototype.foo.bar = function() {
//do stuff
};
...the keyword this references the object foo.
If there some way to overcome this?
The only way to overcome this would be to override the context using call:
String.prototype.foo.bar.call('hello'))
which works, but is pretty ridiculous.
You're better off (as you've already heard) avoiding modifying native prototypes, and instead having an object with your methods accepting the string as a parameter.
Well, there's a couple of ways to do this, depending on how much work you want to put in.
Using bind is the most straightforward way, but you have to define the string as a variable so you can pass a reference of it to bind:
String.prototype.foo = function() { console.log(this); }
String.prototype.foo.bar = function() { console.log(this); }
var g = "hi there";
g.foo() // Yields g
g.foo.bar() // Yields String.prototype.foo()
g.foo.bar.bind(g)() // Yields g again.
There may be another very hackish way to produce the desired result by creating getters and setters on String.prototype.foo so that String.prototype.foo.bar activates a function that returns a function bound to the instance that foo refers to. ??? Confusing.
What might be the best solution to reduce the possibility of conflicts, is to take advantage of prototypal inheritance and create your own sub prototype of the native String.
function MyString(string) {
this.foo = function() { //whatever };
this.foo.bar = (function() {}).bind(this);
this.toString = function() { return string; } // because toString is not generic.
}
MyString.prototype = new String();
Here, you're creating your own "sub-prototype" of the String prototype. It inherits all the properties of the String prototype and adds its own, all without altering the native strings at all. BONUS: this.foo and this.foo.bar will both refer to your instance.
var instance = new MyString("hi");
instance.foo(); // this == instance
instance.foo.bar(); // this == instance
instance.replace("i", "e"); // returns "he"
This maybe wasn't the answer you were looking for, but hopefully it will at least be helpful.

Javascript function parameter to be used as constructor

I'm trying to do a reusable module, with lesser code. Will something like this work? (Well, not really going to work, it's just an example to give you the idea)
var test = function(foo) {
var bar = new foo(); // The keyword foo is from the parameter
}
The parameter is actually a string. So if I passed "FooBar", a FooBar object will be created.
It's like saying:
var test = function('FooBar') {
var bar = new 'FooBar'();
}
Are there other elegant ways which would fit the solution I'm looking for?
Many thanks!
If foo is a constructor function, then your code will work just fine (I'm curious why you didn't just try it). You can see it work here: http://jsfiddle.net/jfriend00/yT6Vk/.
If you want advise on other/better ways to solve your problem, you'll have to back up and describe more about what you're really trying to do.
There are alternate ways of doing things like this such as factory functions or a single function that examines it's arguments to decide which type of object to create, but without more info on exactly what problem you're trying to solve, we can't really say whether other methods are better/worse than what you already have.
A disadvantage of this method is that you haven't allowed for any arguments to be passed to the constructor.
I would use Douglas Crockford's method
var booze = {
beer:'ale',
wine: 'pinot noir'
}
//test(X)
var createObject = function(o){
function F () {}
F.prototype = o
return new F()
}
var test = function () {
var x = createObject(booze)
return x;
}
test()

Putting arrays into custom objects

I am attempting to build my first custom object and it looks something like this:
function URLObject()
{
this.syllables = new Array();
etc...
this.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
}
var myobj = new URLObject();
myobj.AdtoSyllables("text");
The execution of the above code results in the JS engine printing out the following:
This is Sylcount: NAN
-or-
This is SylCount: undefined.
I have looked at information in Head First Javascript, in the Javascript bible, and on various JS websites. All of them cover in exhaustive detail the use of arrays of objects, but none of them discuss arrays within objects.
And yet I am doing something wrong here and I do not know what. Can anyone help?
Here you go:
function URLObject()
{
this.syllables = [];
etc...
}
URLObject.prototype.addToSyllables = function(aWord) {
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
var myobj = new URLObject();
myobj.adtoSyllables("text");
.prototype adds the function declared after it to every object constructed by the constructor function. (in your case every object that was instantiated by new URLObject())
Firstly, the code as posted actually works for me on Chrome and Firefox; so this must depend on the JavaScript engine, or else there's something funky going on.
Update: I suspect what may be confusing you is some separate call to AddtoSyllables (in code you haven't shown us) where suddenly this.syllables is no longer defined. This is where the behavior of this can get confusing. I've created a jsFiddle to hopefully explain how it works a bit better for you.
http://jsfiddle.net/J3tUb/
That said, it is often very possible to write code like this without having to use this (or the prototype) at all. For instance:
function createURLObject() {
// Use closed-over locals instead of attaching properties.
var syllables = new Array();
function AddToSyllables(AWord) {
// Since syllables is closed over, it is accessible here
// (but WON'T be accessible outside this scope).
syllables.push(AWord);
return syllables.length;
}
// Expose whatever functionality you want to be "public"
// in the returned object.
return {
AddToSyllables: AddToSyllables
};
}
var myObj = createURLObject();
myObj.AddToSyllables("text");
It is, of course, valuable to understand JavaScript's quirky (and surprising, to most developers coming from other languages) behavior with respect to this. That said, once you do understand it, I suspect you will find that it can often be avoided altogether.
you need to do this :
function URLObject()
{
var that = this;
that.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
etc...
Like this you can add method and attributes to one object.
The issue you are having is that the function AddtoSyllables is not a member function or method of the URLObject. It is just a nested function with no object attachments, so all usages of this will result in returning the dom window object. The correct way of declaring the AddtoSyllables function is this:
function URLObject()
{
//...
}
URLObject.prototype.AddtoSyllables = function (AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
To explain the reasons of the behavior in the question, I'd like to clarify that objects in javascript are treated like a map, dictionary or a key-value pair (use the term what suits you best). Using the syntax x.y = value; is equivalent putting the value value into the map x with key y. Having the code:
this.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
adds the AddtoSyllables function as an entry to the object this points to.
The code
myobj.AdtoSyllables(...)
is equivalent to
myobj["AdtoSyllables"](...) // now a retreiaval operation
or even
var fn = myobj["AdtoSyllables"];
fn (...);
Inside the AdtoSyllables function, this is used. Against common expectations, it is not a pointer to the myobj.
The cause of this is that AddtoSyllables is treated as a static method of the URLObject class (as OOP guys would understand it), or even a loose static function (like in C). To make JS treat it like a member of the URLObject object (an instance method to OOP guys), JS must be told to do so. This is achieved through the URLObject.prototype.AddtoSyllables = .... which equivalents to declaration of an instance method.
From an alternative point of view:
function foo() { /* some code using `this` */ }
var bar = {};
var baz = {};
bar.foo = foo; // same as bar["foo"] = foo;
baz.foo = foo; // same az baz["foo"] = foo;
In the above code, this usages inside foo will neither point to bar, nor baz. At the same time bar.foo will point to the very same instance as baz.foo, for foo is also an object.

Categories

Resources