Troskyvs
Troskyvs

Reputation: 8057

Why javascript function has instance per call?

The javascript introduction says: When I have code like below:

var Person=function(name){ 
     this.name=name; 
     this.sayHello=function(){return 'Hello '+name;} 
} 

Whenever I instantiate a "Person", there will be a copy of "sayHello" function in the memory. To reduce this memory consumption, I can change the code like below:

var Person=(function(){ 
     var sayHello=function(){return 'Hello '+name} 
     return function(name){ 
         this.name=name 
         this.sayHello=sayHello 
     } 
})() 

In this way, there'll not be multiple copies of sayHello()

My questions are:

  1. For the 1st type of code, what's the benefit except wasting more memory?
  2. Should we write code in the 2nd way, or javascript should avoid one copy for one function per instance?

Thanks a lot.

Upvotes: 1

Views: 88

Answers (3)

slebetman
slebetman

Reputation: 113954

The behavior you are witnessing is the result of two things:

  1. Functions as first-class objects. This means functions are treated the same way as strings, numbers, arrays etc.

  2. How local variables are treated in functions. Local variables are created (typically on the stack) each time the function is called. This allows functions to be called recursively.

This behavior exists in many different languages that have anonymous functions like Go, Perl, Lisp etc.

The two rules above means that each time you call your function the inner function gets created and assigned to the variable.

What's the advantage of this?

The primary advantage of this from the language point of view is consistency of behavior. It means functions are really treated as first-class objects just like numbers, strings etc. Treating it consistently means that people who try to use anonymous functions won't get surprised by the behavior.

How do people use this feature?

Sometimes you find yourself writing several different functions that look similar:

function double (x) {return x * 2};
function quadruple (x) {return x * 4};

Wouldn't it be nice to be able to categorize a "family" of functions that are similar and somehow write them once?

Well, in languages like C you may use a macro system to basically cut-and-paste the text you type to generate several different code.

In languages with first-class-functions you write a function to generate functions:

function makeMultiplier (factor) {
    return function (x) { return x * factor }
}

So now you can do:

var double = makeMultiplier(2);
var quadruple = makeMultiplier(4);

Now OBVIOUSLY for this to work the makeMultiplier() function MUST return two different functions. It cannot just modify a single function to do different things each time it is called. Otherwise both the double() and quadruple() functions will multiply by 4 after the second call to makeMultiplier().


Implementation detail

It is possible to create a system whereby the body of inner functions are compiled only once and the differences are captured by a closure. So all functions only occupy RAM once but different versions of a function may occupy more than one closure. It is possible that this is how it's implemented by most js engines but I don't really know. If so, then inner functions do take up additional RAM each time they're defined but not by much (typically by one stack frame - so each function definition takes up the same space as a function call).

From the programmer's point of view though, inner functions must appear to work as if they're created each call because that's how you'd expect them to work.

Upvotes: 1

Jokester
Jokester

Reputation: 5617

For the 1st type of code, what's the benefit except wasting more memory?

This could be used for access control (like private in some other languages).

Consider:

var Person=function(name){ 
   this.sayHello = function(){return 'Hello '+name;}
};

name can only be accessed by sayHello, which is a opaque Function.

Other code may replace this.sayHello, but will not be able to let this sayHello instance use another name.

Upvotes: 0

jusopi
jusopi

Reputation: 6813

For the 1st type of code, what's the benefit except wasting more memory?

The only time i'd use something like this is for quick testing of an anonymous object. An example of this would be in some sort of factory implementation:

getWidget = function(){
    return {
        foo: 'bar',
        test: function(){ ... }
    }
}

And honestly, this would be quickly replaced with proper coding conventions after I confirmed my initial testing.

Should we write code in the 2nd way, or javascript should avoid one copy for one function per instance?

I'd say no. Don't write code like this. It's unnecessarily convoluted and doesn't appear to work from what I can tell. I'd recommend just creating methods on the function prototype:

var Person = function(name){
    this.name = name;
}

Person.prototype.sayHello = function(){
    return 'Hello ' + this.name;
}

pros - easy to read - easy to manage - this is scoped properly within the context of calling methods

cons - a nominal increase in effort to code - per a comment to the question, you lose access to variables scoped exclusively to the constructor

Upvotes: 0

Related Questions