开发者

Javascript Function `Recreation´?

开发者 https://www.devze.com 2023-02-28 17:07 出处:网络
I read a lot of JavaScript code and see lots of different styles of making so-called Classes. I\'m developing a light-weight DOMish class which contains the bare minimum for my template script, runnin

I read a lot of JavaScript code and see lots of different styles of making so-called Classes. I'm developing a light-weight DOMish class which contains the bare minimum for my template script, running on Node.JS, (which transforms a DOMish instance into another DOMish instance using JSON and then serializes it to HTML, caching the original DOMish instance and cloning it per template-request).

Above is all irrelevant to my question. After reading http://www.phpied.com/3-ways-to-define-a-javascript-class/, Section 1.2. Methods defined internally

A drawback of 1.1. is that the method getInfo() is recreated every time you create a new object.

The way of defining classes, as described in Section 1.1, is (slightly modified to reflect to my own case, using local/private variables):

function Apple (type) {
    var that = this;

    // local-variable
    var color = 'red';

    // local-(extern)-function
    var infoProvider = function() { // inner-function
        // note the danger of this and that!
        return that.color + ' ' + that.type + ' ' + this.type;
    };

    this.__defineGetter__("type", function() { return type; });

    this.getInfo = function(otherContext) {
        return infoProvider.call开发者_JS百科(otherContext); // other "this" scope
    };
}

var apple = new Apple('iPod');
apple.getInfo({type: 'music player'}); // 'red iPod music player'

I happen to use the same style, as the function now has access to local/private variables and functions, defined inside the constructor. But the sentence "[The function] is recreated every time you create a new object." scares me (performance wise)! As I'm using Node, which uses V8, I always thought that functions are only created once and cached some-how, when called on different objects, using only a different context (the thises and the thats).

Should I be scared of "recreation"? How bad is it compared to prototype-based functions? Or is this purely aesthetic (people love keeping stuff together, in the constructor, VS, people love prototypes)?


Although V8 does indeed cache many things, this isn't one of those cases, as can be demonstrated by the following code:

> function foo(){ this.bar = function(){ return this.x; }; this.x = Math.random(); }
> var ary = [];
> for(var i=0; i<1000000; i++){ ary.push(new foo()); }

the above uses 144MB of memory.

> function foo(){ this.x = Math.random(); }
> foo.prototype.bar = function(){ return this.x; }
> var ary = [];
> for(var i=0; i<1000000; i++){ ary.push(new foo()); }

And this uses 68MB of memory.

Note that the V8 source header at:

http://code.google.com/p/v8/source/browse/branches/bleeding_edge/src/compilation-cache.h?r=5284

Seems to imply that the compilation of said function may indeed be cached :

The compilation cache keeps shared function infos for compiled scripts and evals. The shared function infos are looked up using the source string as the key. For regular expressions the compilation data is cached.

But the test shows that even if the compilation is compiled, new objects are still created, as if you were not creating new objects you would break JS :)

EDIT

A further test:

function foo(){
    this.bar = function(){
        this.x = '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
        return this.x;
    };
    this.x = Math.random();
}
var ary = [];
for(var i=0; i<1000000; i++){ ary.push(new foo()); }

Uses 144MB of memory. Due to the fact that I added a 100 char string, if the function itself were not cached, we would be using an extra 100MB or so of memory.

So the above indicates that yes, the function itself is cached. But it still needs to be represented by a new object.


The following code:

this.getInfo = function(otherContext) {
    return infoProvider.call(otherContext); // other "this" scope
};

...creates a new function and assigns a reference to it to the getInfo property of the newly created object. This happens every time you invoke new Apple. Each new instance gets its own copy.

However, this code:

Apple.prototype.getInfo = function(otherContext) {};

...creates one shared instance of the getInfo function, assigned to the constructor's prototype.

This difference is not purely aesthetic. It is a fundamentally different way of creating instance methods. A function is just like any other object (i.e. you can assign properties to it). For example, you could do this:

this.getInfo.classVariable = "whatever" 

This would create a new property on only one instance's getInfo function. If the function were cached then that assignment would affect all instances, which is not what's desired.

0

精彩评论

暂无评论...
验证码 换一张
取 消