Javascript 1.9.3 / ECMAScript 5 introduces Object.create, which Douglas Crockford amongst others has been advocating for a long time. How do I replace new in the code below with Object.create?
var UserA = function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
}
UserA.prototype.sayHello = function() {
console.log('Hello '+ this.name);
}
var bob = new UserA('bob');
bob.sayHello();
(Assume MY_GLOBAL.nextId exists).
The best I can come up with is:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB);
bob.init('Bob');
bob.sayHello();
There doesn't seem to be any advantage, so I think I'm not getting it. I'm probably being too neo-classical. How should I use Object.create to create user 'bob'?
With only one level of inheritance, your example may not let you see the real benefits of Object.create.
This methods allows you to easily implement differential inheritance, where objects can directly inherit from other objects.
On your userB example, I don't think that your init method should be public or even exist, if you call again this method on an existing object instance, the id and name properties will change.
Object.create lets you initialize object properties using its second argument, e.g.:
var userB = {
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB, {
'id' : {
value: MY_GLOBAL.nextId(),
enumerable:true // writable:false, configurable(deletable):false by default
},
'name': {
value: 'Bob',
enumerable: true
}
});
As you can see, the properties can be initialized on the second argument of Object.create, with an object literal using a syntax similar to the used by the Object.defineProperties and Object.defineProperty methods.
It lets you set the property attributes (enumerable, writable, or configurable), which can be really useful.
There is really no advantage in using Object.create(...) over new object.
Those advocating this method generally state rather ambiguous advantages: "scalability", or "more natural to JavaScript" etc.
However, I have yet to see a concrete example that shows that Object.create has any advantages over using new. On the contrary there are known problems with it. Sam Elsamman describes what happens when there are nested objects and Object.create(...) is used:
var Animal = {
traits: {},
}
var lion = Object.create(Animal);
lion.traits.legs = 4;
var bird = Object.create(Animal);
bird.traits.legs = 2;
alert(lion.traits.legs) // shows 2!!!
This occurs because Object.create(...) advocates a practice where data is used to create new objects; here the Animal datum becomes part of the prototype of lion and bird, and causes problems as it is shared. When using new the prototypal inheritance is explicit:
function Animal() {
this.traits = {};
}
function Lion() { }
Lion.prototype = new Animal();
function Bird() { }
Bird.prototype = new Animal();
var lion = new Lion();
lion.traits.legs = 4;
var bird = new Bird();
bird.traits.legs = 2;
alert(lion.traits.legs) // now shows 4
Regarding, the optional property attributes that are passed into Object.create(...), these can be added using Object.defineProperties(...).
Object.create is not yet standard on several browsers, for example IE8, Opera v11.5, Konq 4.3 do not have it. You can use Douglas Crockford's version of Object.create for those browsers but this doesn't include the second 'initialisation object' parameter used in CMS's answer.
For cross browser code one way to get object initialisation in the meantime is to customise Crockford's Object.create. Here is one method:-
Object.build = function(o) {
var initArgs = Array.prototype.slice.call(arguments,1)
function F() {
if((typeof o.init === 'function') && initArgs.length) {
o.init.apply(this,initArgs)
}
}
F.prototype = o
return new F()
}
This maintains Crockford prototypal inheritance, and also checks for any init method in the object, then runs it with your parameter(s), like say new man('John','Smith'). Your code then becomes:-
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}} // For example
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.build(userB, 'Bob'); // Different from your code
bob.sayHello();
So bob inherits the sayHello method and now has own properties id=1 and name='Bob'. These properties are both writable and enumerable of course. This is also a much simpler way to initialise than for ECMA Object.create especially if you aren't concerned about the writable, enumerable and configurable attributes.
For initialisation without an init method the following Crockford mod could be used:-
Object.gen = function(o) {
var makeArgs = arguments
function F() {
var prop, i=1, arg, val
for(prop in o) {
if(!o.hasOwnProperty(prop)) continue
val = o[prop]
arg = makeArgs[i++]
if(typeof arg === 'undefined') break
this[prop] = arg
}
}
F.prototype = o
return new F()
}
This fills the userB own properties, in the order they are defined, using the Object.gen parameters from left to right after the userB parameter. It uses the for(prop in o) loop so, by ECMA standards, the order of property enumeration cannot be guaranteed the same as the order of property definition. However, several code examples tested on (4) major browsers show they are the same, provided the hasOwnProperty filter is used, and sometimes even if not.
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}}; // For example
var userB = {
name: null,
id: null,
sayHello: function() {
console.log('Hello '+ this.name);
}
}
var bob = Object.gen(userB, 'Bob', MY_GLOBAL.nextId());
Somewhat simpler I would say than Object.build since userB does not need an init method. Also userB is not specifically a constructor but looks like a normal singleton object. So with this method you can construct and initialise from normal plain objects.
TL;DR:
new Computer() will invoke the constructor function Computer(){} for one time, while Object.create(Computer.prototype) won't.
All the advantages are based on this point.
Sidenote about performance: Constructor invoking like new Computer() is heavily optimized by the engine, so it may be even faster than Object.create.
You could make the init method return this, and then chain the calls together, like this:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
return this;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB).init('Bob');
Another possible usage of Object.create is to clone immutable objects in a cheap and effective way.
var anObj = {
a: "test",
b: "jest"
};
var bObj = Object.create(anObj);
bObj.b = "gone"; // replace an existing (by masking prototype)
bObj.c = "brand"; // add a new to demonstrate it is actually a new obj
// now bObj is {a: test, b: gone, c: brand}
Notes: The above snippet creates a clone of an source object (aka not a reference, as in cObj = aObj). It benefits over the copy-properties method (see 1), in that it does not copy object member properties. Rather it creates another -destination- object with it's prototype set on the source object. Moreover when properties are modified on the dest object, they are created "on the fly", masking the prototype's (src's) properties.This constitutes a fast an effective way of cloning immutable objects.
The caveat here is that this applies to source objects that should not be modified after creation (immutable). If the source object is modified after creation, all the clone's unmasked properties will be modified, too.
Fiddle here(http://jsfiddle.net/y5b5q/1/) (needs Object.create capable browser).
I think the main point in question - is to understand difference between new and Object.create approaches. Accordingly to this answer and to this video new keyword does next things:
Creates new object.
Links new object to constructor function (prototype).
Makes this variable point to the new object.
Executes constructor function using the new object and implicit perform return this;
Assigns constructor function name to new object's property constructor.
Object.create performs only 1st and 2nd steps!!!
In code example provided in question it isn't big deal, but in next example it is:
var onlineUsers = [];
function SiteMember(name) {
this.name = name;
onlineUsers.push(name);
}
SiteMember.prototype.getName = function() {
return this.name;
}
function Guest(name) {
SiteMember.call(this, name);
}
Guest.prototype = new SiteMember();
var g = new Guest('James');
console.log(onlineUsers);
As side effect result will be:
[ undefined, 'James' ]
because of Guest.prototype = new SiteMember();
But we don't need to execute parent constructor method, we need only make method getName to be available in Guest.
Hence we have to use Object.create.
If replace Guest.prototype = new SiteMember();
to Guest.prototype = Object.create(SiteMember.prototype); result be:
[ 'James' ]
Sometimes you cannot create an object with NEW but are still able to invoke the CREATE method.
For example: if you want to define a Custom Element it must derive from HTMLElement.
proto = new HTMLElement //fail :(
proto = Object.create( HTMLElement.prototype ) //OK :)
document.registerElement( "custom-element", { prototype: proto } )
The advantage is that Object.create is typically slower than new on most browsers
In this jsperf example, in a Chromium, browser new is 30 times as fast as Object.create(obj) although both are pretty fast. This is all pretty strange because new does more things (like invoking a constructor) where Object.create should be just creating a new Object with the passed in object as a prototype (secret link in Crockford-speak)
Perhaps the browsers have not caught up in making Object.create more efficient (perhaps they are basing it on new under the covers ... even in native code)
Summary:
Object.create() is a Javascript function which takes 2 arguments and returns a new object.
The first argument is an object which will be the prototype of the newly created object
The second argument is an object which will be the properties of the newly created object
Example:
const proto = {
talk : () => console.log('hi')
}
const props = {
age: {
writable: true,
configurable: true,
value: 26
}
}
let Person = Object.create(proto, props)
console.log(Person.age);
Person.talk();
Practical applications:
The main advantage of creating an object in this manner is that the prototype can be explicitly defined. When using an object literal, or the new keyword you have no control over this (however, you can overwrite them of course).
If we want to have a prototype The new keyword invokes a constructor function. With Object.create() there is no need for invoking or even declaring a constructor function.
It can Basically be a helpful tool when you want create objects in a very dynamic manner. We can make an object factory function which creates objects with different prototypes depending on the arguments received.
You have to make a custom Object.create() function. One that addresses Crockfords concerns and also calls your init function.
This will work:
var userBPrototype = {
init: function(nameParam) {
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
function UserB(name) {
function F() {};
F.prototype = userBPrototype;
var f = new F;
f.init(name);
return f;
}
var bob = UserB('bob');
bob.sayHello();
Here UserB is like Object.create, but adjusted for our needs.
If you want, you can also call:
var bob = new UserB('bob');
While Douglas Crockford used to be a zealous advocate of Object.create() and he is basically the reason why this construct actually is in javascript, he no longer has this opinion.
He stopped using Object.create, because he stopped using this keyword altogether as it causes too much trouble. For example, if you are not careful it can easily point to the global object, which can have really bad consequences. And he claims that without using this Object.create does not make sense anymore.
You can check this video from 2014 where he talks at Nordic.js:
https://www.youtube.com/watch?v=PSGEjv3Tqo0
new and Object.create serve different purposes. new is intended to create a new instance of an object type. Object.create is intended to simply create a new object and set its prototype. Why is this useful? To implement inheritance without accessing the __proto__ property. An object instance's prototype referred to as [[Prototype]] is an internal property of the virtual machine and is not intended to be directly accessed. The only reason it is actually possible to directly access [[Prototype]] as the __proto__ property is because it has always been a de-facto standard of every major virtual machine's implementation of ECMAScript, and at this point removing it would break a lot of existing code.
In response to the answer above by 7ochem, objects should absolutely never have their prototype set to the result of a new statement, not only because there's no point calling the same prototype constructor multiple times but also because two instances of the same class can end up with different behavior if one's prototype is modified after being created. Both examples are simply bad code as a result of misunderstanding and breaking the intended behavior of the prototype inheritance chain.
Instead of accessing __proto__, an instance's prototype should be written to when an it is created with Object.create or afterward with Object.setPrototypeOf, and read with Object.getPrototypeOf or Object.isPrototypeOf.
Also, as the Mozilla documentation of Object.setPrototypeOf points out, it is a bad idea to modify the prototype of an object after it is created for performance reasons, in addition to the fact that modifying an object's prototype after it is created can cause undefined behavior if a given piece of code that accesses it can be executed before OR after the prototype is modified, unless that code is very careful to check the current prototype or not access any property that differs between the two.
Given
const X = function (v) { this.v = v };
X.prototype.whatAmI = 'X';
X.prototype.getWhatIAm = () => this.whatAmI;
X.prototype.getV = () => this.v;
the following VM pseudo-code is equivalent to the statement const x0 = new X(1);:
const x0 = {};
x0.[[Prototype]] = X.prototype;
X.prototype.constructor.call(x0, 1);
Note although the constructor can return any value, the new statement always ignores its return value and returns a reference to the newly created object.
And the following pseudo-code is equivalent to the statement const x1 = Object.create(X.prototype);:
const x0 = {};
x0.[[Prototype]] = X.prototype;
As you can see, the only difference between the two is that Object.create does not execute the constructor, which can actually return any value but simply returns the new object reference this if not otherwise specified.
Now, if we wanted to create a subclass Y with the following definition:
const Y = function(u) { this.u = u; }
Y.prototype.whatAmI = 'Y';
Y.prototype.getU = () => this.u;
Then we can make it inherit from X like this by writing to __proto__:
Y.prototype.__proto__ = X.prototype;
While the same thing could be accomplished without ever writing to __proto__ with:
Y.prototype = Object.create(X.prototype);
Y.prototype.constructor = Y;
In the latter case, it is necessary to set the constructor property of the prototype so that the correct constructor is called by the new Y statement, otherwise new Y will call the function X. If the programmer does want new Y to call X, it would be more properly done in Y's constructor with X.call(this, u)
new Operator
This is used to create object from a constructor function
The new keywords also executes the constructor function
function Car() {
console.log(this) // this points to myCar
this.name = "Honda";
}
var myCar = new Car()
console.log(myCar) // Car {name: "Honda", constructor: Object}
console.log(myCar.name) // Honda
console.log(myCar instanceof Car) // true
console.log(myCar.constructor) // function Car() {}
console.log(myCar.constructor === Car) // true
console.log(typeof myCar) // object
Object.create
You can also use Object.create to create a new object
But, it does not execute the constructor function
Object.create is used to create an object from another object
const Car = {
name: "Honda"
}
var myCar = Object.create(Car)
console.log(myCar) // Object {}
console.log(myCar.name) // Honda
console.log(myCar instanceof Car) // ERROR
console.log(myCar.constructor) // Anonymous function object
console.log(myCar.constructor === Car) // false
console.log(typeof myCar) // object
I prefer a closure approach.
I still use new.
I don't use Object.create.
I don't use this.
I still use new as I like the declarative nature of it.
Consider this for simple inheritance.
window.Quad = (function() {
function Quad() {
const wheels = 4;
const drivingWheels = 2;
let motorSize = 0;
function setMotorSize(_) {
motorSize = _;
}
function getMotorSize() {
return motorSize;
}
function getWheelCount() {
return wheels;
}
function getDrivingWheelCount() {
return drivingWheels;
}
return Object.freeze({
getWheelCount,
getDrivingWheelCount,
getMotorSize,
setMotorSize
});
}
return Object.freeze(Quad);
})();
window.Car4wd = (function() {
function Car4wd() {
const quad = new Quad();
const spareWheels = 1;
const extraDrivingWheels = 2;
function getSpareWheelCount() {
return spareWheels;
}
function getDrivingWheelCount() {
return quad.getDrivingWheelCount() + extraDrivingWheels;
}
return Object.freeze(Object.assign({}, quad, {
getSpareWheelCount,
getDrivingWheelCount
}));
}
return Object.freeze(Car4wd);
})();
let myQuad = new Quad();
let myCar = new Car4wd();
console.log(myQuad.getWheelCount()); // 4
console.log(myQuad.getDrivingWheelCount()); // 2
console.log(myCar.getWheelCount()); // 4
console.log(myCar.getDrivingWheelCount()); // 4 - The overridden method is called
console.log(myCar.getSpareWheelCount()); // 1
Feedback encouraged.
I would like to implement the following behavior in JS. Please note that the syntax is symbolic.
This is my parent class
class = TList {
FList: array;
function AddElement(Ele) {
Flist.Add(Ele)
};
function RemoveEle(Ele) {
FList.Remove(Ele)
};
}
Now I'm going to inherit from this class. My child class should automatically have all the properties of the parent and should be able to extend them without rewriting the code.
class = TAlertList(inherit from TList) {
function AddElement(Ele) {
Alert('element will be added');
call.parent.AddElement(Ele)
};
function RemoveElement(Ele) {
call.parent.RemoveElement(Ele);
Alert('element removed');
}
}
Please note how I inherit the parent methods at places I wish.
Now I should be able to create an object from my child class and do the following.
MyAlertList = new TAlertList;
MyAlertList.Add('hello');
console.log(MyAlertList.FList);
I should be able to inherit more child classes from TAlertList and be able to change the existing behavior. I need to do this in pure ES5 without using any libraries. Standard OOP practices are expected.
Please note that the TList constructor should be applied to the TAlertList instance;
ES5, first set up the base constructor
function TList() {
this.Flist = [];
// ...
}
TList.prototype = {
constructor: TList,
AddElement: function AddElement(Ele) {
this.Flist.push(Ele);
},
RemoveEle: function RemoveEle(Ele) {
var i = this.Flist.lastIndexOf(Ele);
if (i !== -1)
this.Flist.splice(i, 1);
}
};
Next set up the constructor which extends it, see how this means calling the base constructor on the instance being created by the extended constructor and creating a prototype object which inherits the prototype of the base constructor
function TAlertList() {
// construct from base
TList.call(this);
// further construct
// ...
}
TAlertList.prototype = Object.create(TList.prototype);
TAlertList.prototype.constructor = TAlertList;
// depending on how you want to reference stuff
TAlertList.prototype.AddElement = function AddElement(Ele) {
alert('element will be added');
TList.prototype.AddElement.call(this, Ele);
};
TAlertList.prototype.RemoveElement = function RemoveElement(Ele) {
TList.prototype.RemoveEle.call(this, Ele);
alert('element removed');
};
ES6 syntax makes use of the super keyword
class TList {
constructor() {
this.FList = [];
}
AddElement(Ele) {
this.Flist.push(Ele);
}
RemoveEle(Ele) {
var i = this.Flist.lastIndexOf(Ele);
if (i !== -1)
this.Flist.splice(i, 1);
}
}
class TAlertList extends TList {
constructor() {
super();
}
AddElement(Ele) {
alert('element will be added');
super.AddElement(Ele);
}
RemoveElement(Ele) {
super.RemoveEle(Ele);
alert('element removed');
}
}
Back to ES5, generalising as a factory so you can see a sort of algorithm of how to do it
function extend(baseConstructor, extendedConstructor, prototypeLayer) {
function Constructor() {
var i = 0, j = 0, args = Array.prototype.slice.call(arguments);
i = j, j += baseConstructor.length;
baseConstructor.apply(this, args.slice(i, j));
i = j, j = args.length;
extendedConstructor.apply(this, args.slice(i, j));
}
Object.defineProperty(Constructor, 'length', { // fix .length
value: baseConstructor.length + extendedConstructor.length,
configurable: true
});
Constructor.prototype = Object.create(baseConstructor.prototype);
Constructor.prototype.constructor = Constructor;
Object.assign(Constructor.prototype, prototypeLayer);
return Constructor;
}
So then
function Foo(x) {this.foo = x;}
Foo.prototype.fizz = 1;
var Bar = extend(Foo, function (x) {this.bar = x;}, {buzz: 1});
// ...
var b = new Bar('foo', 'bar');
b.foo; // "foo"
b.bar; // "bar"
b instanceof Foo; // true
b instanceof Bar; // true
b.fizz; // 1
b.buzz; // 1
Please note that this is an example of the algorithm you should be following when you write each extended constructor, not production code
Your code would be the following
function TList(){
this.FList = [];
}
TList.prototype.AddElement = function(Ele){
this.FList.push(Ele);
}
TList.prototype.RemoveElement = function(Ele){
this.FList.splice(Ele,1); //Ele is the index to remove;
}
This is an approximation to know how the inherit works in JavaScript.
function TAlertList (){
TList.call(this);
}
TAlertList.prototype = Object.create(TList.prototype);
TAlertList.prototype.constructor = TAlertList;
TAlertList.prototype.AddElement = function(ele){
alert('Element will be added');
TList.prototype.AddElement.call(this,ele);
};
TAlertList.prototype.RemoveElement = function(ele){
alert('Element will be remove');
TList.prototype.RemoveElement.call(this,ele);
};
So, the classic super call is
ParentClass.prototype.myMethod.call(this,args);
This is Q&A
Edit - Don't forget to read #paul's comment too if you planning to read the full text.
Almost all the answers came in were based on the popular "Person" example in the MDN documentation about JS OOP.
The theory behind this method is to put the fields of the object inside a constructor function while implementing the methods in a prototype object. A child object can inherit all the fields by calling the constructor function with a contrived this value. Also it can inherit all the methods by having the same prototype object of the parent as it's prototype object too. The only rule is that you need to call the methods using call or apply to point the methods to the correct this object when implementing inheritance.
I didn't like this approach for two reasons.
The fields and methods of an objects has to be separated between two objects (fields - constructor function, methods - prototype). This doesn't have the flavor of a unique behavior of a unique entity - which should be a single class.
You have to specify the name of the parent object when inheriting. This is not automatic. Let's say object C inherits from the object A. So, inside the methods of the object C, you need to mention object A when inheriting from it. (TList.prototype.AddElement.call(this, Ele);) What if object B comes in between later on? You will have to change all the inheriting methods of C to call from B. This is in no way near good inheritance.
I wanted to overcome these problems in MDN method. I came up with the following model with no this no call and no apply. Code is simple and easy to follow. You don't have to mention the name of the parent object when inheriting from it. So, a new class can come in between the parent and the child at any time without too many changes. Please discuss this and point out the weaknesses of this model.
Here is the function which returns the parent object.
function tList() {
var ret = Object.create(null);
ret.list = [];
ret.addElement = fucntion(ele) {
ret.list.push(ele)
};
return ret;
}
//You can create tList object like this:
var myList = tList();
myList.addElement('foo');
Now comes the child object:
function tAlertList() {
var ret = Object.create(tList());
//Lets inherit with the fashion of overriding a virtual method
ret.addElement = function(ele) {
//Here is new code
alert('Adding element ' + ele);
//Automatic inheritance now
Object.getPrototypeOf(ret).addElement(ele);
}
return ret;
}
//Just create the child object and use it
var myAlertList = tAlertList();
myAlertList.addElement('buzz') ;
You can have grand children object and inherit from parent without mentioning their names. Let's say you have to put tCustomList between tList and tAlertList. All you have to do is to tell the tAlertList to inherit from tCustomList in a single place. (var ret = Object.create(tCustomList());) Everything else remain the same.
Here is the fiddle.
With pure ES5, you could do it like this:
function TList() {
this.FList = []; //not really ideal.
}
TList.prototype.addElement = function(ele) {
this.FList.push(ele);
};
TList.prototype.removeElement = function(ele) {
this.FList.splice(this.FList.indexOf(ele), 1);
}
function TAlertList(){
this.FList = [];
}
TAlertList.prototype = new TList(); //inherit from TList
TAlertList.prototype.constructor = TAlertList; //reset constructor
TAlertList.prototype.addElement = function(ele) {
alert('element will be added');
TList.prototype.addElement.call(this, ele);
};
TAlertList.prototype.removeElement = function(ele) {
alert('element removed');
TList.prototype.removeElement.call(this, ele);
};
Couple of notes:
The FList property of its parent will actually be shared amongst all objects that inherit from the parent unless overwritten. That means that if you don't overwrite FList you'll get this:
var a = new TAlertList();
var b = new TAlertList();
a.push(1); //b.Flist === [1]
In my opinion, it would be best if you named your children functions with other names different from the parent. This way you don't need to do:
TList.prototype.function.call(this, parameter1, parameter2, ..);
You can just call them like this:
this.function(paremeter1, parameter2);
Of course, it's not a static way to call the parent as you can overwrite the function with your own. Then again TList.prototype.function isn't necessary the function of the parent of the object that owns the function. For that you'd need to use non-standard ES5 __proto__ property.
this.__proto__.function.call(this, parameter1, parameter2, ..);
Unless you plan on juggling the function around different objects, you don't need that.
I am trying to understand what is going on here:
if (!Object.create) {
Object.create = (function () {
var F = function(){};
return function (o) {
if (arguments.length !== 1) {
throw new Error('Object.create implementation only accepts one parameter.');
}
F.prototype = o;
return new F();
};
}());
}
what does F.prototype mean... How does returning a function work
These are two separate questions. The concept of a prototype and what it means is separate from the concept of returning functions. I will do my best to try and explain.
What does F.prototype mean?
Javascript does not support inheritance in the classical sense, but rather uses prototype inheritance to pass object properties from one function to another.
All Javascript objects contain a prototype field by default. The prototype field is always initially set to the base Object object. (You can create a new instance of Object by doing
var x = new Object() or by doing var x = {}.) You can create objects that set the prototype to another object thereby gaining access to their methods and properties that are placed on the prototype.
Let's walk through an example to illustrate.
Consider you create a constructor to create a Bird object.
function Bird(name) {
var me = this;
this.name = name;
this.flying = false;
this.fly = function() { me.flying = true; };
}
Bird.prototype.fly = function() { this.flying = true; }
Bird.prototype.land = function() { this.flying = false; }
If we look at the details of this object (which you can do using console.dir(obj), or by using Chrome developer tools):
Now consider you want to create another bird object that implements the Object Bird. You would do something like this.
function Duck(name) {
this.name = name;
this.quack = function() {
console.log("quack");
}
}
If you look at the details of this object you see:
Now if you want to make the duck fly, you do not have a method on it yet. You need to set the prototype of Duck to be Bird. You do that by doing something like this:
function Duck(name) {
this.name = name;
this.quack = function() {
console.log("quack");
}
}
Duck.prototype = new Bird();
Now when you look at the details of the object you will see that the prototype is now set to bird.
In short prototypes are used to provide code reuse among objects. Programmers coming from object oriented backgrounds can use prototypes to provide the same mechanisms as inheritance. Mozilla has a good article that goes into more depth.
How does returning a function work?
Javascript is a functional programming language. One of the principles of the functional programming paradigm is the existence function as first class objects. Among other things this means that functions are treated the same as any other object.
A function returning a function means nothing different then a function that returns a string.
function getString() {
return "I am a string";
}
You can use the result of this function in whatever way you choose. A function that returns a function is the same way.
function getFunctionToGetSomethingImportant() {
return function() {
return "I am something important";
}
}
Now when you want to get a function that returns a function that does something important you can do this:
var x = getFunctionToGetSomethingImportant();
x();
Despite these use cases having little value, using functions as first class objects is incredibly valuable. Functions can be treated like other objects which means they can be passed into other functions as parameters (a concept called higher order functions).
function filter(list, function(element) {
return element < 0;
});
The function filter takes as its second parameter a function that takes an element parameter. An implementation of filter would loop through each element in list and apply the function given as the second paramater. This is one example of many important use cases of functions as first class objects. This wiki article contains more information.
Initialy F is empty function and new F() returns empty object, i.e {}
after
F.prototype = o
F as class gets properties of the object o
for example if o={a:1}, then new F() returns {a:1}
this is the same like you define F as
F = function(){
this.a = 1;
}
but in your example you can create new object based on the class of object o passed to the create() function
function dostuff() {
return function () {console.log('hello')}
}
f = dostuff();
f();
--output:--
hello
.
Array.prototype.greet = function() {console.log('hello')};
[1, 2, 3].greet();
--output:--
hello
.
function Dog(name) {
this.name = name;
this.speak = function() {console.log('Ruff, ruff!') };
}
mydog = new Dog("Joey")
console.log(mydog.name);
mydog.speak();
--output:--
Joey
Ruff, ruff!
.
function Dog() {
}
Dog.prototype.speak = function() {console.log("Ruff, ruff!")};
mydog = new Dog();
mydog.speak();
--output:--
Ruff, ruff!
.
function Dog() {
}
var obj = {
name: "Joey",
speak: function() {console.log("Ruff, ruff!")}
}
Dog.prototype = obj;
mydog = new Dog();
console.log(mydog.name);
mydog.speak();
--output:--
Joey
Ruff, ruff!
obj.jump = function() {console.log("Look at me jump!")};
mydog.jump();
--output:--
Look at me jump!
.
var F = function() {
};
var o = {
"greet": function() {console.log('hello')}
};
F.prototype = o;
f = new F();
f.greet();
--output:--
hello
I have a JavaScript object defined like so:
var Object = (function () {
function Object() {
this.id = RandomNumber();
}
// Custom Object.prototype / Object impementations here...
return Object;
})();
The problem is that once this has been constructed, it loses original functionality like Object.defineProperty etc.
The idea is that I want to extend the basic functionality of Object, not re-write or overwrite the existing prototype.
How can this be achieved?
EDIT: Just to be clear, I know I can do this without affecting the original functionality:
Object.prototype.foo = function() { }
but I need to specifically add functionality to Object's constructor, i.e.
function Object() { this.id = 0; }
The new functionality must not overwrite the original Functionality.
Use the .prototype to add a property:
Object.prototype.specialMethod = function () {
// Your method's code
};
And you'd use it like:
var a = {};
a.specialMethod();
Although I would discourage adding a property to the Object's prototype, because it is enumerable and will mess up looping, and will be inherited by all objects, and objects that inherit from Object, which is basically everything.
You could actually use the Object.defineProperty method you mention:
Object.defineProperty(Object.prototype, "specialMethod", {
enumerable: false, // The important one, to avoid looping problems
configurable: false,
writable: false,
value: function () {
// Your method's code
}
});
Do as Ian wrote. If you also want to check it the method already exists use
if (Object.prototype.specialMethod == null) Object.prototype.specialMethod = function() { ... };
In order to extend this object you should create another object that has its prototype assigned a new instance of Object.
var Object = (function () {
function Object() {
this.id = 5;
}
Object.prototype.speak = function(prop){
alert(this[prop]);
}
return Object;
})();
function ExtendsObject(prop){
this.someProperty = prop;
}
ExtendsObject.prototype = new Object();
var xObj = new ExtendsObject("derived");
xObj.speak("id");
xObj.speak("someProperty");
Working Example: http://jsfiddle.net/RbCcA/
If you want to stick with the self executing functions here is the example rewrote:
var Object = (function () {
function Object() {
this.id = 5;
}
Object.prototype.speak = function(prop){
alert(this[prop]);
}
return Object;
})();
var ExtendsObject = (function(){
function ExtendsObject(prop){
this.someProperty = prop;
}
ExtendsObject.prototype = new Object();
return ExtendsObject;
})();
var xObj = new ExtendsObject("derived");
xObj.speak("id");
xObj.speak("someProperty");
Working Example: http://jsfiddle.net/RbCcA/1/
I do question the use of self executing functions in this situation. They are usually used to encapsulate and shield internals, however in the code example they are being exposed by returning the object from the SEF. Returning the object and storing it in a global variable just re-exposes the object, allowing its prototype and properties to be manipulated. Maybe there are private variables you have not mentioned, but as stated I find the SEFs unnecessary.
I am building a function that allows an object to be extended by any other object
Object.prototype.extend = function(constructor, args) {
var proto = this;
while(proto.__proto__.constructor !== Object) {
proto = proto.__proto__
}
proto.__proto__ = new constructor(args)
console.log(this);
}
the method would be called like this:
function ChildModelConstructor(1,2,3) {
this.extend(ParentModel, arguments)
}
or
instanceOfChildModel.extend(ParentModel, [1,2,3])
the problem is if I call new like this:
new constructor(args)
the constructor of the parent object receives argument which is an arguments object or array.
What I would like is to be able to call
new constructor.apply(args)
or something similar, I am not trying to change the context of this new, apply is the only method of calling a method using an args object or an array that I am aware of.
Thanks for the help :)
Update, I found a better way
Here's a better approach to Inheritance I came up with, it avoids using the depreciated proto
There are several advantages to this method, over other inheritance schemes I've found. The biggest is that it does not merge multiple levels of the proto chain. Many schemes mix the childClass's proto methods with the parent classes instance variables, or worse, all methods and properties from the parents initialization directly into the main body of the childClass.
The drawbacks are, it is single inheritance, and you cannot change the inheritance of a single instance, since the prototype property belongs to the Constructor.
Function.prototype.inherit = function(parentClass) {
var newPrototype = Object.create(Object.create(parentClass.prototype));
for(key in this.prototype){
newPrototype[key] = this.prototype[key];
}
this.prototype = newPrototype;
this.prototype.constructor = this;
this.prototype.parentClass = parentClass;
this.prototype.initParent = function(args) {
var proto = Object.getPrototypeOf(Object.getPrototypeOf(this))
this.parentClass.apply(proto, args);
}
this.prototype.uber = function() {
return Object.getPrototypeOf(Object.getPrototypeOf(this));
}
}
and you can set up the inheritance like this:
function Model(n) {
this.initParent(arguments)
this.test = n*2;
}
Model.inherit(BaseClass);
Here is a slightly more detailed version in JSFiddle http://jsfiddle.net/michaelghayes/2rHgK/
This is untested, but I think it will work. Replace:
proto.__proto__ = new constructor(args)
With:
proto.__proto__ = {};
proto.__proto__.prototype = constructor.prototype;
constructor.apply(proto.__proto__, args);
Take note that __proto__ is deprecated.
its better not to attach things to the object prototype and just set up the inheritance manually:
Model function() {
//init parent first because of chromes hidden classes
ParentClass.apply(this, [].slice.call(arguments))
//new instance properties
this.something = 'something'
}
Model.prototype = Object.create(ParentClass.prototype, {
constructor: {value: Model}
})
//Prototype props
Model.prototype.whatever = function(){return 'whatever'}
this also allows you to modify args before initing the parent since your new class shouldn't be restricted to using the exact same args as its parent