Javascript - Prototypal inheritance problem and possible general understanding issues
I started to learn JavaScript, after years of using it without really knowing what's going on, i decided it is time to do something about that. Additionally, I work on a project where JavaScripts can be used to script the Application.
So, enough of all the yada-yada, my problem relates to prototypal inheritance, I think I know how it works by now, but there might be issues. The basic Idea is that every object (well, no开发者_StackOverflow中文版t every object - yeah ;-)) has a prototype where all requests are delegated to if the actual object cannot handle it until the end of the prototype chain has been reached (the prototype of an object can have a prototype too, right?).
In my Application, massive filtering is going to happen and I want to give the users (which are not very technical, It should be as easy as possible.) a way to chain simple filter commands narrowing the result set with each additional call. What do I mean? Smth. like this:
zoo.getAnimals().getAnimalsWithFurColor("red").getMammals()
zoo
is always in scope and is an object containing animals and additional properties for the zoo. So, I would have an object like this (lets call it Container
) to be returned by all method calls in the example:
{
data: [harryTheElephant, sallyThePenguin, timTheWoodpecker],
someFilterMethod: function() {
return new Container(data.filter(function(animal) {
return animal.someProperty == someValue;
});
}
}
So far, so good. But i want the Zoo to be a container too. This is where my real question comes into play: As the zoo has to do some very expensive stuff to retrieve the starting set of animals, i want to lazy-load them. When the zoo gets an getAnimals()
request the data is fetched.
My Idea was to set the prototype of the Zoo to be a Container which obtains its data from the zoo. But I cannot find a way to access the getAnimals()
method from the zoo from the prototype (the container). I tried it with this
but the method cannot be found.
Any Ideas how to write code that does what i want to do? Please note that i'm not in a Browser environment, i embed JavaScript (1.7) in my Application.
Thanks!
It doesn't make much sense for an object to access the properties of something that (prototypally) inherits from it. E.g., if a Cat
has a meow()
method, it would be weird for Mammal
to reference meow()
. Similarly, it would be weird for Container
to reference getAnimals()
, if Zoo
is the one deriving from Container
.
My suggestion, to accomplish your lazy-loading, would be to pass an accessor function that returns an array into the Container
constructor, instead of passing an array directly. This might look something like:
function Container(getAnimals) {
this.someFilterMethod = function () {
return new Container(function () {
return getAnimals().filter(function (animal) {
return animal.someProperty === someValue;
});
});
};
this.get = getAnimals;
}
function makeZoo(animals) {
var zoo = Object.create(new Container(function () { return animals; }));
zoo.customZooMethod = function () { /* ... */ };
return zoo;
}
var aZoo = makeZoo([harryTheElephant, sallyThePenguin, timTheWoodpecker]);
var filteredAnimals = aZoo.someFilterMethod().get();
Objects inherit from their internal prototype, not their public prototype.
To implement chaining, just have each method return the instance.
e.g.
function Foo(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Foo.prototype.sayFirstName = function() {
alert(this.firstName);
return this;
}
Foo.prototype.sayLastName = function() {
alert(this.lastName);
return this;
}
var foo = new Foo('Foo', 'Bar');
foo.sayFirstName().sayLastName();
However, chaining isn't a good idea because it makes debugging difficult. If you chain a bunch of commands together and in a single statement or expression and it fails, how do you find out which one failed?
Edit
You may want to do something like:
// Container constructor
function Container(dataArray) {
this.data = dataArray;
}
// Filter data and return new container
Container.prototype.getAnimalsWithFurColor = function(color) {
var filteredArray = [];
for (var i=0, iLen=this.data.length; i<iLen; i++) {
// Presuming the items (animals?) in data have a getColor methed
if (this.data[i].getColor() == color) {
filteredArray.push(this.data[i]);
}
}
return new Container(filteredArray);
}
精彩评论