1

What exactly is the difference between

function ObjA() {
  this.a = 'text';
}

var obj = new ObjA();

and

function ObjB() {
  return {
    a: 'text'
  };
}

var obj = new ObjB();

I'm asking because I was reading this question and I've noticed the following in one of the answers:

function Test() {
  this.a = 1;

  return {
    get A() { return this.a; },
    set A(v) { this.a = v; }
  };
}

so I asked myself what is the difference between that and the following:

function Test() {
    this.a = 1;
}

Test.prototype = { 
    get A() { return this.a; },
    set A(v) { this.a = v; }
};

They say in the comments that the former "hogs up memory as the getter and setter is "unique" per each object". Could someone please elaborate on this?

Community
  • 1
  • 1
Korikulum
  • 2,529
  • 21
  • 25
  • 5
    There are really two completely different questions here; the first two things are different from each other in a different way than the second two. In the second pair, your second example actually will not work. A `var` inside a constructor function does **not** become an object property. It would have to say `this.a = 1;`. – Pointy Sep 24 '12 at 17:48
  • http://stackoverflow.com/questions/2938940/return-statement-in-js-constructors?rq=1 – Matt Ball Sep 24 '12 at 17:52
  • 3
    Please, could you change the name? Calling a class `Object` is like the worst thing to do. – Prinzhorn Sep 24 '12 at 17:55

5 Answers5

1

Your last example doesn't work.

function Test() {
    var a = 1;
}

Test.prototype = { 
    // This code has no clue what a is
    get A() { return a; },
    set A(v) { a = v; }
};

but if it were

function Test() {
    this.a = 1;
}

Test.prototype = { 
    get A() { return this.a; },
    set A(v) { this.a = v; }
};

Then the two pieces of code would be similar, except that the one that uses Test.prototype creates an instance of Test where the first example (module pattern), always creates something of the base type Object by using a Factory method

Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
1

You're actually asking a couple different questions. So let me concentrate on the first one (modifying the variable names to more easily refer to them and not overwrite Object):

What exactly is the difference between:

function ObjA() {
  this.a = 'text';
}

var objA = new ObjA();

and

function ObjB() {
  return {
    a: 'text'
  };
}

var objB = new ObjB();

The difference is that the former version maintains the prototype chain, whereas the later version discards it. Consider the following lines of code:

ObjA.prototype.b = "something";
ObjB.prototype.b = "something";

The following then becomes true:

objA.b; //is "something"
objB.b; //is undefined

The reason is that the object returned from the "constructor" does not append ObjB's prototype chain. It's a brand new object. So that's the "difference."

The second example (using .prototype vs. returning an object) actually doesn't really "waste" memory as far as I know (see update). Because the process of calling the new operator on a function will create a copy of the object's prototype and then call its function. The nice part is that the prototyped methods will be available within the "constructor" function when you use .prototype, and you'll maintain the prototype chain with that version. But I don't know that there's anything really "wrong" about using the return-based method.

UPDATE:

I checked out the ECMAScript spec on the subject (and oiled my thinking gears a bit) and it appears that I was wrong about the memory wasting. It looks like the methods/properties of the "class" function's prototype property are linked by reference. So it does actually waste a bit of memory to generate a new object rather than making use of the prototype. Additionally, any properties declared in the returned object are instance-level, whereas properties declared in the prototype object are static to the "class" (i.e. shared by all instances).

And as others have noted, your example has a small bug (a is not available to the prototype object). But that's somewhat immaterial to the question at hand, so I ignored it. (I see you fixed the bug).

Pete
  • 2,538
  • 13
  • 15
1

The difference between

function Obj () {
  this.a = 'text';
}

var obj = new Obj();

and

function Obj () {
  return {
    a: 'text'
  };
}

var obj = new Obj();

Is that the first one is considered unsafe. That is if you forget to use the new operator, you'll pollute the global namespace with properties.

The second method of defining object is much better. You can both do var obj = new Obj(); and var obj = Obj(); and the result will be exactly the same.

Furthermore using vars inside the constructor will cause that they won't be accessible from outside the scope of the constructor itself. Thus you can use them as private and define functions working as getters/setters, for example:

function Obj () {
    var privateVar = 'xxx';

    return {
        getPrivateVar: function () {
            return privateVar;
        },
        setPrivateVar: function (val) {
            privateVar = val;
        }
    };
}

This way you'll have access to the variable from outside the constructor but you won't be able to modify it without calling proper function (setter).

Using prototype is an extensive topic. It allows you to save memory (methods are shared between object instances instead of being created each time you create new object), it allows you to modify method in all instances of an object just by modifying the prototype. Moreover prototype can be used to imitate inheritance (look for "prototype chain").

I recommend reading "JavaScript: The Good Parts".

Michał Miszczyszyn
  • 11,835
  • 2
  • 35
  • 53
0

Allow you create object without private methods/function(simulatory but it is)

   function Object() {
      // a can be change via OBJECTs API
      this.a = 7;
    }

Allow use function and variable to "inner job" which will not be accessible in code

 function Object() {
      // b CAN BE CHANGED FROM OBJECTs  API 
      var b = 125;          
      return {
        a: 7+b
      };
    }
Anton Baksheiev
  • 2,211
  • 2
  • 14
  • 15
0
function Object() {
  this.a = 'text';
}
var obj = new Object();

function Object() {
  return {
    a: 'text'
  };
}
var obj = new Object();

would each be used like:

console.log(obj.a); // 'text'

However,

function Test() {
  var a = 1;

  return {
    get A() { return a; },
    set A(v) { a = v; }
  };
}
var obj = new Test();

would be used like

console.log(obj.A); // 1
obj.A = "banana";
console.log(obj.A) // 'banana'

It is making a private, and creating an external property A to get/set it. The benefit of this is that it allows you to make the property static or readonly, do calculations when getting/setting, and many other things.

Shmiddty
  • 13,847
  • 1
  • 35
  • 52