JavaScript uses a Prototype system, which is fundamentally different than a Class system. This is my first serious encounter with the language. I had fooled around with it previously, but this is the first time I built a system with proper OO, inheritance, polymorphism, etc.
From what I read there seems to be a few common methods to do member function inheritance in Javascript. Assuming you have a parent foo as following
foo = function(){ this.one = 1; }
foo.prototype.func1 = function(){return this.one;}
The MDN Introduction to JavaScript Inheritance suggests the naive approach of invoking the parent's method in the context of the child, as shown below.
bar = function(){ foo.call(this); }
bar.prototype = Object.create(foo.prototype);
bar.prototype.func1 = function(){ return this.one + foo.prototype.func1();}
This has the advantage of being simple to understand, but can become cumbersome as pointed out in this Salsify Blog post. The blog post outlines an alternate method where a super property is defined in the child prototype, and the name of each member function is attached as a property to the method. This method, however, relies on the caller property of a method, which the article points out will soon be deprecated. Rather than duplicate the entire post, I believe a summary of the important points are these
Object.defineProperty(bar.prototype, "super", {
get: function get() {
...
// methodName is set as a property on each method in an omitted code segment
methodName = get.caller.methodName;
...
Object.getPrototypeOf(this.prototype)[methodName]
}
}
Which is to say that you find the method with the same name in your prototype's prototype. I was wondering if this can be done in a simpler manner, without having to attach the method name as a parameter and without the Function.caller.
foo.prototype.super = function(method) {
superMethod = Object.getPrototypeOf(this.constructor.prototype)[method];
return superMethod.call(this, Array.prototype.slice.call(arguments, 1));
}
bar.prototype.func1 = function(){ return this.one + super('func1'); }
I'm making a number of assumptions in the above, I'd like to verify some assumptions.
new bar().constructor.prototype === Object.getPrototypeOf(new bar())
If the above is always true, is one preferable over the other?
The Parent's member function will always live in the child's prototype's prototype (assuming that neither of the prototypes were mutated after object creation)
That Object.getPrototypeOf() is not the "language support for accessing super methods" that the blog refers to as being added in ES6
If Object.getPrototypeOf() isn't that language support, what is?
After seeing the error of using this, which does not change throughout the execution and always refers to the instance of the subclass, I've revisited and am thinking I need something like this
Grandfather = function(){};
Grandfather.prototype.function1 = function(){console.log("I am the Grandfather");};
Father = function(){Grandfather.apply(this);};
Father.prototype = Object.create(Grandfather.prototype);
Father.prototype.function1 = function f(){ f.super(); console.log("I am the Father");};
Father.prototype.function1.super = Grandfather.prototype.function1;
Child = function(){Father.apply(this);}
Child.prototype = Object.create(Father.prototype);
Child.prototype.function1 = function f(){ f.super(); console.log("I am the Child");};
Child.prototype.function1.super = Father.prototype.function1;
c = new Child();
c.function1();
// I am the Grandfather
// I am the Father
// I am the Child
And so the question becomes, how to set the super property on to each function in some automatic way?
One such way to do this is shown below, it has the benefit that functions added to the prototype after objects are instantiated still receive the benefit of being able to call superFunc, whereas an approach that sets a super property at class extension time would not set such a property if functions are added to the prototype later.
The downsides of this approach are that it only works in single threaded environment and that it requires functionality inherited from a common base class. It is not threadsafe since some state is held in a what is effectively a static variable of the function. This is fine for my purposes since browsers still have single threaded JavaScript. The requirement that all classes inherit from some base class containing this method isn't a huge blocker (especially if you do a "bad thing" and insert this into Object's prototype).
Grandfather.prototype.superFunc = function f(funcName){
currentPrototype = Object.getPrototypeOf(f.startingPrototype || Object.getPrototypeOf(this));
f.startingPrototype = currentPrototype;
return currentPrototype[funcName]();
}
Child.prototype.function2 = function(){this.superFunc('function2'); console.log("Still in the Child");};
Father.prototype.function2 = function(){this.superFunc('function2'); console.log("Still in the Father");};
GrandFather.prototype.function2 = function(){console.log("Still in the Grandfather");};
c = new Child();
c.function2();
// Still in the Grandfather
// Still in the Father
// Still in the Child
Question 1
new Bar().constructor.prototype should equal Object.getPrototypeOf(new Bar()), provided you haven't overrided Bar.prototype.constructor or Bar.prototype, or return a different object in the Bar constructor. Here's an example:
function Bar() {}
var foo = new Bar();
foo.constructor.prototype === Object.getPrototypeOf(foo); // true
function Bar2() {}
var foo2 = new Bar2();
Bar2.prototype = {};
foo2.constructor.prototype === Object.getPrototypeOf(foo2); // false
function Bar3() {}
var foo3 = new Bar3();
Bar3.prototype.constructor = function NotBar3() {};
foo3.constructor.prototype === Object.getPrototypeOf(foo3); // false
Question 2
If you're looking to get the actual prototype of an object, use Object.getPrototypeOf, as that's unaffected by any of the changes shown above.
Question 3
No, you will not be able to access Foo from new Bar(). In your example, new Bar() would not inherit from Foo.prototype and as a result, there's no way to access Foo unless you make it inherit from Foo.prototype or assign Foo to a property of new Bar() or Bar.prototype.
Question 4/5
No, that's not what they're referring to. ES6 will introduce a separate class contruct, where super takes on a special meaning (similar to how super works in other languages with classes). Here's an example of how classes work in ES6:
class Foo {
constructor() {
this.one = 1;
}
func1() {
return this.one;
}
}
class Bar extends Foo {
func1() {
return this.one + super();
}
}
When you use super in the way you do it'll break when inheritance is more than 2 levels.
Assuming you'd use it the following way:
//changed super to this.super since super is not shown to exist in global scope
bar.prototype.func1(){ return this.one + this.super('func1'); }
See the following example:
function GrandFather(){
this.i = 0;
};
GrandFather.prototype.test = function(){
console.log('test in GrandFather');
};
function Father(){
GrandFather.call(this);
};
Father.prototype = Object.create(GrandFather.prototype);
Father.prototype.constructor = Father;
Father.prototype.super = GrandFather.prototype;
Father.prototype.test = function(){
console.log('test in Father');
//prevent too many recursions
this.i++;
if(this.i>5){
return;
}
this.super.test.call(this);//because test in child was called
// with Child instance as invoking object this will be Child
// and this.super will be Father.prototype
};
function Child(){
Father.call(this);
}
Child.prototype = Object.create(Father.prototype);
Child.prototype.constructor = Child;
Child.prototype.super = Father.prototype;
Child.prototype.test = function(){
console.log('test in Child');
this.super.test.call(this);//because invoking object is Child
//this.super in Father is Child
};
var c = new Child();
c.test();
It's also common practice to start a constructor function with a capital so it's better to use Foo and Bar for constructor function names.
If you want to go through all the trouble of simulating super in JavaScript then the following way would be slightly more robust: http://ejohn.org/blog/simple-javascript-inheritance/
Related
I have the following code I am trying to run, I get an error at the last line. From my understanding x's prototype chain looks good. What am I missing here
var Child = (function(){
function Parent(){
this.name ="parent";
this.parentHello = function(){
console.log("parent hello "+this.name);
};
}
return function(){
function Bridge(){
}
Bridge.prototype = new Parent();
this.constructor.prototype = new Bridge();
this.hello = function(){
console.log('hello');
};
};
})();
var x = new Child();
console.log(x.constructor);
console.log(x.constructor.prototype);
x.hello();
x.constructor.prototype.parentHello(); // This works
x.parentHello(); // TypeError: x.parentHello is not a function
This is modeled after an existing code, I cannot change the structure of it. I modified the original a little bit to post as question.
Update: Why the original doesn't work. You've asked in the comments to the question why it doesn't work. I'm not going to dig up the actual specifications for this for you, but the explanation is straightforward.
You do this:
this.constructor.prototype = new Bridge();
inside the constructor function. That's too late. When the JS Engine creates an object with new it looks to the constructor function you're calling, creates a new empty object, then assigns the prototype of that object from the constructor's prototype. Then it applies the function in the context of this newly created object. Inside there, you reassign the prototype of the constructor, but it's too late.
It's easy to see that this is the issue by just doing this:
var x = new Child();
x.parentHello(); // throws an exception
var y = new Child(); // gets the updated prototype
y.parentHello(); // works as expected
But the big question is why you would want to reassign the prototype from within the constructor. It is an extremely confusing notion, even if it were to work properly.
We now return you to your originally scheduled answer.
The reason this doesn't work is that you're confusing levels, and trying to do something inside a constructor function that really should be done outside of it. Below is what I think of as the minimal modification of your code to make it work. It is not how I would suggest actually writing this, but it's a starting place for discussion:
var Child = (function(){
function Parent(){
this.name ="parent";
this.parentHello = function(){
console.log("parent hello "+this.name);
};
}
function Child() {
this.hello = function(){
console.log('hello');
};
}
function Bridge(){}
Bridge.prototype = new Parent();
Child.prototype = new Bridge();
Child.prototype.constructor = Parent;
return Child;
})();
var x = new Child();
x.hello(); //=> logs "hello"
x.parentHello(); //=> logs "parent hello parent"
Now that last block really should become an inherit function or some such:
var inherit = function(Parent, Child) {
function Bridge(){}
Bridge.prototype = new Parent();
Child.prototype = new Bridge();
Child.prototype.constructor = Parent;
return Child;
}
var Child = (function(){
function Parent(){
this.name ="parent";
this.parentHello = function(){
console.log("parent hello "+this.name);
};
}
function Child() {
this.hello = function(){
console.log('hello');
};
}
return inherit(Parent, Child);
})();
Often these days, these things are handled in one of two different ways, though. This version is pretty old-school. Instead now, if you're using es6, there is a class syntax that does pretty much the equivalent of this. And if not, techniques using Object.create are very common.
I'm going to attempt to both explain what was wrong with your code and show a better way to achieve the same inheritance you have now.
Analysis of your code:
Child is a constructor function.
In a private scope of that function is the Parent() constructor
Calling the Child function with new attepts to return a new object that initializes the Bridge constructor and prototype and then attempts to set the constructor of the current object's prototype to new Bridge().
I'm guessing here since you don't explicitly describe what you're trying to accomplish, but it looks like maybe you're trying to create two levels of inheritance where Parent is the base, then Bridge derives from Parent, then Child derives from Bridge.
But, you can't be setting the prototype for Child in the constructor of Child. That's too late to be setting it because the first Child object has already been created.
So, when you do x = new Child();, x will just be a Child object without inheriting from Bridge. Thus, there is no .parentHello() method on it.
When you create new objects with inheritance, you also need to call the inherited constructors so they can properly initialize their instances.
Fixing the code:
Since the inheritance structure here is fixed and completely known ahead of time, there is no reason to try to do this dynamically. It should be assigned once at the time the Child IIFE runs, not inside the Child constructor. This will both fix timing issues and make the code run properly.
Further, it's 2016, so we should be using Object.create() to create prototypes, not new.
And, objects needs to call the constructors of the things they inherit from.
Here's what I would suggest (you can run this snippet and look in the debug console):
var Child = (function(){
// define base class
function Parent(){
this.name ="parent";
this.parentHello = function(){
console.log("parent hello "+this.name);
};
}
Parent.prototype.constructor = Parent;
// define Bridge which inherits from Parent
function Bridge() {
// call parent constructor
Parent.call(this);
}
Bridge.prototype = Object.create(Parent.prototype);
Bridge.prototype.bridgeHello = function() {
console.log("bridge hello");
}
Bridge.prototype.constructor = Bridge;
function Child() {
// call parent constructor
Bridge.call(this);
this.hello = function(){
console.log('hello');
};
}
Child.prototype = Object.create(Bridge.prototype);
Child.prototype.constructor = Child;
return Child;
})();
var x = new Child();
console.log(x);
console.log(x.constructor);
x.hello();
x.bridgeHello();
x.parentHello();
And, here's a similar implementation using the more modern ES6 class syntax (you can run this snippet in a browser that supports ES6 classes such as Chrome, Firefox or Edge):
"use strict";
var Child = (function(){
// base class
class Parent {
constructor() {
this.name = "parent";
}
parentHello() {
console.log("parent hello "+this.name);
}
}
// define Bridge which inherits from Parent
class Bridge extends Parent {
constructor() {
super();
this.name = "bridge";
}
bridgeHello() {
console.log("bridge hello");
}
}
class Child extends Bridge {
constructor() {
super();
this.name = "child";
}
hello() {
console.log('hello');
}
}
return Child;
})();
var x = new Child();
console.log(x);
console.log(x.constructor);
x.hello();
x.bridgeHello();
x.parentHello();
I'm trying to create some kind of inheritance between objects:
var foo = (function(){
function doFooStuff(){
console.log(arguments.callee.name);
}
return {
doFooStuff: doFooStuff
}
})();
var bar = (function(){
$.extend(this, foo);
function doBarStuff(){
console.log(arguments.callee.name);
doFooStuff();
}
return {
doBarStuff: doBarStuff,
}
})();
bar.doBarStuff();
bar.doFooStuff(); //<-- Uncaught TypeError:
//Object #<Object> has no method 'doFooStuff'
http://jsfiddle.net/wRXTv/
Why isn't doFooStuff accessible here? Would you recommend another approach than using $.extend?
$.extend(this, foo);
this is not the object which you return from the function below (in fact it cannot be since it's created after this call), but the global object - check MDN's introduction to the this keyword.
For what you want to do, there are two ways:
Copy all properties from foo onto your bar object after it is created:
var bar = (function() {
…
return {…};
})();
$.extend(bar, foo);
You can do that as well directly on the returned object:
return $.extend({…}, foo);
A variant of this pattern allows you to overwrite foo properties. Copy foo into an empty object, then write your bar properties to it:
return $.extend({}, foo, {…});
Use prototypical inheritance. Create an object that inherits its properties from foo, and then write your bar properties to it:
return $.extend(Object.create(foo), {…});
Now when foo changes afterward, you still can access those new properties on bar (unless they're shadowed by own properties). Notice that Object.create might not be supported in legacy environments, but you can easily shim it.
As noted by #raina77ow, your doBarStuff function is flawed too. The doFooStuff function is not in the scope of your function, and you cannot change that. You never will be able to access the private declared functions and variables from the foo module, only those that are public - if you did need them, consider a different pattern or app design. However, doFooStuff is a property on the exported (public) foo object, from which bar inherits (regardless in which of the above demonstrated ways). Therefore, you can access it as a method of bar as well, usually by using this.doFooStuff().
You attempt to work with revealing module as if it were a constructor. Hence an attempt to extend this, wrong for many reasons. The most glaring, I suppose, is that neither the function is used as a constructor (no new) nor its context is changed. In plain words, this just points to a global object here.
But that's not the only problem. Consider that part of your code:
function doBarStuff(){
console.log(arguments.callee.name);
doFooStuff();
}
Here doFooStuff won't be in the scope even if you somehow manage to extend this. ) Remember, the scope resolution doesn't involve the context object.
So what's the solution? Well, I often use aggregation in similar cases:
var foo = (function(){
function doFooStuff(){
console.log(arguments.callee.name);
}
return {
doFooStuff: doFooStuff
}
})();
var bar = (function(){
var _super = foo;
function doBarStuff(){
console.log(arguments.callee.name);
_super.doFooStuff();
}
// static parent: further changes on `foo` won't affect `bar`,
// as $.extend takes the parent's current state
return $.extend({}, _super, {
doBarStuff: doBarStuff,
});
// dynamic parent: further changes on `foo` will affect `bar`,
// as extended object now has `foo` in its prototype chain
return $.extend(Object.create(_super), {
doBarStuff: doBarStuff,
});
})();
JS Fiddle.
Yes, it's aggregation, not inheritance. But so what? I'm still able to get the main prize - removing code duplication AND I'm able to control the usage of parent functions within the child module.
The problem with your code is that this in $.extend(this,foo) refers to the window object and not foo. Anonymous function are run in window's context.
I would recommend using a John Resig implementation of classical inheritance in javascript.
http://ejohn.org/blog/simple-javascript-inheritance/.
Extract:
var Person = Class.extend({
init: function(isDancing){
this.dancing = isDancing;
},
dance: function(){
return this.dancing;
}
});
var Ninja = Person.extend({
init: function(){
this._super( false );
},
dance: function(){
// Call the inherited version of dance()
return this._super();
},
swingSword: function(){
return true;
}
});
var p = new Person(true);
p.dance(); // => true
var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true
// Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class
It is because this is an anonymous function. This part of your function deceleration:
var foo = (function(){
function doFooStuff(){
console.log(arguments.callee.name);
}
return {
doFooStuff: doFooStuff
}
})();
Do you see that you are immediately invoking this function call and ultimately do not have access to doFooStuff within your return statement.
If you remove the anonymous function deceleration, it will work.
When I run this code:
function foo() {
console.log("foo");
var self = this;
this.a = function() {
return arguments.length == 0 ? self.b : (self.b = arguments[0]);
};
};
function bar() {
};
bar.prototype = new foo();
var a = new bar();
var b = new bar();
console.log(a.a());
b.a(true);
console.log(a.a());
I get the following output: foo, undefined, true
What I do not understand is how the object returned by the constructor function foo somehow manages to allocate a new memory location for b. I was totally expecting the last output to be true because I only get 1 foo output.
That this works is great, but it feels too much like magic.
My problem really here is that I'd like to setup an initialization order (or chain). What I've realized is that foo cannot take any arguments, because it's only called once, to provide a base (or template of sorts).
I'd like to devise a really simple schema where foo has parameters that has to be passed from bar to foo (because bar inherits foo). I'm fine with something like calling foo.apply(this, arguments) from bar but the call to set the prototype has to be done without arguments, what I need is a fluent way to somehow tell the two apart.
But I really don't want to build an entire service around creating objects that allow some kind of inheritance, the only thing I really care about is constructing the objects, correctly...
On a side note, you're sometimes using self and sometimes using this... personally, I'd be more consistent. I like to use that because this can be confusing and self is part of the BOM, but it's just a matter of taste.
Try parasitic inheritance:
function foo(arg) {
var that = this;
that.a = function() {
return arguments.length == 0 ? that.b : (that.b = arguments[0]);
};
}
function bar(arg) {
return new foo(arg);
}
bar.prototype = new foo();
var a = new bar(); // the `new` is now optional. Personally I'd remove it...
var b = bar(); // ... like I did here!
console.log(a.a());
b.a(true);
console.log(a.a());
console.log(b.a());
... here the inheritance behaves in a more classically, explicitly invoking a parent constructor when the constructor is called.
Well, this is one of the weak spots (and yet, strong spots) of JS. You're running into a pattern issue here. I'd suggest taking a look at http://ejohn.org/blog/simple-javascript-inheritance/ - there's a free 'class' you can use to help straighten up what one would expect with a more 'classical' inheritance.
Just as a quick example, most patterns I've seen have a base 'object' (which is more or less a customized class) and the constructor (which is more or less 'how the object gets built') calls something like "this.init.apply(this, arguments)". That calls an 'init' method on the object with all the arguments that have been passed. So the init can then be set, extended, re-set, etc., and the constructor always calls the one that is 'local' to itself with the arguments that have been passed. Pretty neat.
Hope that helps, or at least doesn't confuse.
The last output is true. You are being deceived by your JavaScript console. That last undefined is the return value from your expression. Make your console.log() calls more descriptive to shine a light on what's happening:
function foo() {
console.log("foo constructor called");
var self = this;
this.a = function() {
return arguments.length == 0 ? self.b : (self.b = arguments[0]);
};
}
function bar() {
}
bar.prototype = new foo();
var a = new bar();
var b = new bar();
console.log("value from a.a(): " + a.a());
b.a(true);
console.log("value from a.a(): " + a.a());
console.log("done logging");
This yields the following output in the console:
foo constructor called
value from a.a(): undefined
value from a.a(): true
done logging
undefined
It's not magic, it's prototypal inheritance. I think what you're trying to achieve is combining two constructor functions to get called automagically. You're probably mixing up constructors and prototypes.
But I really don't want to build an entire service around creating
objects that allow some kind of inheritance, the only thing I really
care about is constructing the objects, correctly...
I don't know what you mean by "service". But as in any other object-oriented programming language, superclass method calls need to be done manually. So either you hard-code the "superclass" like this:
function foo() {
console.log("foo");
var self = this;
this.a = function() {
return arguments.length == 0 ? self.b : (self.b = arguments[0]);
};
}
function bar() {
foo.apply(this, arguments); // <- ugly
}
//bar.prototype = new foo(); // this is not neccessary
...or you build some wrapper stuff to connect your "classes". Something like:
function inherit(superconstructor) {
return function () {
superconstructor.apply(this, arguments);
};
}
function foo() {...}
bar = inherit(foo);
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.
Well I tried to figure out is this possible in any way. Here is code:
a=function(text)
{
var b=text;
if (!arguments.callee.prototype.get)
arguments.callee.prototype.get=function()
{
return b;
}
else
alert('already created!');
}
var c=new a("test"); // creates prototype instance of getter
var d=new a("ojoj"); // alerts already created
alert(c.get()) // alerts test
alert(d.get()) // alerts test from context of creating prototype function :(
As you see I tried to create prototype getter. For what? Well if you write something like this:
a=function(text)
{
var b=text;
this.getText=function(){ return b}
}
... everything should be fine.. but in fact every time I create object - i create getText function that uses memory. I would like to have one prototypical function lying in memory that would do the same... Any ideas?
EDIT:
I tried solution given by Christoph, and it seems that its only known solution for now. It need to remember id information to retrieve value from context, but whole idea is nice for me :) Id is only one thing to remember, everything else can be stored once in memory. In fact you could store a lot of private members this way, and use anytime only one id. Actually this is satisfying me :) (unless someone got better idea).
someFunc = function()
{
var store = new Array();
var guid=0;
var someFunc = function(text)
{
this.__guid=guid;
store[guid++]=text;
}
someFunc.prototype.getValue=function()
{
return store[this.__guid];
}
return someFunc;
}()
a=new someFunc("test");
b=new someFunc("test2");
alert(a.getValue());
alert(b.getValue());
JavaScript traditionally did not provide a mechanism for property hiding ('private members').
As JavaScript is lexically scoped, you could always simulate this on a per-object level by using the constructor function as a closure over your 'private members' and defining your methods in the constructor, but this won't work for methods defined in the constructor's prototype property.
Of course, there are ways to work around this, but I wouldn't recommend it:
Foo = (function() {
var store = {}, guid = 0;
function Foo() {
this.__guid = ++guid;
store[guid] = { bar : 'baz' };
}
Foo.prototype.getBar = function() {
var privates = store[this.__guid];
return privates.bar;
};
Foo.prototype.destroy = function() {
delete store[this.__guid];
};
return Foo;
})();
This will store the 'private' properties in another object seperate from your Foo instance. Make sure to call destroy() after you're done wih the object: otherwise, you've just created a memory leak.
edit 2015-12-01: ECMAScript6 makes improved variants that do not require manual object destruction possible, eg by using a WeakMap or preferably a Symbol, avoiding the need for an external store altogether:
var Foo = (function() {
var bar = Symbol('bar');
function Foo() {
this[bar] = 'baz';
}
Foo.prototype.getBar = function() {
return this[bar];
};
return Foo;
})();
With modern browsers adopting some ES6 technologies, you can use WeakMap to get around the GUID problem. This works in IE11 and above:
// Scope private vars inside an IIFE
var Foo = (function() {
// Store all the Foos, and garbage-collect them automatically
var fooMap = new WeakMap();
var Foo = function(txt) {
var privateMethod = function() {
console.log(txt);
};
// Store this Foo in the WeakMap
fooMap.set(this, {privateMethod: privateMethod});
}
Foo.prototype = Object.create(Object.prototype);
Foo.prototype.public = function() {
fooMap.get(this).p();
}
return Foo;
}());
var foo1 = new Foo("This is foo1's private method");
var foo2 = new Foo("This is foo2's private method");
foo1.public(); // "This is foo1's private method"
foo2.public(); // "This is foo2's private method"
WeakMap won't store references to any Foo after it gets deleted or falls out of scope, and since it uses objects as keys, you don't need to attach GUIDs to your object.
Methods on the prototype cannot access "private" members as they exist in javascript; you need some kind of privileged accessor. Since you are declaring get where it can lexically see b, it will always return what b was upon creation.
After being hugely inspired by Christoph's work-around, I came up with a slightly modified concept that provides a few enhancements. Again, this solution is interesting, but not necessarily recommended. These enhancements include:
No longer need to perform any setup in the constructor
Removed the need to store a public GUID on instances
Added some syntactic sugar
Essentially the trick here is to use the instance object itself as the key to accessing the associated private object. Normally this is not possible with plain objects since their keys must be strings. However, I was able to accomplish this using the fact that the expression ({} === {}) returns false. In other words the comparison operator can discern between unique object instances.
Long story short, we can use two arrays to maintain instances and their associated private objects:
Foo = (function() {
var instances = [], privates = [];
// private object accessor function
function _(instance) {
var index = instances.indexOf(instance), privateObj;
if(index == -1) {
// Lazily associate instance with a new private object
instances.push(instance);
privates.push(privateObj = {});
}
else {
// A privateObject has already been created, so grab that
privateObj = privates[index];
}
return privateObj;
}
function Foo() {
_(this).bar = "This is a private bar!";
}
Foo.prototype.getBar = function() {
return _(this).bar;
};
return Foo;
})();
You'll notice the _ function above. This is the accessor function to grab ahold of the private object. It works lazily, so if you call it with a new instance, it will create a new private object on the fly.
If you don't want to duplicate the _ code for every class, you can solve this by wrapping it inside a factory function:
function createPrivateStore() {
var instances = [], privates = [];
return function (instance) {
// Same implementation as example above ...
};
}
Now you can reduce it to just one line for each class:
var _ = createPrivateStore();
Again, you have to be very careful using this solution as it can create memory leaks if you do not implement and call a destroy function when necessary.
Personally, I don't really like the solution with the guid, because it forces the developer to declare it in addition to the store and to increment it in the constructor. In large javascript application developers might forget to do so which is quite error prone.
I like Peter's answer pretty much because of the fact that you can access the private members using the context (this). But one thing that bothers me quite much is the fact that the access to private members is done in a o(n) complexity. Indeed finding the index of an object in array is a linear algorithm. Consider you want to use this pattern for an object that is instanciated 10000 times. Then you might iterate through 10000 instances each time you want to access a private member.
In order to access to private stores in a o(1) complexity, there is no other way than to use guids. But in order not to bother with the guid declaration and incrementation and in order to use the context to access the private store I modified Peters factory pattern as follow:
createPrivateStore = function () {
var privates = {}, guid = 0;
return function (instance) {
if (instance.__ajxguid__ === undefined) {
// Lazily associate instance with a new private object
var private_obj = {};
instance.__ajxguid__ = ++guid;
privates[instance.__ajxguid__] = private_obj;
return private_obj;
}
return privates[instance.__ajxguid__];
}
}
The trick here is to consider that the objects that do not have the ajxguid property are not yet handled. Indeed, one could manually set the property before accessing the store for the first time, but I think there is no magical solution.
I think real privacy is overrated. Virtual privacy is all that is needed. I think the use of _privateIdentifier is a step in the right direction but not far enough because you're still presented with a listing of all the _privateIdentifiers in intellisense popups. A further and better step is to create an object in the prototype and/or constructor function for segregating your virtually private fields and methods out of sight like so:
// Create the object
function MyObject() {}
// Add methods to the prototype
MyObject.prototype = {
// This is our public method
public: function () {
console.log('PUBLIC method has been called');
},
// This is our private method tucked away inside a nested privacy object called x
x: {
private: function () {
console.log('PRIVATE method has been called');
}
},
}
// Create an instance of the object
var mo = new MyObject();
now when the coder types "mo." intellisense will only show the public function and "x". So all the private members are not shown but hidden behind "x" making it more unlikely for a coder to accidentally call a private member because they'll have to go out of their way and type "mo.x." to see private members. This method also avoids the intellisense listing from being cluttered with multiple private member names, hiding them all behind the single item "x".
I know this thread is really really old now, but thought this solution might be of interest to anyone passing by:
const Immutable = function ( val ) {
let _val = val;
this.$ = {
_resolve: function () {
return _val;
}
};
};
Immutable.prototype = {
resolve: function () {
return this.$._resolve();
}
};
Essentially hiding the internal _val from being manipulated and making an instance of this object immutable.
I have created a new library for enabling private methods on the prototype chain.
https://github.com/TremayneChrist/ProtectJS
Example:
var MyObject = (function () {
// Create the object
function MyObject() {}
// Add methods to the prototype
MyObject.prototype = {
// This is our public method
public: function () {
console.log('PUBLIC method has been called');
},
// This is our private method, using (_)
_private: function () {
console.log('PRIVATE method has been called');
}
}
return protect(MyObject);
})();
// Create an instance of the object
var mo = new MyObject();
// Call its methods
mo.public(); // Pass
mo._private(); // Fail