17

What is the best way to build constructors in JavaScript using object literal notation?

var myObject = {
 funca : function() {
  //...
 },

 funcb : function() {
  //...
 }
};

I want to be able to call

var myVar = new myObject(...);

And pass the arguments to a constructor function inside myObject.

5
  • What exactly do you want to achieve? Commented Mar 3, 2011 at 10:26
  • I am looking for the best way to define class like structures in JavaScript. I am aware that you can do it through prototyping, but looking around on the web, I have found more and more javascript libraries using object literal (not JSON ;) ) notation, rather than prototyping... why is this? Commented Mar 3, 2011 at 10:30
  • Can you give any particular example? If one needs only one object of a kind, then there is no need to have a constructor function. Commented Mar 3, 2011 at 10:33
  • @Felix I am looking for a more general case... I am building a javascript library and am looking for the best way to implement a class like structure. Multiple instances of the same object can occur in the same script. So... my end result would be something like .... var o = new myObject(someArgs); ... o.doSomething(someArg); ... o.doSomethingElse(someArg);... I can implement this using prototyping, but have seen the above notation use more and more recently and so was wondering if it is a better approach to take. Commented Mar 3, 2011 at 10:48
  • There is no other way. Using prototype is the most efficient one. What you have seen might have been special cases, where other requirements had to be fulfilled. But without knowing them it is hard to tell what others did... Commented Mar 3, 2011 at 10:53

7 Answers 7

49

This is not "JSON notation", this is JavaScript object literal notation. JSON is only a subset of JS object literal notation, but apart from looking similar, they have nothing in common. JSON is used as data exchange format, like XML.

It is not possible what you want to do.

var myObject = {};

creates already an object. There is nothing what you can instantiate.

You can however create a constructor function and add the methods to its prototype:

function MyObject(arg1, arg2) {
    // this refers to the new instance
    this.arg1 = arg1;
    this.arg2 = arg2;

    // you can also call methods
    this.funca(arg1);
}

MyObject.prototype = {
 funca : function() {
  // can access `this.arg1`, `this.arg2`
 },

 funcb : function() {
  // can access `this.arg1`, `this.arg2`
 }
};

Every object you instantiate with new MyObject() will inherit the properties of the prototype (actually, the instances just get a reference to the prototype object).

More about JavaScript objects and inheritance:


Update2:

If you have to instantiate many objects of the same kind, then use a constructor function + prototype. If you only need one object (like a singleton) then there is no need to use a constructor function (most of the time). You can directly use object literal notation to create that object.

Sign up to request clarification or add additional context in comments.

9 Comments

+1, but maybe write a small example to show the OP the a good pattern of usage.
Oops, quite right... I have edited my post to say object literal instead of JSON. Thanks.
Re: Update, see my comment on my OP, this is not about returning objects, but looking for the best way to define the structure of my objects.
Re: Update2... this is exactly what I am looking for. Best of both world. Thanks.
you shouldn't overwrite the prototype directly. You can add to it like this: MyObject.prototype.funca = function() { // do stuff }; MyObject.prototype.funcb = function() { // do stuff };
|
8

Make the object a function, like this:

var myObject = function(arg1){
  this.funca = function(){
    //...
  };
  this.funcb = function(){
    //...
  };
  this.constructor = function(obj){
    alert('constructor! I can now use the arg: ' + obj.name);
  };
  this.constructor(arg1);
};

// Use the object, passing in an initializer:
var myVar = new myObject({ name: 'Doug'});

5 Comments

You are not passing JSON. You are passing a JavaScript object.
The JSON specification is designed to be interchangeable with JavaScript objects. Did you know that JSON is an acronym for JavaScript Object Notation? Wiki's first paragraph sums it up well: en.wikipedia.org/wiki/JSON
That does not change anything of that fact that JSON !== JavaScript object. JSON is not JavaScript and JavaScript is not JSON. You can use JSON in much more environments than you can use JavaScript. A JavaScript object is just the representation of JSON in JavaScript. In Java or Python it would be a Java or Python object. json.org says: JSON is a text format that is completely language independent (...). In your example, { name: 'Doug' } is (a) not text and (b) does not even conform to the JSON syntax. It would be JSON, if you pass the string '{"name": "Doug"}'.
I could have added an eval, and there you had it. But okay then, I changed my answer to exclude the JSON derived object. However, I think that my answer was spot on what he was looking for (before you edited yours to include the same constructor logic as mine). The JSON was not the main issue (and the current edited question doesn't even include the word).
I did not say that your answer was wrong. But it is important to use the right terminology and to make people aware that JSON is not JavaScript object literal syntax. Using a common (and right) terminology is the key for communication. Anything else creates confusion and misunderstandings...
4
var myObject = function(arg){
    return{
        constructor: function(arg){
            //...
            return this;
        },

        funca: function(){
            //...
        },

        funcb: function(){
            //...
        }
    }.constructor(arg);
};

//...

var myVar = new myObject("...");

1 Comment

Great, this is what I was looking for. SO the "secret" is yust creating any method (returning the this) and calling it directly on the literal.
3

Sorry for being late to the party, but... I think saying that this is not possible is a little restrictive depending on how you interpret the OP's question and subsequent comments.

Assuming the OP wanted the namespacing benefits that object literal notation can bring to a library but also wanted to have some "classes" to use within that structure. Could you not use something of this form to combine constructor patterns in to an object literal notation namespaced library structure?

var myNamespace = {
    aProperty: "A value",

    aMethod: function () { return "A method result"; },

    onePlusOneEquals: function () {
        return new myNamespace.classes.NumberStuff(1, 1).added;
    },

    classes: {
        ClassA: function () {
            this.propertyOne = null;
            this.methodOne = function (param) {
                return "The method was passed " + param;
            }
        },

        NumberStuff: function (argOne, argTwo) {
            this.added      = argOne + argTwo;
            this.subtracted = argOne - argTwo;
        }
    }
};

myNamespace.classes.ClassA.prototype.methodTwo = function () { return "At least this one's not bloating our memory footprint with every ClassA created..."; };

...

var anObj = new myNamespace.classes.ClassA();
alert(anObj.methodOne("the parcel")); // "The method was passed the parcel"
alert(myNamespace.onePlusOneEquals()); //2

They're silly examples, but is there any reason not to do this, or why this isn't valid? It gets rid of the global crowding problem that people usually want to use object literal notation for with libraries.

2 Comments

good example, I have actually a similar problem but it also involved in-heritage. Do you have any idea on how could be solved? Thanks stackoverflow.com/questions/19677089/…
Thanks. I've just taken a look and glad to see it seems like you've already got your question answered.
2

The simplest way I know is:

function test(arg1, arg2) {
  var1 = arg1;
  var2 = arg2;
  return {
    var3 : var1, // json can access var1
    var4 : var2 // json can access var2
  };
}

arg1 = 'test';
arg2 = function() {
  window.alert('test')
};
var5 = new test(arg1, arg2);
var5.var4();

Comments

2
var myObject = {
 funca : function() {
  //...
 },

 funcb : function() {
  //...
 }
};

you can not create a new object of above this way

var myVar = new myObject(...);

but you can achieve the same with below construct,

var myVar = Object.create(myObject );

Comments

0

Well, calling new on the object literal is not possible, as others already answered.

But calling new on the object literal constructor is possible.

var obj = {
  arg1: null,
  arg2: null
};

var obj1 = new obj.constructor();
var obj2 = new obj.constructor();

obj1.arg1 = 1;
obj2.arg1 = 2;

console.log("obj2.arg1:", obj2.arg1);
console.log("obj1.arg1:", obj1.arg1);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.