Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object literal as prototype

Tags:

javascript

This question is more about support and backwards compatibility. I have tested the following code.

function newFunc() {}

newFunc.prototype = {

    literal : {
        init : function() {
            console.log(this);
            this.test();
        },
        test : function() {
            console.log('test');
        }
    }
}

var inst = new newFunc();

inst.literal.init();

This works, though I've not seen object literals as prototypes in any other code. Is there a reason for this? This seems like a logical way of coding to me though I don't want to pursue it if it has serious pitfalls.

like image 980
David Barker Avatar asked Nov 03 '22 21:11

David Barker


2 Answers

It's perfectly normal to use an object literal to create the prototype for a function, but normally only as the actual value of the prototype object.

What's unusual is doing what you've done and include a nested object within the prototype.

In effect you've only added one object to the prototype, the one named literal. All of the methods are then properties of that object. It's technically valid syntax, but I've never seen it used before. As @squint points out in the comments, it also appears to break the way that the this variable works, because it binds this to the "next left" property that was used in the function call:

var inst = new newFunc();
inst.literal.init();
> Object { init: function, test: function }

i.e. this has been set to point at the .literal object, and not at the actual instance that has been created.

like image 83
Alnitak Avatar answered Nov 12 '22 18:11

Alnitak


Yes, using literals for prototype is correct. For example Mozilla explicitly uses a literal in the prototype's documentation:

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

var Person = { // this is a literal
    canTalk : true,
    greet : function() { /* ... */ }
}

Customer.prototype = Person;

Some explanation: Value of prototype is an object. It doesn't matter how the object was created - using simply {} is fine. It is often initialized using something like MyClass1.prototype = new MyClass2(), but new just creates a new object. It also sets the prototype property and executes the constructor (MyClass2) but on the new object, it doesn't affect MyClass1 in any way (see explanation here).

Using a nested literal doesn't make a difference. In the question, the prototype is set to { literal : { ... } }. What actually happens when you call inst.literal.init() is:

  1. The runtime looks at inst and checks whether the object has a value assigned for property literal.
  2. inst dos not have such property, therefore the runtime continues with its prototype property
  3. inst.prototype references the literal object to which it was initialized. This object has assigned a value for property literal.
  4. inst.literal therefore evaluates to the nested literal inst.prototype.literal
  5. The literal object does have a value for property init
  6. The init() function is called

This is one of the principles of JavaScript (ECMA Script) so there should be no compatibility issues.

like image 24
Mifeet Avatar answered Nov 12 '22 17:11

Mifeet