<disclaimer>
What follows is the fruits of a thought experiment. What I'm doing
isn't the issue; the symptoms are. Thank you.
</disclaimer>
I've finally wrapped my head around constructors, prototypes, and prototypal inheritance in JavaScript. But the SomethingSpectactular method in the sample below bugs me:
function FinalClass() {
return {
FinalFunction : function() { return "FinalFunction"; },
TypeName : "FinalClass",
SomethingSpectacular : function() {
return FinalClass.prototype.SubFunction.call(this);
}
}
}
FinalClass.prototype = new SubClass();
FinalClass.constructor = FinalClass;
var f = new FinalClass();
The reasons this bugs me are:
JavaScript apparently doesn't scan the prototype chain the same way for methods as it does for properties. That is, f.SubFunction() generates an error.
To get to a method on a prototype, you have to go through at least 3 dot operations every time you want to do it. FinalClass DOT prototype DOT Subfunctino DOT call. You get the point.
Base class (prototype) methods aren't showing up in Intellisense the way I'd expect them to. This is highly annoying.
So the thought experiement was to determine what would happen if I wrote a version of inherits that inserted stub functions onto the subclass that delegated back to the prototype for you. For example, it would automatically create the following function and add it to FinalClass:
function SubFunction() { SubClass.prototype.SubFunction.call(this); }
Now, I've got just about everything mapped out and working. The inherits method, which is an extension to both Object.prototype and Function.prototype, takes a Function as its sole argument. This is the base class. The subclass is determined by analyzing Object.prototype.inherits.caller.
From there, I set the prototype and constructor on the subclass, and then start analyzing the methods on the subclass's new prototype. I build an array containing the methods on both the prototype and the base class's public interface. The end result is a nice array that contains the methods that are exposed through either the prototype or by the base class constructor's return statement.
Once I have that, I start looking for each method on the subclass. If it's not there, I add it to the subclass with the same name and signature. The body of the method, however, simply forwards the call to the base class.
Now, I can step through all this code and it works marvelously, up until I instantiate instances of the subclasses. That's when things get wonky. Here's what I've observed using Visual Studio 2008 (SP1) and Internet Explorer 8:
Prior to instantiation, BaseClass exposes no public methods. This is to be expected. The methods exposed via a class constructor's return statement won't appear until it's instantiated. I'm good with that.
Prior to instantiation, SubClass exposes the methods from BaseClass. This is exactly what I expected.
Once I declare an instance of BaseClass, it has all the members I would expect. It has its typeName and BaseFunction methods.
Once I declare an instance of SubClass, it has only those methods returned by its constructor's return statement. No members from the base class are present. All the work that was done in the inherits method to map base class methods to the subclass appears to have been lost.
The big mystery for me here is the disappearance of the methods that I added to SubClass during the execution of inherits. During its execution, I can clearly see that SubClass is being modified, and that BaseClass's functions are being propagated. But the moment I create an instace of SubClass, that information is no longer present.
I am assuming this has something to do with the constructor, or order of events, or something else that I am simply not seeing.
A Final Note: This project arose as an effort to understand the complexities of JavaScript and how its prototypal inheritance system works. I know there are existing libraries out there. I know I'm reinventing the wheel. I'm reinventing it on purpose. Sometimes, the best way to understand a thing is to build it yourself. This has already been a tremendous learning experience, but I'm just stumped at this one particular point.
THE CODE
sti.objects.inherits = function inherits(baseClass) {
var subClass = sti.objects.inherits.caller;
var baseClassName = sti.objects.getTypeName(baseClass);
var methods = sti.objects.getMethods(baseClass);
if(!sti.objects.isDefined(baseClass.typeName))
baseClass.typeName = baseClassName;
var subClass = sti.objects.inherits.caller;
var subClassName = sti.objects.getTypeName(subClass);
var temp = function() {};
temp.prototype = new baseClass();
subClass.prototype = temp.prototype;
subClass.constructor = subClass;
subClass.typeName = subClassName;
subClass.baseClass = baseClass.prototype; // Shortcut to the prototype's methods
subClass.base = baseClass; // Cache the constructor
for(var index = 0; index < methods.items.length; index++) {
var resource = methods.items[index].getFunction();
var methodName = methods.items[index].getName();
if(methodName != "" && ! sti.objects.isDefined(subClass[methodName])) {
var method = sti.objects.createOverride(baseClassName, resource);
subClass[methodName] = method;
if(typeof subClass.prototype[methodName] == "undefined") {
subClass.prototype[methodName] = method;
}
}
}
}
Object.prototype.inherits = sti.objects.inherits;
Function.prototype.inherits = sti.objects.inherits;
function BaseClass() {
return {
A : function A() {return "A";}
};
}
function SubClass() {
inherits(BaseClass);
return {
B : function B() { return "B"; }
}
}
var b = new BaseClass();
var s = new SubClass();
Your constructors are not working as constructors. When you use the new keyword Javascript creates the new object and expects your constructor to populate it with members etc. Your constructors are returning another new object, not related to the object which is associated with the constructor usage, thus the prototype is not working.
Change your constructor to something like
function FinalClass() {
this.FinalFunction = function() { return "FinalFunction"; };
this.TypeName = "FinalClass";
this.SomethingSpectacular = function() {
return FinalClass.prototype.SubFunction.call(this);
};
}
and you should see the expected inheritance behaviour. This is because the FinalClass method in this case alters the contextual object created via the 'new' mechanism. Your original method is creating another object which is not of type FinalClass.
Related
I was wondering if the following situation is possible. I am trying to write a object factory, that will construct different types of objects. What I am trying to figure out, is if it is possible in java script to set the type as something other then a function or object? Similar to in C# how a class instance of Car is a typeof Car, even though the base type is object. Hopefully I am explaining this clearly. The best way to explain it, is demonstrated below:
var object = function(){
switch(id){
case 1:
$_objInstance = new Car();
break;
case 2:
$_objInstance = new Animal();
break;
return $_objInstance;
}
function Car(){
this.Name = "GM";
}
document.write(object instanceof Car);
or
typof(
object) == Car //is this possible?
Thanks in advance! Happy coding:)
What I am trying to figure out, is if it is possible in java script to set the type as something other then a function or object?
No, you can't. However:
JavaScript does have an instanceof operator you can use to test an instance to see if it's likely to have been constructed by a given constructor:
if (obj instanceof Car) {
// ...
}
Function#name remains unreliable in the wild (in that JavaScript engines don't set it reliably yet), you but you set it explicitly on your constructor functions:
Car.name = "Car";
...and then use obj.constructor.name to find the name of the constructor. That relies on the object inheriting the constructor property correctly, which it will if you don't mess up the default object on the function's prototype property.
Several years back I wrote a blog post about typeof, instanceof, Object.prototype.toString, and various other ways you can use to determine what something is, although I left off that option of just setting your own name.
Here's an example of using .constructor.name:
function Car() {
}
Car.name = "Car";
function Animal() {
}
Animal.name = "Animal";
console.log("Randomly constructing 10 Cars or Animals:");
for (var n = 0; n < 10; ++n) {
var x = Math.random() < 0.5 ? new Car() : new Animal();
console.log("We got: " + x.constructor.name);
}
When I said above
That relies on the object inheriting the constructor property correctly, which it will if you don't mess up the default object on the function's prototype property.
let me give you an example that messes it up, so you know what to keep an eye out for. You routinely see people doing this:
// PROBLEMATIC: Wipes out the `constructor` property
function Car() {
}
Car.prototype = {
drive: function() {
}
// ...
};
That is, rather than augmenting the object that Car.prototype got originally, they replace it. I prefer to augment (e.g., don't replace the whole object, just add properties to it), for various reasons, but if you do replace it you can just make sure you give the new one the correct constructor:
// Keeps `constructor` correct
function Car() {
}
Car.prototype = {
constructor: Car,
drive: function() {
}
// ...
};
I just watched Douglas Crockford talk about how prototypical inheritance is "not a good idea either"
YouTube 35m55s
I don't really care about his views on Prototypical inheritance in conjunction with JavaScript since it is such an essential part of the language that it will always be there.
But I would like to know what benefits I am reaping by using the functional object creation that he is showing in the link:
// Class Free Object Oriented Programming
function constructior(init) {
var that = other_constructor(init),
member,
method = function () {
// init, member, method
};
that.method = method;
return that;
}
After the video I re-read the part about Functional Object Creation in his book "JavaScript The Good Parts" Chapter 5: Inheritance.
But I can't really see the big difference..
I can get private members just fine with the constructor pattern:
function Constructor (value) {
var private = value;
this.getPrivate = function () {
return private;
}
}
var OBJ1 = new Constructor(5);
var OBJ2 = new Constructor('bacon');
console.log( OBJ1.getPrivate() ); // 5
console.log( OBJ2.getPrivate() ); // bacon
The only difference I can spot between a Constructor Pattern and the Functional Pattern is the omission of the new keyword. By avoiding the use of the new keyword we can avoid the error of forgetting the new keyword.
Writing this:
var panda = createBear();
Instead of this:
var panda = new Bear();
Makes me think it is mainly down to personal preference. I can see how avoiding the new keyword can be useful, and I might adopt it the functional pattern.
But this is the only reason I can see as to why you would do it. Can I please get some more information why one would be better or worse than the other?
Alright so I am gonna try and answer my own question here with the information that I have received and additional stuff I have gathered on the internet after asking the question.
TL;DR:
They are both useful and can achieve mostly the same things. Constructors have access to their prototype which can be very useful because it means they have "global" values across all its instances created with the Constructor. It is both useful and potentially dangerous. Useful because all the instances of the Constructor will have access to the same prototype property thus avoiding duplication. Dangerous because you can override the constructor property OR give the instance a property of the same name - making it harder to access the prototypes value.
There is some danger of forgetting new keyword when calling the Constructor but it is easily remedied by adding "use strict"; inside the Constructor function which will then throw an error if you forget the new keyword.
If you want to avoid the Prototype and its features/dangers you can use a Factory
Function.
The really useful Feature of the Functional approach is that you can return anything you like. Rather than always Constructing a "child" of a predefined object.
What I have learned from all this is that it is stupid to pick one over the other when you could be using both. They both have their strengths and weaknesses and people need to remember that Douglas Crockford is just a human being, not the JavaScript God. (That would be Brandon Eich, lol jk!)
The accepted answer by #Domenic on What difference is there in JavaScript between a constructor function, and function returning object which is invoked as a constructor?
Gave me some insights on the differences and similarities between the two methods of object creation.
Constructor
Using the new keyword creates a link between the new object and the Constructor Object it is derived from. The Constructor is the Prototype of the new Object and the new Object is an instance of the Prototype Object.
var Constructor = function () {
this.x = 0;
this.y = 0;
};
var A = new Constructor();
console.log(A instanceof Constructor ); // true
Being linked to the prototype object means that our new object has access to the prototypes properties without having to store them inside the object itself. This is both more memory efficient than creating the properties on each child object and it comes with the added bonus of the power of Prototyping.
Adding a property or method to the object prototype is simple:
Constructor.prototype.color = 'yellow';
Now every object created with the Constructor object has access to the .color property without storing it inside themselves.
var A = new Constructor();
console.log(A.color); // yellow
console.log(A.hasOwnProperty('color')); // false
Since the objects in JavaScript are dynamic it means that you can "retroactively" add new properties to the prototype and objects created before the change will still "inherit" the new properties.
var A = new Constructor();
Constructor.prototype.food = 'bacon';
console.log(A.food); // bacon;
One reason that Crockford might advocate against the Constructor patters is to avoid overriding the prototype property OR overriding the namespace of the prototype inside the child object accidentally.
Constructor.prototype.number = 5;
A.calculate = function () {
return A.number * 5;
}
console.log(A.calculate()); // 25
Constructor.prototype.number = 'fishsticks';
console.log(A.calculate()); // NaN
From what I can understand adding properties after creation will also make the code run slower inside the V8 engine because the objects no longer share the same "hidden classes" But I am not knowledgeable enough to get into that. Breaking the JavaScript Speed Limit with V8
The prototype can still be accessed. Either via the now deprecated .__proto__. or the newObject.getPrototypeOf() method.
console.log(Object.getPrototypeOf(A.color)); // yellow
The other reason why Crockford is advocating against the use of a Constructor Function is that you might forget to type new. If you forget to write new in front of the Constructor it will run the Constructor Function instead of creating a new object.
var A = Constructor();
console.log(A); // undefined
This is easily fixed by adding strict typing to your function which will throw an error if you forget the new keyword.
var Constructor = function () {
"use strict";
this.x = 0;
this.y = 0;
}
var A = Constructor();
console.log(A);
// Uncaught TypeError: Cannot set property 'x' of undefined
Factory Function
I found this pretty straight forward. If you don't want to have deal with the new keyword, and some of the "dangers" of the Constructor function, you can create objects that don't use their prototype with this approach.
function factory () {
var obj = {
x: 0,
y: 0
}
return obj;
}
var A = factory(); // {x: 0, y: 0}
This can be very handy for when you want to do something with the data other than just creating an Object.
function factory () {
if ( new Date().getHours() < 8 ) {
return "can't create object. Need Coffe!"
};
var obj = {
x: 0,
y: 0
}
return obj;
}
var A = factory(); // Before 8 am: "can't create object. Need Coffe!"
var A = factory(); // After 8 am: {x: 0, y: 0};
Doing this you lose the power / danger of the prototype. Because the object is not bound to one.
factory.prototype.foo = "bar";
A = factory();
console.log(A.foo); // undefined
This means you can't use it. But it also means you can't mess it up.
In conclusion.
See TL;DR
I learned a lot searching and writing this, hopefully someone else will learn a thing or two too.
References:
What difference is there in JavaScript between a constructor function, and function returning object which is invoked as a constructor?
Constructor function vs Factory functions
It’s time to start using JavaScript strict mode
Sorry I can't phrase this better. But I ran across some code like the following:
MyObject.prototype = Object.create(MyObject.prototype);
MyObject.prototype.constructor = MyObject;
And I just can't seem to figure out what it does. MyObject is defined above it something like this:
function MyObject(options) {
this.someProp = someDefault;
this.otherProp = process(options.something);
// etc...
}
and it's always called as a constructor. I'm just wondering what benefit those first two lines provide and if it's a known pattern in Javascript.
I just can't seem to figure out what it does
It creates a new object that inherits from [the old] MyObject.prototype via Object.create and then overwrites MyObject.prototype with that. It also explicitly adds a .constructor property which actually should be existing already.
I'm just wondering what benefit those first two lines provide
None, unless before that snippet someone has corrupted the prototype (like MyObject.prototype = Object.prototype) and this is an attempt to fix it.
…and if it's a known pattern in Javascript.
Not like this. Using Object.create to set up the prototype chain for inheritance between constructor-defined "classes" is a known pattern, but then the constructors would be different on each side of the assignment.
The two lines of code provided seem to be an incorrect attempt of the use of prototypal inheritance, but I see where you're going with this and what you're trying to accomplish.
As we know, there are two ways in JavaScript to define objects that have properties and methods as members - the object literal notation and function notation. Using object literal notation, we don't have immediate access to the new keyword (think of this like using abstract classes in Java or C#). With function notation, we have access to the new keyword because the initial declaration of an object as a function serves as our constructor.
In ECMAScript 5, The Object object was given a method called create that provided developers a simple way to create a new object from an existing object declared with the object literal notation. (See documentation here). However, objects created in function notation have problems with this method because they are Function objects. The Object.create method is a great way to use simple inheritance, allowing access to the base properties and methods.
With function notation, once the new keyword is used, the result is not a function, but rather an object. For example, I can test this:
var Obj = function(){};
console.log(typeof Obj) // "function"
console.log(typeof new Object()); // "object"
Because of this, you can only inherit once (meaning the child object cannot be derived from):
var MyObject = new Object();
var anotherObj = new MyObject() // throws exception
To alleviate this problem, you need to follow three steps:
Create your child object in function notation (so you can create new instances of it using the new keyword and inherit from it).
Set the child object's prototype (an object) to the result of a new instance of the base object (which will be an object as well).
Set the constructor of the child object (which happens to be on the object's prototype) back to reference the Function of itself (which is a function prior to instantiation). If you don't do this, the constructor will remain an object, which cannot spawn new instances.
From here, you can create new instances of both the child and parent objects and derive from both, using the pattern. Here's a practical example:
var Vehicle = function(){};
Vehicle.prototype.start = function() {
return this.make + " " + this.model + " " + "started";
}
var Car = function(color, make, model) {
this.color = color;
this.make = make;
this.model = model;
}
Car.prototype = new Vehicle();
Car.prototype.constructor = Car;
var myCar = new Car("red", "chevy", "aveo");
myCar.start(); //"chevy aveo started"
I really don't see any benefit in doing that.
What it's doing is providing the new object with the previous objects methods. But it's coming from the same object...
Here is a good example of JS inheritance:
http://jsfiddle.net/aDCmA/2/
var App = (function(){
var Being = function() {
this.living = true;
this.breathes = function () {
return true;
};
};
var Robert = function() {
this.blogs = true;
this.getsBored = function () {
return "You betcha";
}
};
Robert.prototype = new Being();
return {
Being: Being,
Robert: Robert,
being: function(){ return new Being(); },
robert: function(){ return new Robert(); }
}
}());
Here is another question that is similar: inherit prototype methods from other classes without overriding own prototype methods
Credit to Robert Nyman for originally blogging about it: http://robertnyman.com/2008/10/06/javascript-inheritance-how-and-why/
Let's see line by line:
MyObject.prototype = Object.create(MyObject.prototype);
This redefines MyObject.prototype to an object that inherits from MyObject.prototype. This is unusual, because it makes no sense to inherit from itself.
MyObject.prototype.constructor = MyObject;
Since the previous line overwrote MyObject.prototype, this is just fixing the constructor property that was lost in the process.
I can think of one scenario where tht might be useful: if some code before that messed up with MyObject.prototype, for example assigning the prototype of another constructor to it:
MyObject.prototype = SomethingElse.prototype; // wrong way to do inheritance.
Then the code you posted would be an attempt to fix it.
This is perfectly valid Javascript.
Any javascript function (say Func)can be used as a constructor and the constructor invocation also requires a prototype property (i.e. F.prototype or the prototype associated with the function) . Thus (almost) every function has a prototype property. The value of this property (i.e. Func.prototype).
Now the value of this prototype associated with the function is an object itself that has a single non enumerable property called constructor. And the value of this constructor property is the function object (i.e. F itself).
Lets take an example.
Say I construct a function Func
var Func = function() {
//your definition
};
Now since this can be invoked as a constructor it has to have a prototype property Func.prototype lets call this proto.
proto = Func.prototype;
Now the prototype has a single property (that is non enumerable) called constructor. This constructor has a value that is equal to the function object itself.
Dont believe me check it like this
Func.prototype.constructor === Func // =>true
Will always return true for any function.
Now from the code you explained :
So basically these two lines
MyObject.prototype = Object.create(MyObject.prototype);
MyObject.prototype.constructor = MyObject;
are modifying the value of the prototye to have a constructor property with the value of MyObject that is defined. But that would have happened anyways in the normal course of things. But the reason could be that maybe the prototype of the object has been changed earlier from the class it has been inherited from. In that case would those two lines make sense.
Hope that helps :)
I'm working on a JavaScript project that uses Prototypical Inheritance. The way that I decided to use it is the following:
var MySuperClass = function (param) {
this.prop = param;
};
MySuperClass.prototype.myFunc = function () {
console.log(this.prop);
};
var MySubClass = function (param) {
MySuperClass.call(this, param);
};
MySubClass.prototype = new MySuperClass();
MySubClass.prototype.constructor = MySubClass;
var obj = new MySubClass('value');
obj.myFunc();
With the emphasis on the inheritance.
The issue with this is that if I put a console.log in the constructor of each class (the super and the sub), the super class is called twice, once when it is passed into the subclass with MySubClass.prototype = new MySuperClass(); without any parameters and once with parameters when it is 'constructor stolen' in the constructor of the sub class.
This can cause errors if I then try to save those parameters (meaning that I have to add logic to deal with empty params).
Now if I do this:
var MySubClass = function (param) {
MySuperClass.call(this, param);
};
MySubClass.prototype = MySuperClass;
MySubClass.prototype.constructor = MySubClass;
Everything seems to work correctly but I've never seen anyone do this before (in my Googl'ing).
Can anyone explain to me if and how the 2nd one is incorrect (it seems to be similar to the Crockford inheritance function) and how to fix the 1st one to not fire twice if it is please?
Doing this is not a correct solution:
MySubClass.prototype = MySuperClass;
You're setting the function itself as the prototype instead of the prototype object, so you're not inheriting what you'd expect.
But you are right. Doing this does invoke the constructor, which can cause problems.
MySubClass.prototype = new MySuperClass();
The solution is to use Object.create to set up the inheritance. It gives you a new object that inherits from the object provided, but doesn't invoke any constructor.
MySubClass.prototype = Object.create(MySuperClass.prototype);
Now you have an object assigned to MySubClass.prototype that inherits from MySuperClass.prototype, but you never had to actually invoke the constructor.
Non ES5 compliant implementations won't support Object.create, but you can make a (partial) shim for it.
if (!Object.create) {
Object.create = function(proto) {
function F(){}
F.prototype = proto;
return new F();
};
}
Again, this is not a full shim, but it emulates just enough to be able to make inherited objects without having to invoke the constructor that references the prototype object.
I want to create a simple class in Javascript with only one public function as follows:
function A(myTitle) {
var title = "";
this.getTitle = function() {
return title;
};
title = myTitle;
};
var anInstance = new A("first");
console.log("anInstance.getTitle(): '"+anInstance.getTitle()+"'");
// expecting to return "first"
This does work as expected.
Now I want to add this class as a prototype to a new class, that includes a new title variable, so that the getTitle() method returns the value of the variable instead:
var myA = new Object();
myA.title ="second";
myA.prototype = anInstance;
console.log("myA.getTitle(): '"+myA.getTitle()+"'");
// expecting to return "second"
But instead of the expected "second", it results in the following error:
TypeError: 'undefined' is not a function (evaluating 'myA.getTitle()')
What is the problem with this function access?
Update:
The key point for my question is the following: In my application I will create several thousand instances of type "A" and several more of other comparable types. Thus memory efficiency and performance do matter. So I thought it would be great to create the according methods (several more will follow, getTitle is only one example) only once and the "data objects" reference these methods. Is this possible?
If all you want is instance variables (and that's all I see you using), what's wrong with idiomatic JavaScript:
function A(title) {
this.title = title;
};
A.prototype.getTitle = function() {
return this.title;
};
var anInstance = new A("first");
var myA = new A("second");
You can implement both Self-like prototypal OO and Smalltalk-like class-based OO on top of JavaScript, but this only makes sense in case of inheritance hierarchies, where the flat model of JS (which favors composition over inheritance - it's easy to add new methods to the prototype or apply() arbitrary constructor functions, but you'll have to jump through some hoops to make inheritance work properly) is not sufficient.
As to why your code can't work: your getTitle() method returns a lexical instead of an instance variable, which takes no part in property resolution via the prototype chain and thus can't be overwritten your way; also, .prototype is a property of constructor functions which is used to initialize the internal [[Prototype]] property of newly created instances - setting .prototype on general objects has no effect whatsoever on property resolution.
Firstly JavaScript is not a class based language.
This works just as well and am unsure what you are trying to achieve with your solution:
http://jsfiddle.net/jRtD2/