Adding Prototype to JavaScript Object Literal
The prototype object is meant to be used on constructor functions, basically functions that will be called using the new operator to create new object instances.
Functions in JavaScript are first-class objects, which means you can add members to them and treat them just like ordinary objects:
var STORE = {
item : function() {
}
};
STORE.item.add = function() { alert('test 123'); };
STORE.item.add();
A typical use of the prototype object as I said before, is when you instantiate an object by calling a constructor function with the new operator, for example:
function SomeObject() {} // a constructor function
SomeObject.prototype.someMethod = function () {};
var obj = new SomeObject();
All the instances of SomeObject will inherit the members from the SomeObject.prototype
, because those members will be accessed through the prototype chain.
Every function in JavaScript has a prototype object because there is no way to know which functions are intended to be used as constructors.
Why cannot I use prototype in Object Literals in javascript?
First of all, the .prototype
property belongs to function object. You cannot access it from a plain object instance. Basically the constructor-associated .prototype
property will be used when constructing the internal [[prototype]]
of an instance. Here you are having an instance, if you want to add the function to the prototype chain of it, then you have to modify it by
var obj = { firstname: 'foo', lastname:'bar' };
var pro = Object.getPrototypeOf(obj);
pro.getMethod = function () {
console.log('this is a function');
};
As @bergi pointed out, there is a risk of adding the getMethod
to all the instances if we follow the above approach. But in order to avoid that you could alternatively do,
var obj = { firstname: 'foo', lastname:'bar' };
Object.setPrototypeOf(obj, Object.create({getMethod : function(){
console.log("Hello");
}}));
console.log(obj.getMethod()); //"Hello"
How can I attach prototype to Object Literals in JS
You can use Object.create
to use your defined objects as prototypes. For instance:
var Dog = Object.create(Animal, {
bark : {
value: function() {
console.log("Woof! My name is " + this.name);
}
}
});
Now you can create a new Dog object:
var myDog = Object.create(Dog);
myDog.bark(); // 'Woof! My name is null'
myDog.getColor(); // 'The hair color is null'
Example: http://jsfiddle.net/5Q3W7/1/
Alternatively, if you're working in the absence of Object.create
, you can use constructors:
function Animal() {
this.name = null;
this.hairColor = null;
this.legs = 4;
};
Animal.prototype = {
getName : function() {
return this.name;
},
getColor : function() {
console.log("The hair color is " + this.hairColor);
}
}
function Dog() {
}
Dog.prototype = new Animal;
Dog.prototype.bark = function() {
console.log("Woof! My name is " + this.name);
};
Example: http://jsfiddle.net/5Q3W7/2/
For more information about Object.create: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create/
For more information about Constructors and prototypes chains:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/constructor
https://developer.mozilla.org/en/JavaScript/Guide/Inheritance_and_the_prototype_chain
Object literal as prototype
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.
Changing prototype of an object which was created with literal initialization
With the current spec, you can't change an object's prototype once it's instantiated (as in, swap out one and swap in another). (But see below, things may be changing.) You can only modify the object's prototype. But that may be all you want, looking at your question.
To be clear about the distinction:
var p1 = {
foo1: function() {
console.log("foo1");
}
};
var p2 = {
foo2: function() {
console.log("foo1");
}
};
var o = Object.create(p1);
o.foo1(); // logs "foo1"
o.foo2(); // ReferenceError, there is no foo2
// You cannot now *change* o's prototype to p2.
// You can modify p1:
p1.bar1 = function() { console.log("bar1"); };
// ...and those modifications show up on any objects using p1
// as their prototype:
o.bar1(); // logs "bar1"
// ...but you can't swap p1 out entirely and replace it with p2.
Getting back to your question:
If u was created with a constructor like this...Then whatever I added to the prototype of
U
would automatically be added to every object that is created after those changes. But how do I get the same effect with Object literals?
By modifying the object you passed into Object.create
as the prototype, as above. Note how adding bar1
to p1
made it available on o
, even though o
was created before it was added. Just as with constructor functions, the prototype relationship endures, o
doesn't get a snapshot of p1
as of when it was created, it gets an enduring link to it.
ES.next is looking likely to have the "set prototype operator" (<|
), which will make it possible to do that. But there's no standard mechanism for it currently. Some engines implement a pseudo-property called __proto__
which provides this functionality now, but it's not standardized.
Object literal vs constructor+prototype
There is a (fundamental, in my opinion) difference between object literals and functions, the "private" variables. Since an object can't be instantiated(because it is already an instance of Object
) it has no possibility to have its own (new) scope. It is a base concept of advanced JS programming. Having a new scope allows you to do almost everything(you can declare your own window
, document
or whatever you want except the JS keywords inside your own scope). Now, some simple examples:
Let's assume you want to create a large number of instances of the same object(using as few lines as possible):
function MyObj(i) {
var privateCounter = "I am the instantiated object " + i + " .";
this.counter = function() {
return privateCounter;
};
}
var MyObjList = [],
ObjLitList = [];
for (var i = 0; i < 100; i++) {
MyObjList.push(new MyObj(i));
ObjLitList.push({counter: "I am the literal object number " + i + "."});
}
Now you have 200 objects that are almost, but not precisely, the same thing. You can extend them as you prefer, because functions are objects, but in the case of the function you cannot access the private
variable directly. Let's see which are the advantages of a function:
- It is treated like an
Object
- It has its own
Prototype
- It has private variables
And the Object
s?
- It is an
Object
- It doesn't have its own
Prototype
, but you can declare the functions and extend the object itself - It doesn't have private variables
Apart the private vars, they are not much different from each other.
Let's see what a function's prototype can do:
MyObj.prototype.setX = function(x) {
this.x = x;
}
Using the prototype allows you to create an only instance of an anonymous function(which can be named too and then assigned) which will be shared across instances. How can you do the same thing with object literals?
function setX(x) {
this.x = x;
}
var obj = {
setX: setX
};
As you can see you have to create the object defining everytime a property which is setX
. Otherwise, you can extend Object.prototype
itself(but there is a long debate about extending the prototype of native JS objects).
So which is the best way? There is no one, it depends on what you have to do, what you need from your script, which of the two you feel more comfortable with.
I prefer writing my own functions and treat them like classes, because they are more readable and I am able to use "private" variables. I don't know anyone using literals instead of functions though.
As for the questions:
Which is the best preferred way of programming(object literals vs constructors vs prototype)
Answered.
can a code with constructor and protoype be written using just object literals without using constructor and protoype.
Yes, you can if you don't need private variables(and if the script isn't too big. Imagine jQuery written as an Object literal :D).
what is the signifiance of anonymous function.
Oh well, I can answer with an example:
//code
myNamedFunction();
//code
function myNamedFunction() {
alert("I'm defined everywhere! :)");
}
This works and won't generate a TypeError
.
myAnonymousFunction();
var myAnonymousFunction = function() {
alert("I'm defined after this declaration :(");
}
myAnonymousFunction(); // works!
This will cause a Uncaught TypeError: undefined is not a function
, because myAnonymousFunction
is only a reference to the effective function(which is unnamed, so it is not callable from the script).
There are a lot of things to say about this argument, and a good point to start advanced programming is Javascript Garden. Other good readings are Basics of OOP in JS - NetTutsPlus, Working with Objects - MDN and OOP in JS - Phrogz
Hope this helps!
Sidenote: functions also have a good advantage since they can change their context(this
) just with a function(call
for example), while objects can't.
Object literal in object with prototypes, with funtion parameters
You're calling the method on the script
object, not the SomeThing
instance. Use either call
to set the receiver explicitly
…choose = function(data) {
var script = {
one: self.one,
two: self.two,
};
return script[data.type].call(self, data);
};
or just drop the script
object and directly use
…choose = function(data) {
if (["one", "two"].includes(data.type))
return self[data.type](data);
};
Related Topics
Appending Array to Formdata and Send via Ajax
Thickness of Lines Using Three.Linebasicmaterial
Pagination on a List Using Ng-Repeat
Es6 Promises - Something Like Async.Each
Is There a Downside to Using Es6 Template Literals Syntax Without a Templated Expression
How to Access Accelerometer/Gyroscope Data from JavaScript
How to Handle Circular Dependencies with Requirejs/Amd
How to Convert CSV to JSON in Node.Js
Unsigned Integer in JavaScript
How to Skip Over an Element in .Map()
JavaScript 'In' Operator for 'Undefined' Elements in Arrays
Find Day Difference Between Two Dates (Excluding Weekend Days)
Run JavaScript in Visual Studio Code
Understanding What Goes on with Textarea Selection with JavaScript
Angularjs Toggle Class Using Ng-Class
Differences Between Contenttype and Datatype in Jquery Ajax Function