15

i answered one question about closures here in SO with this sample:

function Constructor() {
    var privateProperty = 'private';
    var privateMethod = function(){
        alert('called from public method');
    };
    return {
        publicProperty: 'im public',
        publicMethod: function(){
            alert('called from public method');
        },
        getter: privateMethod
    }
}

var myObj = new Constructor();

//public
var pubProp = myObj.publicProperty;
myObj.publicMethod();
myObj.getter();

//private - will cause errors
myObj.privateProperty
myObj.privateMethod

a user commented on my answer saying:

Also, if your function explicitly returns an object it is not a good practice to call it with new because that is misleading - if using new you'd expect the result to be an instance of Constructor

i usually create objects using new. but why is it not a good practice? it seems like using new and not using new returns the same thing. what is the proper way of creating objects from closures?

Joseph
  • 117,725
  • 30
  • 181
  • 234

2 Answers2

11

No, it's not the same thing. Consider when using instanceof:

function C1() {
    return {};
}

function C2() {
}

var c1 = new C1();
var c2 = new C2();
alert(c1 instanceof C1); // false; wha...?
alert(c2 instanceof C2); // true, as you'd expect.

Here's a demo.

So instead, create them by assigning to this, possibly with a safeguard to prevent forgotten news.

function Constructor() {
    var privateProperty = 'private';
    var privateMethod = function() {
        alert('Called from private method');
    };

    this.publicProperty = "I'm public!";
    this.publicMethod = function() {
        alert('Called from public method');
    };
    this.getter = privateMethod;
}

Even better, use the prototype when possible:

function Constructor() {
    var privateProperty = 'private';
    var privateMethod = function() {
        alert('Called from private method');
    };

    this.getter = privateMethod;
}

Constructor.prototype.publicProperty = "I'm public!";
Constructor.prototype.publicMethod = function() {
    alert('Called from public method');
};
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • like this: http://jsfiddle.net/DZTC8/1/ both return the same thing, with or without the `new` – Joseph Feb 16 '12 at 02:47
  • 4
    @Joseph: My point is that it makes `instanceof` act weird. The returned object is *not an instance of the constructor*, as a user would expect, but rather just an Object. – Ry- Feb 16 '12 at 02:48
  • @minitech Isn't the `prototype` not a good solution as you can never access the private members? – jb10210 Apr 17 '12 at 12:01
  • @jb10210: JavaScript really has no concept of private members, just closed variables. It depends what you need to do. If you must have private variables, then those methods can be put inside the function; but then you won't be able to make direct calls. It really depends. But in the last part, I said "use the prototype where possible" - you'll notice that `this.getter` is still assigned to in the constructor because it has to access a private property. (Supposedly `:)`) The public method only needs access to the public property. – Ry- Apr 17 '12 at 13:16
  • @minitech I will quote 'private members' from now on when talking about JS :) Thanks for the response! – jb10210 Apr 17 '12 at 15:20
  • Sorry, I didn't found this as eloquent answer about when to use `new` and when not? – Amit Shah Nov 16 '17 at 03:51
  • @AmitShah: That’s because that’s not really what the question was about. – Ry- Nov 16 '17 at 04:44
2

Consider point 4 from this answer: What is the 'new' keyword in JavaScript?

"It returns the newly created object, unless the constructor function returns a non-primitive value. In this case, that non-primitive value will be returned."

So as function C1 from minitech's answer returns an empty object the variable c1 will be that returned object and not the one created by the 'new' statement. Therefore no instance of the constructor function.

If I try to return a primitive value from the constructor function my webstorm tells me: "When called with new, this value will be lost and object will be returned instead."

Community
  • 1
  • 1