I am reading about prototipcal inheritance. There, and from elsewhere, I am learning this style of avoiding classical inheritance which I am still digesting.
One aspect that still puzzles me, though, is the this pointer, which is said to cause confusion for many like myself who come from classic OO languages. (If I were to avoid classic inheritance, shouldn't I be avoiding this as well?
)
After some reading, I realize that the this pointer is defined not at the time of object/function definition (as in C++) but rather at the site of function call. The this pointer seems (to me) like a dangling pointer whose target depends on where/how you use it.
Using an example in the linked blog article about extending objects, can someone help explain the following:
Can we avoid using this or replacing it with explicit object reference?
A related question is, is the this pointer necessary if I only use prototypical inheritance?
Example from the blog:
It would be nice to combine these two operations into one, ... and
extend it with new properties. This operation, called extend, can be
implemented as a function:
1 Object.prototype.extend = function (extension) {
2 var hasOwnProperty = Object.hasOwnProperty;
3 var object = Object.create(this);
4
5 for (var property in extension)
6 if (hasOwnProperty.call(extension, property) ||
7 typeof object[property] === "undefined")
8 object[property] = extension[property];
9
10 return object;
11 };
Using the above extend function we can rewrite the code for square as
follows:
1 var square = rectangle.extend({
2 create: function (side) {
3 return rectangle.create.call(this, side, side);
4 }
5 });
6
7 var sq = square.create(5);
8
9 alert(sq.area());
Note, this is used in line 3 of both code segments.
If you want to avoid this completely, then you should step away from creating methods that act on the object they are applied on, meaning that you should not have method calls like obj.method(), where method needs to use the state of obj in some way.
So the effect of the following should be the same as obj.method():
var method = obj.method;
method();
In places where the above would fail, you'll need to refactor the code, so that you can in principle use it like this without problems:
var method = obj1.method;
method(obj2); // apply method on obj2
So, in general you'll need to create utility functions that take one more argument: the object to apply the logic on.
In your case this would mean that you don't define extend on Object.prototype (which is considered bad practice anyway), but on Object itself, and give it the extra source object parameter. This is also how many native methods are defined, like Object.assign, Object.keys, et al. Also the definition of rectangle will need some changes to make it work without ever using this:
Object.extend = function (source, extension) {
var hasOwnProperty = Object.hasOwnProperty;
var object = Object.create(source);
for (var property in extension)
if (hasOwnProperty.call(extension, property) ||
typeof object[property] === "undefined")
object[property] = extension[property];
return object;
};
var rectangle = {
create: function (width, height) {
var self = {
width: width,
height: height,
area: function () {
return self.width * self.height;
}
};
return self;
}
};
var square = Object.extend(rectangle, {
create: function (side) {
return rectangle.create(side, side);
}
});
var sq = square.create(5);
console.log(sq.area());
As you have realised, there are lots of ways to work with objects and implement some form of inheritance in JavaScript, and each has its pros and cons.
Related
In Ruby I think you can call a method that hasn't been defined and yet capture the name of the method called and do processing of this method at runtime.
Can Javascript do the same kind of thing ?
method_missing does not fit well with JavaScript for the same reason it does not exist in Python: in both languages, methods are just attributes that happen to be functions; and objects often have public attributes that are not callable. Contrast with Ruby, where the public interface of an object is 100% methods.
What is needed in JavaScript is a hook to catch access to missing attributes, whether they are methods or not. Python has it: see the __getattr__ special method.
The __noSuchMethod__ proposal by Mozilla introduced yet another inconsistency in a language riddled with them.
The way forward for JavaScript is the Proxy mechanism (also in ECMAscript Harmony), which is closer to the Python protocol for customizing attribute access than to Ruby's method_missing.
The ruby feature that you are explaining is called "method_missing" http://rubylearning.com/satishtalim/ruby_method_missing.htm.
It's a brand new feature that is present only in some browsers like Firefox (in the spider monkey Javascript engine). In SpiderMonkey it's called "__noSuchMethod__" https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/NoSuchMethod
Please read this article from Yehuda Katz http://yehudakatz.com/2008/08/18/method_missing-in-javascript/ for more details about the upcoming implementation.
Not at the moment, no. There is a proposal for ECMAScript Harmony, called proxies, which implements a similar (actually, much more powerful) feature, but ECMAScript Harmony isn't out yet and probably won't be for a couple of years.
You can use the Proxy class.
var myObj = {
someAttr: 'foo'
};
var p = new Proxy(myObj, {
get: function (target, methodOrAttributeName) {
// target is the first argument passed into new Proxy, aka. target is myObj
// First give the target a chance to handle it
if (Object.keys(target).indexOf(methodOrAttributeName) !== -1) {
return target[methodOrAttributeName];
}
// If the target did not have the method/attribute return whatever we want
// Explicitly handle certain cases
if (methodOrAttributeName === 'specialPants') {
return 'trousers';
}
// return our generic method_missing function
return function () {
// Use the special "arguments" object to access a variable number arguments
return 'For show, myObj.someAttr="' + target.someAttr + '" and "'
+ methodOrAttributeName + '" called with: ['
+ Array.prototype.slice.call(arguments).join(',') + ']';
}
}
});
console.log(p.specialPants);
// outputs: trousers
console.log(p.unknownMethod('hi', 'bye', 'ok'));
// outputs:
// For show, myObj.someAttr="foo" and "unknownMethod" called with: [hi,bye,ok]
About
You would use p in place of myObj.
You should be careful with get because it intercepts all attribute requests of p. So, p.specialPants() would result in an error because specialPants returns a string and not a function.
What's really going on with unknownMethod is equivalent to the following:
var unk = p.unkownMethod;
unk('hi', 'bye', 'ok');
This works because functions are objects in javascript.
Bonus
If you know the number of arguments you expect, you can declare them as normal in the returned function.
eg:
...
get: function (target, name) {
return function(expectedArg1, expectedArg2) {
...
I've created a library for javascript that let you use method_missing in javascript: https://github.com/ramadis/unmiss
It uses ES6 Proxies to work. Here is an example using ES6 Class inheritance. However you can also use decorators to achieve the same results.
import { MethodMissingClass } from 'unmiss'
class Example extends MethodMissingClass {
methodMissing(name, ...args) {
console.log(`Method ${name} was called with arguments: ${args.join(' ')}`);
}
}
const instance = new Example;
instance.what('is', 'this');
> Method what was called with arguments: is this
No, there is no metaprogramming capability in javascript directly analogous to ruby's method_missing hook. The interpreter simply raises an Error which the calling code can catch but cannot be detected by the object being accessed. There are some answers here about defining functions at run time, but that's not the same thing. You can do lots of metaprogramming, changing specific instances of objects, defining functions, doing functional things like memoizing and decorators. But there's no dynamic metaprogramming of missing functions as there is in ruby or python.
I came to this question because I was looking for a way to fall through to another object if the method wasn't present on the first object. It's not quite as flexible as what your asking - for instance if a method is missing from both then it will fail.
I was thinking of doing this for a little library I've got that helps configure extjs objects in a way that also makes them more testable. I had seperate calls to actually get hold of the objects for interaction and thought this might be a nice way of sticking those calls together by effectively returning an augmented type
I can think of two ways of doing this:
Prototypes
You can do this using prototypes - as stuff falls through to the prototype if it isn't on the actual object. It seems like this wouldn't work if the set of functions you want drop through to use the this keyword - obviously your object wont know or care about stuff that the other one knows about.
If its all your own code and you aren't using this and constructors ... which is a good idea for lots of reasons then you can do it like this:
var makeHorse = function () {
var neigh = "neigh";
return {
doTheNoise: function () {
return neigh + " is all im saying"
},
setNeigh: function (newNoise) {
neigh = newNoise;
}
}
};
var createSomething = function (fallThrough) {
var constructor = function () {};
constructor.prototype = fallThrough;
var instance = new constructor();
instance.someMethod = function () {
console.log("aaaaa");
};
instance.callTheOther = function () {
var theNoise = instance.doTheNoise();
console.log(theNoise);
};
return instance;
};
var firstHorse = makeHorse();
var secondHorse = makeHorse();
secondHorse.setNeigh("mooo");
var firstWrapper = createSomething(firstHorse);
var secondWrapper = createSomething(secondHorse);
var nothingWrapper = createSomething();
firstWrapper.someMethod();
firstWrapper.callTheOther();
console.log(firstWrapper.doTheNoise());
secondWrapper.someMethod();
secondWrapper.callTheOther();
console.log(secondWrapper.doTheNoise());
nothingWrapper.someMethod();
//this call fails as we dont have this method on the fall through object (which is undefined)
console.log(nothingWrapper.doTheNoise());
This doesn't work for my use case as the extjs guys have not only mistakenly used 'this' they've also built a whole crazy classical inheritance type system on the principal of using prototypes and 'this'.
This is actually the first time I've used prototypes/constructors and I was slightly baffled that you can't just set the prototype - you also have to use a constructor. There is a magic field in objects (at least in firefox) call __proto which is basically the real prototype. it seems the actual prototype field is only used at construction time... how confusing!
Copying methods
This method is probably more expensive but seems more elegant to me and will also work on code that is using this (eg so you can use it to wrap library objects). It will also work on stuff written using the functional/closure style aswell - I've just illustrated it with this/constructors to show it works with stuff like that.
Here's the mods:
//this is now a constructor
var MakeHorse = function () {
this.neigh = "neigh";
};
MakeHorse.prototype.doTheNoise = function () {
return this.neigh + " is all im saying"
};
MakeHorse.prototype.setNeigh = function (newNoise) {
this.neigh = newNoise;
};
var createSomething = function (fallThrough) {
var instance = {
someMethod : function () {
console.log("aaaaa");
},
callTheOther : function () {
//note this has had to change to directly call the fallThrough object
var theNoise = fallThrough.doTheNoise();
console.log(theNoise);
}
};
//copy stuff over but not if it already exists
for (var propertyName in fallThrough)
if (!instance.hasOwnProperty(propertyName))
instance[propertyName] = fallThrough[propertyName];
return instance;
};
var firstHorse = new MakeHorse();
var secondHorse = new MakeHorse();
secondHorse.setNeigh("mooo");
var firstWrapper = createSomething(firstHorse);
var secondWrapper = createSomething(secondHorse);
var nothingWrapper = createSomething();
firstWrapper.someMethod();
firstWrapper.callTheOther();
console.log(firstWrapper.doTheNoise());
secondWrapper.someMethod();
secondWrapper.callTheOther();
console.log(secondWrapper.doTheNoise());
nothingWrapper.someMethod();
//this call fails as we dont have this method on the fall through object (which is undefined)
console.log(nothingWrapper.doTheNoise());
I was actually anticipating having to use bind in there somewhere but it appears not to be necessary.
Not to my knowledge, but you can simulate it by initializing the function to null at first and then replacing the implementation later.
var foo = null;
var bar = function() { alert(foo()); } // Appear to use foo before definition
// ...
foo = function() { return "ABC"; } /* Define the function */
bar(); /* Alert box pops up with "ABC" */
This trick is similar to a C# trick for implementing recursive lambdas, as described here.
The only downside is that if you do use foo before it's defined, you'll get an error for trying to call null as though it were a function, rather than a more descriptive error message. But you would expect to get some error message for using a function before it's defined.
This question just got upvoted so can update question with what I did
I solved it by iterating over the window object (or user specified object root) and when I found the correct instance I backtracked and got the name from the index. The final solution can be found here
https://github.com/AndersMalmgren/Knockout.BindingConventions
Update end
I'm planning on writing a convention over configuration template source engine for KnockoutJS / MVC.
I'm started with a little client side POC and ran into a show stopper right away
My plan is use this syntax or something similar
MyApp.EditCustomersViewModel = function() {
ko.templates.loadView(this);
};
When doing this it will check the tamplate cache or fetch the templates from server using the object name as key.
The problem is I cant get the name of the prototype object, i tried this
Object.prototype.getName = function() {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec((this).constructor.toString());
return (results && results.length > 1) ? results[1] : "";
};
If works for objects defined like this
function MyClass() {
}
If you add a prototype to the above object it will not work, or if you define it like this
MyApp = {};
MyApp.MyClass = function() {
};
Prototype and scoping is two musts so this is a showstopper, any ideas?
Fiddle: http://jsfiddle.net/aRWLA/
edit: The background for this is like this.
On the server you have structure like this
Templates\ [ViewName]\index.html
Templates\ [ViewName]\sub-model-template.html
on the client you will do
MyApp.EditCustomersViewModel = function() {
ko.templates.loadView(this);
};
which will generate a ajax request with the objects name as key, which will fetch all the templates for the view in question
Only hoisted functions (function someFunc() {) have a retrievable name.
Assigned functions do not, because you are not technically naming the function but creating an anonymous function and assigning a reference to it (in the memory) to a named variable.
So it's the var, not the function, that is named.
This makes the very idea of retrieving function names pretty much a none-starter, since in any vaguely mature pattern you'll be writing methods, not hoisted functions - and methods of course are assigned functions.
Named expressions (see other answers) are a partial workaround but these have other issues - not least lack of support in older IEs.
(Sidenote: I've long expected browser vendors to build around this such that the names of assigned functions became retrievable, but no joy yet AFAIK.)
I think you problem in improper replacing function prototype: if you replace function prototype object then you must preserve constructor member in prototype:
function Test1() {
}
Test1.prototype={
constructor: Test1
};
MyApp={};
MyApp.MyClass=function MyClass(){
};
MyApp.MyClass.prototype={
constructor: MyApp.MyClass
};
Your example: http://jsfiddle.net/aRWLA/1/
Modified example: http://jsfiddle.net/aRWLA/2/
You can make use of named function expressions:
MyApp.MyClass = function MyClass() { ... };
But note that (suprise) they don't work correctly in all versions of IE.
See: http://kangax.github.com/nfe/
THIS DOES NOT ANSWER THE QUESTION
However, the code might be useful to other people, so I'm leaving it here, just in case. I don't expect upvotes, but please don't abuse it for downvoting either. Thanks.
I don't know your use case, as such I think you've got a design issue - the problem you describe shouldn't happen in practice.
But let's say you do need to have this working. An easy way to do what you need would be something like:
function findNamed(obj, fn){
for(var p in obj)
if(obj[p] === fn)
return p;
return false;
}
var m = {};
m.MyClass = function() {};
console.log(findNamed(m, m.MyClass));
Of course, the solution could be made into a more appropriate OOP form, but this is just to give an idea.
To replicate your use case, it would look like:
m.MyClass = function() {
findNamed(this, arguments.callee);
};
So, the final code is:
Object.prototype.getNameOfCall = function(fn) {
for(var p in this)
if(this[p] === fn)
return p;
throw "Callback not in object.";
};
var m = {};
m.MyClass = function() {
console.log(this.getNameOfCall(arguments.callee)); // MyClass
};
m.MyClass(); // test it out
I've read pages and pages about JavaScript prototypal inheritance, but I haven't found anything that addresses using constructors that involve validation. I've managed to get this constructor to work but I know it's not ideal, i.e. it's not taking advantage of prototypal inheritance:
function Card(value) {
if (!isNumber(value)) {
value = Math.floor(Math.random() * 14) + 2;
}
this.value = value;
}
var card1 = new Card();
var card2 = new Card();
var card3 = new Card();
This results in three Card objects with random values. However, the way I understand it is that each time I create a new Card object this way, it is copying the constructor code. I should instead use prototypal inheritance, but this doesn't work:
function Card(value) {
this.value = value;
}
Object.defineProperty( Card, "value", {
set: function (value) {
if (!isNumber(value)) {
value = Math.floor(Math.random() * 14) + 2;
}
this.value = value;
}
});
This doesn't work either:
Card.prototype.setValue = function (value) {
if (!isNumber(value)) {
value = Math.floor(Math.random() * 14) + 2;
}
this.value = value;
};
For one thing, I can no longer call new Card(). Instead, I have to call var card1 = new Card(); card1.setValue(); This seems very inefficient and ugly to me. But the real problem is it sets the value property of each Card object to the same value. Help!
Edit
Per Bergi's suggestion, I've modified the code as follows:
function Card(value) {
this.setValue(value);
}
Card.prototype.setValue = function (value) {
if (!isNumber(value)) {
value = Math.floor(Math.random() * 14) + 2;
}
this.value = value;
};
var card1 = new Card();
var card2 = new Card();
var card3 = new Card();
This results in three Card objects with random values, which is great, and I can call the setValue method later on. It doesn't seem to transfer when I try to extend the class though:
function SpecialCard(suit, value) {
Card.call(this, value);
this.suit = suit;
}
var specialCard1 = new SpecialCard("Club");
var specialCard2 = new SpecialCard("Diamond");
var specialCard3 = new SpecialCard("Spade");
I get the error this.setValue is not a function now.
Edit 2
This seems to work:
function SpecialCard(suit, value) {
Card.call(this, value);
this.suit = suit;
}
SpecialCard.prototype = Object.create(Card.prototype);
SpecialCard.prototype.constructor = SpecialCard;
Is this a good way to do it?
Final Edit!
Thanks to Bergi and Norguard, I finally landed on this implementation:
function Card(value) {
this.setValue = function (val) {
if (!isNumber(val)) {
val = Math.floor(Math.random() * 14) + 2;
}
this.value = val;
};
this.setValue(value);
}
function SpecialCard(suit, value) {
Card.call(this, value);
this.suit = suit;
}
Bergi helped me identify why I wasn't able to inherit the prototype chain, and Norguard explained why it's better not to muck with the prototype chain at all. I like this approach because the code is cleaner and easier to understand.
the way I understand it is that each time I create a new Card object this way, it is copying the constructor code
No, it is executing it. No problems, and your constructor works perfect - this is how it should look like.
Problems will only arise when you create values. Each invocation of a function creates its own set of values, e.g. private variables (you don't have any). They usually get garbage collected, unless you create another special value, a privileged method, which is an exposed function that holds a reference to the scope it lives in. And yes, every object has its own "copy" of such functions, which is why you should push everything that does not access private variables to the prototype.
Object.defineProperty( Card, "value", ...
Wait, no. Here you define a property on the constructor, the function Card. This is not what you want. You could call this code on instances, yes, but note that when evaluating this.value = value; it would recursively call itself.
Card.prototype.setValue = function(){ ... }
This looks good. You could need this method on Card objects when you are going to use the validation code later on, for example when changing the value of a Card instance (I don't think so, but I don't know?).
but then I can no longer call new Card()
Oh, surely you can. The method is inherited by all Card instances, and that includes the one on which the constructor is applied (this). You can easily call it from there, so declare your constructor like this:
function Card(val) {
this.setValue(val);
}
Card.prototype...
It doesn't seem to transfer when I try to extend the class though.
Yes, it does not. Calling the constructor function does not set up the prototype chain. With the new keyword the object with its inheritance is instantiated, then the constructor is applied. With your code, SpecialCards inherit from the SpecialCard.prototype object (which itself inherits from the default Object prototype). Now, we could either just set it to the same object as normal cards, or let it inherit from that one.
SpecialCard.prototype = Card.prototype;
So now every instance inherits from the same object. That means, SpecialCards will have no special methods (from the prototype) that normal Cards don't have... Also, the instanceof operator won't work correctly any more.
So, there is a better solution. Let the SpecialCards prototype object inherit from Card.prototype! This can be done by using Object.create (not supported by all browsers, you might need a workaround), which is designed to do exactly this job:
SpecialCard.prototype = Object.create(Card.prototype, {
constructor: {value:SpecialCard}
});
SpecialCard.prototype.specialMethod = ... // now possible
In terms of the constructor, each card IS getting its own, unique copy of any methods defined inside of the constructor:
this.doStuffToMyPrivateVars = function () { };
or
var doStuffAsAPrivateFunction = function () {};
The reason they get their own unique copies is because only unique copies of functions, instantiated at the same time as the object itself, are going to have access to the enclosed values.
By putting them in the prototype chain, you:
Limit them to one copy (unless manually-overridden per-instance, after creation)
Remove the method's ability to access ANY private variables
Make it really easy to frustrate friends and family by changing prototype methods/properties on EVERY instance, mid-program.
The reality of the matter is that unless you're planning on making a game that runs on old Blackberries or an ancient iPod Touch, you don't have to worry too much about the extra overhead of the enclosed functions.
Also, in day-to-day JS programming, the extra security from properly-encapsulated objects, plus the extra benefit of the module/revealing-module patterns and sandboxing with closures VASTLY OUTWEIGHS the cost of having redundant copies of methods attached to functions.
Also, if you're really, truly that concerned, you might do to look at Entity/System patterns, where entities are pretty much just data-objects (with their own unique get/set methods, if privacy is needed)... ...and each of those entities of a particular kind is registered to a system which is custom made for that entity/component-type.
IE: You'd have a Card-Entity to define each card in a deck.
Each card has a CardValueComponent, a CardWorldPositionComponent, a CardRenderableComponent, a CardClickableComponent, et cetera.
CardWorldPositionComponent = { x : 238, y : 600 };
Each of those components is then registered to a system:
CardWorldPositionSystem.register(this.c_worldPos);
Each system holds ALL of the methods which would normally be run on the values stored in the component.
The systems (and not the components) will chat back and forth, as needed to send data back and forth, between components shared by the same entity (ie: the Ace of Spade's position/value/image might be queried from different systems so that everybody's kept up to date).
Then instead of updating each object -- traditionally it would be something like:
Game.Update = function (timestamp) { forEach(cards, function (card) { card.update(timestamp); }); };
Game.Draw = function (timestamp, renderer) { forEach(cards, function (card) { card.draw(renderer); }); };
Now it's more like:
CardValuesUpdate();
CardImagesUpdate();
CardPositionsUpdate();
RenderCardsToScreen();
Where inside of the traditional Update, each item takes care of its own Input-handling/Movement/Model-Updating/Spritesheet-Animation/AI/et cetera, you're updating each subsystem one after another, and each subsystem is going through each entity which has a registered component in that subsystem, one after another.
So there's a smaller memory-footprint on the number of unique functions.
But it's a very different universe in terms of thinking about how to do it.
I am learning more advanced OO tactics for javascript coming from a C# background and am wondering about how to or if its even a good idea to implement prototype based validation. For instance when an object or function requires one of its parameters to satisfy a certain interface, you could check its interface like so,
var Interface = function Interface(i) {
var satisfied = function (t, i) {
for (var key in i) {
if (typeof t !== 'object') {
return false;
}
if (!(key in t && typeof t[key] == i[key])) {
return false;
}
}
return true;
}
this.satisfiedBy = function (t) { return satisfied(t, i); }
}
// the interface
var interfacePoint2D = new Interface({
x: 'number',
y: 'number'
});
// see if it satisfies
var satisfied = interfacePoint2D.satisfiedBy(someObject);
I came up with this strategy to validate an object by its interface only, ignoring the internal implementation of the object.
Alternatively say you are using prototype-based inheritance, should you or should not validate parameters based on their prototype functions? I understand that you'd use a prototype to implement default functionality whereas an interface doesn't specify any default functionality. Sometimes the object you are passing into a function might need certain default functionality in order for that function to work. Is it better to only validate against an interface, or should you ever validate against a prototype, and if so, whats the best way to do it?
EDIT -- I am providing some more context as to why I am asking this,
Say for instance in online game design (games written mostly in javascript). There are 2 main reasons I am interested in validation within this context,
1) Providing a strong public API for modding the game if desired
2) Preventing (or atleast discouraging greatly) potential cheaters
Which requires a balance between customizability and abuse. Specifically one situation would be in designing physics engine where objects in the game react to gravity. In a realistic system, users shouldn't be able to add objects to the system that do not react to gravity. The system has a function that expresses the global effect of gravity at any given point:
function getGravityAt(x, y) {
// return acceleration due to gravity at this point
}
And objects which react have a method that uses this to update their acceleration:
function update() {
this.acceleration = getGravity(this.position);
}
The minimum thing to do might be to ensure that any object added to the system has an 'update' method, but you still aren't ensuring that the update() method really is intended to react to gravity. If only objects that inherit from a prototypical update() method are allowed, then you know at least to some degree everything in the system reacts realistically.
This is a pretty subjective question. I'll pass on the question of whether it's a good idea to do interface-based validation in Javascript at all (there may well be good use-cases for it, but it's not a standard approach in the language). But I will say that it's probably not a good idea to validate objects based on their prototypes.
If you're validating by interface at all, you're probably working with objects created by other programmers. There are lots of ways to create objects - some rely on prototypes, some do not, and while they each have their proponents, they're all valid and likely approaches. For example:
var Point = function(x,y) {
return {
x: function() { return x },
y: function() { return y }
};
};
var p = new Point(1,1);
The object p conforms to an interface similar to yours above, except that x and y are functions. But there's no way to validate that p satisfies this interface by inspecting its constructor (which is Object()) or Point.prototype. All you can do is test that p has attributes called x and y and that they are of type "function" - what you're doing above.
You could potentially insist that p has a specific ancestor in its prototype chain, e.g. AbstractPoint, which would include the x and y functions - you can use instanceof to check this. But you can't be sure that x and y haven't been redefined in p:
var AbstractPoint = function() {};
AbstractPoint.prototype.x = function() {};
AbstractPoint.prototype.y = function() {};
var Point = function(x,y) {
var p = new AbstractPoint(x,y);
p.x = "foo";
return p;
}
var p = new Point(1,1);
p instanceof AbstractPoint; // true
p.x; // "foo"
And perhaps more importantly, this makes it harder to drop in custom objects that also satisfy the interface but don't inherit from your classes.
So I think what you're currently doing is probably the best you can hope for. In my experience, Javascript programmers are much more likely to use on-the-fly duck-typing than to try to mimic the capabilities of statically typed languages:
function doSomethingWithUntrustedPoint(point) {
if (!(point.x && point.y)) return false; // evasive action!
// etc.
}
I'll reiterate, type checking is not idiomatic javascript.
If you still want type checking, Google's closure compiler is the implementation I recommend. Type checking is done statically :) It has conventions for interfaces as well as (proto)type checking.
I'm relatively new to Javascript. I was wondering if it supports components and objects like Python does. If it does, what would the syntax look like?
For instance, I know an object look like this:
function Foo(a, b) {
this.a = a;
this.b = b;
}
Now, is there a way to declare some components, pick one of those, and add it to the object? For instance, let's say I have a object Item. Could I declare some different components, such as Weapon, Magical, Legendary, etc. and them add them to the object? Using this approach I could end up with a Magical Weapon, or a Legendary Item, or even a Legendary Magical Weapon.
I thought about using parenting for this but for what I want to do, it seems like that would be rather limited. For instance, my heirarchy would look like Item/Weapon or Item/Legendary, so I couldn't have a Legendary Weapon.
So, are components possible in Javascript?
What you describe as a 'component' is more commonly called a class. What you describe as 'parenting' is more commonly called inheritance. You are spot on about the class hierarchy :)
Ok, so your base class in an Item. This item will have the basic attributes which all items in your game world must have. All objects in your game world will inherit from Item.
A Weapon is an Item. A MagicalItem is an Item. A LegendaryItem is an item. These three classes are all subclasses of Item.
Things get a little bit more tricky when you want a LegendaryMagicalWeaponItem. This is the essence of your question: Is multiple inheritance possible in JavaScript?
To paraphrase the Boondock Saints, you do not want multiple inheritance unless you are absolutely, positively sure that you need it. Why? It quickly leads to complications. For example, what if two superclasses have a method or an attribute with the same name? What if they inherit from two different base classes, and one of those classes causes a name collision? You can see where this is going.
Fortunately, JavaScript, like Python, is a very flexible language. You are not forced to use multiple inheritance or even interfaces to generalise behaviour across heterogeneous objects.
Let's say MagicalItem has a mana property and LegendaryItem has a legacy() method. Let's say a weapon object has a damage. Let's say Item has important physical attributes and a bunch of physics methods; it is clearly the 'dominant' superclass. There is nothing stopping you from doing this:
// Base classes
function Item() {
// some default values...
}
Item.prototype.physics = function (t) {/* physics stuff */}
function Magical(mana) {
this.mana = mana;
}
function Weapon(damage) {
this.damage = damage;
}
function Legendary(legacy) {
this.legacy = function () {return legacy;};
}
// Actual world item class
function MyLegendaryMagicalSword(x,y) {
this.x = x;
this.y = y;
Weapon.call(this, MyLegendaryMagicalSword.DAMAGE);
Legendary.call(this, MyLegendaryMagicalSword.LORE);
Magical.call(this, MyLegendaryMagicalSword.START_MANA);
}
// actual prototypal inheritance
MyLegendaryMagicalSword.prototype = new Item();
// class attributes
MyLegendaryMagicalSword.DAMAGE = 1000;
MyLegendaryMagicalSword.START_MANA = 10;
MyLegendaryMagicalSword.LORE = "An old sword.";
// Sword instance
var sword = new MyLegendaryMagicalSword(0, 0);
sword.physics(0);
sword.mana;
sword.legacy();
// etc
// probe object for supported interface
if (sword.hasOwnProperty("damage")) {
// it's a weapon...
}
This is a down and dirty way to do what you describe.
> sword
{ x: 0,
y: 0,
damage: 1000,
legacy: [Function],
mana: 10 }
I have no idea what you mean by components. The term is too generalized. In Delphi, a component is a non-visible code module which introduces some special functionality to the application. A "timer" is one such example of a component (in Delphi).
Guessing from your description, you seem to want to add properties dynamically? Or is it about overloading?
In the latter case, you can't do this by design, as in, it lifts the limitations you mentioned.
Example (mixing):
function mixItems(weapon,legend){
return {
"damage":legend.damage+weapon.damage,
"name":legend.name+"' "+weapon.name
};
}
var weapon={ "damage":45, "name":"sword"};
var legend={ "name":"Goliath", "damage":34 };
var LegendaryWeapon = mixItems(weapon,legend);
console.log( LegendaryWeapon );
// output:- name: "Goliath's sword", damage: 79
Example (extending):
function clone(old){ // non-deep cloning function
var res={};
for(i in old)
res[i]=old[i];
return res;
}
var sword = {
"damage":50
"hit": function(){ // returns the percentage hit chance
return Math.round(Math.random()*100);
}
};
var bigsword=clone(sword);
bigsword.damage=60;
bigsword.hit=function(){ // returns the percentage hit chance
return Math.round(Math.random()*80)+20;
};
an object in javascript looks like this:
var Foo = {
a: null,
b: null,
init: function(a,b){
this.a = a;
this.b = b;
}
}
//call the init:
Foo.init(12,34);
almost the same as you have in the question.
And this object is extendable
you code example is a Function object which is intended to be used as a constructor function i.e. call it with the new keyword and it returns an instance of an object that has an a property and a b property (amongst other inherited properties).
Function objects inherit from Object like all other objects in JavaScript.
Usually, objects are created using object literal syntax, i.e. var x = { a: 'a', b: 'b' }; although they can also be created by using the new keyword with Object.
It looks like your question is referring to inheritance with JavaScript. Well, there are many ways to perform inheritance. One example is
function A() { }
function B() { }
B.prototype = new A;
Here both A and B are constructor functions. Functions have a prototype property which is an object and can contain members that can be shared by all object instances constructed by the function. We assign an instance of an object returned by the constructor function A to B's prototype, giving B all members available on an instance of A. This is just one way to perform inheritance in JavaScript.
The Mozilla Developer Center article on the Object Model is worth a read.