Collection/Instance objects style vie javascript without proto - javascript

I'm trying to make classical Collection/Instance model via javascript. So Collection object has some method for working with full collection and ((new Collection()) instanceof Instance) has methods to work with the instance. My code is rather simple.
var Collection = function Collection() {
this.message = "collection";
var I = Instance.bind(null, this);
I.__proto__ = this;
return I;
};
Collection.prototype = {
collectionMethod: function () {
console.log(this.message);
}
};
var Instance = function Instance(collection) {
this.collection = collection;
this.message = "instance";
};
Instance.prototype = {
instanceMethod: function () {
console.log(this.message);
}
};
// Test exec (values are like expected);
var C = new Collection();
var i = new C();
C.collectionMethod(); // collection
i.instanceMethod(); // instance
i.collection.collectionMethod(); // collection
C.newMethod(); // TypeError
i.newMethod(); // TypeError
Collection.prototype.newMethod = Instance.prototype.newMethod = function () {
console.log("newMethod: " + this.message);
}
C.newMethod(); // newMethod: collection
i.newMethod(); // newMethod: instance
But i don't want to use proto because it's not a part of standart and doesn't work in IE at all. Is there any way around in this case?
Some explanations about what's all about. For example you have a collection of users. And you want to be able find the user and create new one.
So you create new collection like
var User = new Collection();
Then you create new instance like.
var me = new User({name: "alex"});
And now you find this instance like
User.find_by_name("alex"); // === me
Also (in fact this is the main reason i'm doing this way instead of just creating something like User.new function to use it like var me = User.new({name: "alex"});) you can know who I am doing something like (if you for example have also var Dog = new Collection())
me instanceof Dog // false
me instanceof User // true

This code:
var I = Instance.bind(null, this);
I.__proto__ = this;
return I;
really doesn't make much sense. Function.bind creates a new function, so anyone calling your Collection function, in any way, will get back a function, not an object whose prototype is set to the function's prototype.
In general, if you want to create an object whose prototype is set to a specific object, you don't set __proto__ since that's not standard, as you stated. The best way is to just use Object.create (which is shimable if you want to support IE8).
var I = Object.create(this);
Also, the reason you're getting errors on newMethod is because you're trying to call them before you add them to the prototype:
Collection.prototype.newMethod = Instance.prototype.newMethod = function () {
console.log("newMethod: " + this.message);
}
C.newMethod(); // should work now
i.newMethod(); // should work now

So seems like it's impossible for now. More information can be found here.
How do I inherit javascript functions ?

Related

Can a javascript function be a class and an instance of another object?

If you look at this code:
function supportAggregate(Meanio) {
Meanio.prototype.aggregated = function(ext, group, callback) {
// Aggregated Data already exists and is ready
if (Meanio.Singleton.config.clean.aggregate === false){
return callback('');
}
if (aggregated[group][ext].data) return callback(aggregated[group][ext].data);
// No aggregated data exists so we will build it
sortAggregateAssetsByWeight();
// Returning rebuild data. All from memory so no callback required
callback(aggregated[group][ext].data);
};
Meanio.prototype.aggregatedsrc = function(ext, group, callback) {
// Aggregated Data already exists and is ready
if (Meanio.Singleton.config.clean.aggregate !== false){
if(ext==='js'){
if(group==='header'){
return callback(['/modules/aggregated.js?group=header']);
}else{
return callback(['/modules/aggregated.js']);
}
}else if(ext==='css' && group==='header'){
return callback(['/modules/aggregated.css']);
}
return callback([]);
}
if (aggregated[group][ext].src) return callback(aggregated[group][ext].src);
// No aggregated data exists so we will build it
sortAggregateAssetsByWeight();
// Returning rebuild data. All from memory so no callback required
callback(aggregated[group][ext].src);
};
// Allows rebuilding aggregated data
Meanio.prototype.rebuildAggregated = function() {
sortAggregateAssetsByWeight();
};
Meanio.prototype.Module.prototype.aggregateAsset = function(type, asset, options) {
options = options || {};
if (!options.inline && !options.absolute && !options.url) {
asset = path.join(Meanio.modules[this.name].source, this.name, 'public/assets', type, asset);
}
Meanio.aggregate(type, asset, options, Meanio.Singleton.config.clean);
};
Meanio.onModulesFoundAggregate = function(ext, options) {
var config = Meanio.Singleton.config.clean;
var aggregator = new Aggregator(options, false, config);
for (var name in Meanio.modules) {
aggregator.readFiles(ext, path.join(process.cwd(), Meanio.modules[name].source, name.toLowerCase(), 'public'));
}
};
Meanio.aggregate = function(ext, asset, options, config) {
var aggregator;
options = options || {};
if (!asset) {
return;
}
aggregator = new Aggregator(options, true, config);
if (options.inline) return aggregator.addInlineCode(ext, asset);
else if (options.url) return aggregator.getRemoteCode(ext, asset);
else if (options.singlefile) return aggregator.processDirOfFile(ext, asset);
else return aggregator.readFile(ext, path.join(process.cwd(), asset));
};
Meanio.prototype.aggregate = Meanio.aggregate;
}
module.exports = supportAggregate;
(https://github.com/linnovate/meanio/blob/master/lib/aggregation.js#L213)
You can see that there are two types of functions for Meanio that are created. Also, by the way, you can see where this is instantiated here: https://github.com/linnovate/meanio/blob/master/lib/mean.js#L114
But I'm just confused. Sometime, Meanio functions are defined like this:
Meanio.prototype.myfunction = function() {}
and sometimes they are defined like this:
Meanio.myfunction = function() {}
I just don't get it; although I have a feeling that dependency injection is somehow involved.
How can this be? How can an object be both a class and an instance of itself?
This code is very confusing to me, and I would really appreciate it if someone could shed some light on this for me. I'm not asking you to heavily research the code, but if you could give me a general understanding, that would be great.
Thanks in advance!
How can an object be both a class and an instance of itself?
That's not what's going on here. The object passed to the function is an instance.
The function does however modify both the instance that you pass to it, and the class of that instance.
If you create two instances of the same class, and pass one of them to the function, the other instance is not modified, but the class that is common to them is modified. Example:
function MyClass() {}
var a = new MyClass();
var b = new MyClass();
supportAggregate(a);
Now both a.rebuildAggregated and b.rebuildAggregated exist, as that is added to the class. The a.onModulesFoundAggregate exists because it's added to the instance, but b.onModulesFoundAggregate doesn't exist.
(Note: The example won't actually work, as there is more going on. The class has to have some more properties to work with that function, the example is only to show the difference between properties added to the prototype and to the instance.)
Let's say I have a constructor
// First I will define a constructor
function MyClass() {
this.classproperty = 1;
}
In Javascript the constructor is also an object instance. When I use "this" keyword inside a constructor I'm telling that I want to create a new property inside a special object present in all javascript objects called prototype.
// Then I add a new property without using prototype obj
MyClass.newProperty = 2;
alert(MyClass.classproperty); // alert 1
alert(MyClass.newProperty); // alert 2
// It will work because I'm using the MyClass main Object
When you create a new instance from Myclass Obj. The new created object will inherit the prototype object from parent (the one used to instantiate), but not the properties added straight to MyClass obj:
var instance = new MyClass();
alert(instance.newProperty); // undefined because the new instance will
// inherit only what is inside prototype obj
I have to add it to the prototype object in order to new instances inherit the property;
Myclass.prototype.newProperty = 2;
var instance = new Myclass();
alert(instance.newProperty) // alert 2

How to make the variable available in the methods of the class?

I apologize for this question, just starting to learn Javascript.
I have 2 methods:
Manager.prototype.filters = function () {
var user = [];
...
Manager.prototype.filters_main = function () {
var user = [];
...
I need to make the property 'user' available to the 2 methods (filters, filters_main). So that they can use the shared variable (user).
How it is possible to write?
You have to understand the prototype-based inheritance here.
var Manager = function() {
this.user = [];
}
var manager = new Manager();
These lines will define a Manager constructor function and create a new object. When you call the new Manager(), what happens is:
a new, empty, object is created: {}.
the code inside the constructor will run with this new, empty, object being the value of this. So, it will set the user property of the new object ({}) to be an empty array.
the __proto__ property of the new object will be set to the value of Manager.prototype. So, this happens without you seeing: manager.__proto__ = Manager.prototype.
Then, you want to define new methods on your prototype objects, using the inheritance. Keep in mind that the prototype is a plain JS object. Not a constructor, but an object. So every object created from the Manager function will have its __proto__ property set to the same object.
Then, you start defining new methods on the prototype object, like the filters function. When you, later, call manager.filters(), it will first look up its own properties for the filters function and won't find it. So, then, it will go for its prototype properties, and there if will find it. manager will then run the filters function that was defined on the prototype, but using itself (manager) as the context, as the this inside the function.
So, to use your user property inside the filters function, all you have to do is:
Manager.prototype.filters = function () {
this.user = ...;
}
Manager.prototype.filters_main = function () {
this.user = ...;
}
and you'll be manipulating the same user property defined when the object was constructed.
Define the variable in your Manager definition:
function Manager() {
this.user = [];
}
And now you should be able to use it in your filter functions:
Manager.prototype.filters = function() {
// Use it:
if (this.user.indexOf(...) != -1) {
...
}
};
Then you can continue as normal:
var manager = new Manager();
manager.user = ["user1", "user2"];
var filters = manager.filters();
Add it to the body:
function Manager() {
this.user = [];
}
Manager.prototype.filters = function () {
alert(this.user)
}
var m = new Manager();
m.user = [11,22,33]
m.filters();

Object Oriented JavaScript programming

I have been trying to learn OOP with JavaScript before I start attempting to learn backbone.js.
I want to be able to data bind but I can't seem to get it to work.
I've just made a simple protoype of a budget website that you can put in a budget and input how much you've spent, and it will show if you've gone over.
function BudgetItem(spent, budget){
this.setSpent = function(spent){
this.spent = spent;
}
this.setBudget = function(budget){
this.budget = budget;
}
this.getSpent = function(){
return this.spent;
}
this.getBudget = function(){
return this.budget;
}
}
function BudgetType(type){
this.getType = function(){
return type;
}
}
BudgetType.prototype = new BudgetItem();
$(document).ready(function(){
var food = new BudgetType('food');
$('.budget').html(food.getBudget());
$('.editbudget').change(function(){
food.setBudget($('.editbudget').data())
});
})
That's my code thus far. I'm not sure if I'm doing it right. Am I supposed to extend things? Also, can someone explain how to dynamically data bind without a library?
First I'll give you some theory. A Javascript function is a dynamic object, just like Object is, and a new instance can be created using the new keyword much like you are doing in your listener. When this happens, the function itself will run as a constructor while the this keyword will be bound to the newly created object. What you're doing above then is in fact adding new properties on the fly as you're passing in their values for the first time... which is fine, but not very clear to another reader.
Now for the tricky part. Every function has a link to a "hidden" Prototype object. This is an anonymous (not accessible by name) object created by the JavaScript runtime and passed as a reference to the user object through the prototype property. This Prototype object also has a reference to the function through its constructor property. To test what I'm saying for yourself, try the following:
BudgetItem.prototype.constructor === BudgetItem // true
Putting it all together, you can now think of functions as constructors to (hidden) classes that are created for you behind the scenes, accessible through the function's prototype property. So, you could add the fields to the Prototype object directly as so:
function BudgetItem(spent) {
this.spent = spent
}
BudgetItem.prototype.setSpent = function(spent) { this.spent = spent };
BudgetItem.prototype.getSpent = function() { return this.spent };
Another problem is inheritance and passing parameters to the constructor. Again, your version is valid but you lose the ability to pass the spent and budget values when initializing a BudgetType. What I would do is forget prototypes and go:
function BudgetType(type, spent) {
var instance = new BudgetItem(spent);
instance.type = type;
return instance;
}
This is close to what Scott Sauyet suggested above but more powerful. Now you can pass both parameters (and more) and have a more complicated inheritance tree.
Finally, what you can do is create private (or pseudo-private, more accurately) properties by providing a getter to an otherwise automatic variable (one passed as an argument or initialised inside the function). This is a special feature of the language and it works like so:
function BudgetType(type, spent) {
var instance = new BudgetItem(spent);
instance.getType = function() {
return type;
}
return instance;
}
Now you can access the 'type' passed in the constructor by obj.getType() but cannot override the initial value. Even if you define obj.type = 'New Value' the getType() will return the initial parameter passed because it has a reference to another context which was created when the object was initialised and never got released due to the closure.
Hope that helps...
if you want all instances of objects to reference the same members/values you can use a closure:
// create a constrctor for you object wrapped in a closure
myCon = (function() {
// define shared members up here
var mySharedObj = new function () {
this.member = "a";
}();
// return the actual constructor
return function () {
this.mySharedObj = mySharedObj;
}
}());
// create two instances of the object
var a = new myCon();
var b = new myCon();
// Altering the shared object from one
a.mySharedObj.member = "b";
// Alters it for all
console.log(b.mySharedObj.member);
If you want to build objects from other objects(sort of like other languages' class whatever extends baseClass), but do not want them to share values via reference(instead a clone of values), you can use something like the following:
Object.prototype.extendsUpon = (function (_prop, _args) {
return function (base) {
for (var key in base) {
if (_prop.call(base, key)) {
this[key] = base[key];
}
}
function con(child){
this.constructor = child;
}
con.prototype = base.prototype;
this.prototype = new con(this);
this.__base__ = base.prototype;
var args = _args.call(arguments);
args.shift();
base.constructor.apply(this, args);
}
}(Object.prototype.hasOwnProperty, Array.prototype.slice));
Then to build objects ontop of objects:
// Base Object Constructor
function Fruit(name) {
this.fruitname = name;
}
Fruit.prototype.yum = function() {
return "I had an " + this.fruitname;
}
// Object constructor that derives from the Base Object
function Favorite() {
// Derive this object from a specified base object:
// #arg0 -> Object Constructor to use as base
// #arg1+ -> arguments passed to the BaseObject's constructor
this.extendsUpon(Fruit, "apple");
// From here proceed as usual
// To access members from the base object that have been over-written,
// use "this.__base__.MEMBER.apply(this, arguments)"
}
Favorite.prototype.yum = function() {
return this.__base__.yum.apply(this) + " and it was my favorite";
}
var mmm = new Favorite();
// Outputs: "I had an apple and it was my favorite"
mmm.yum();

How can I count the instances of an object?

If i have a Javascript object defined as:
function MyObj(){};
MyObj.prototype.showAlert = function(){
alert("This is an alert");
return;
};
Now a user can call it as:
var a = new MyObj();
a.showAlert();
So far so good, and one can also in the same code run another instance of this:
var b = new MyObj();
b.showAlert();
Now I want to know, how can I hold the number of instances MyObj?
is there some built-in function?
One way i have in my mind is to increment a global variable when MyObj is initialized and that will be the only way to keep track of this counter, but is there anything better than this idea?
EDIT:
Have a look at this as suggestion here:
I mean how can I make it get back to 2 instead of 3
There is nothing built-in; however, you could have your constructor function keep a count of how many times it has been called. Unfortunately, the JavaScript language provides no way to tell when an object has gone out of scope or has been garbage collected, so your counter will only go up, never down.
For example:
function MyObj() {
MyObj.numInstances = (MyObj.numInstances || 0) + 1;
}
new MyObj();
new MyObj();
MyObj.numInstances; // => 2
Of course, if you want to prevent tampering of the count then you should hide the counter via a closure and provide an accessor function to read it.
[Edit]
Per your updated question - there is no way to keep track of when instances are no longer used or "deleted" (for example by assigning null to a variable) because JavaScript provides no finalizer methods for objects.
The best you could do is create a "dispose" method which objects will call when they are no longer active (e.g. by a reference counting scheme) but this requires cooperation of the programmer - the language provides no assistance:
function MyObj() {
MyObj.numInstances = (MyObj.numInstances || 0) + 1;
}
MyObj.prototype.dispose = function() {
return MyObj.numInstances -= 1;
};
MyObj.numInstances; // => 0
var a = new MyObj();
MyObj.numInstances; // => 1
var b = new MyObj();
MyObj.numInstances; // => 2
a.dispose(); // 1 OK: lower the count.
a = null;
MyObj.numInstances; // => 1
b = null; // ERR: didn't call "dispose"!
MyObj.numInstances; // => 1
Create a static property on the MyObj constructor called say count and increment it within the constructor itself.
function MyObj() {
MyObj.count++;
}
MyObj.count = 0;
var a = new MyObj;
var b = new MyObj;
alert(MyObj.count);
This is the way you would normally do it in say Java (using a static property).
var User = (function() {
var id = 0;
return function User(name) {
this.name = name;
this.id = ++id;
}
})();
User.prototype.getName = function() {
return this.name;
}
var a = new User('Ignacio');
var b = new User('foo bar');
a
User {name: "Ignacio", id: 1}
b
User {name: "foo bar", id: 2}
Using ES6 Classes MDN syntax - we can define a static method:
The static keyword defines a static method for a class. Static methods are called without instantiating their class and cannot be called through a class instance. Static methods are often used to create utility functions for an application.
class Item {
static currentId = 0;
_id = ++Item.currentId; // Set Instance's this._id to incremented class's ID
// PS: The above line is same as:
// constructor () { this._id = ++Item.currentId; }
get id() {
return this._id; // Getter for the instance's this._id
}
}
const A = new Item(); // Create instance (Item.currentId is now 1)
const B = new Item(); // Create instance (Item.currentId is now 2)
const C = new Item(); // Create instance (Item.currentId is now 3)
console.log(A.id, B.id, C.id); // 1 2 3
console.log(`Currently at: ${ Item.currentId }`); // Currently at: 3
PS: if you don't want to log-expose the internal currentId property, make it private:
static #currentId = 0;
_id = ++Item.#currentId;
Here's an example with constructor and without the getter:
class Item {
static id = 0;
constructor () {
this.id = ++Item.id;
}
getID() {
console.log(this.id);
}
}
const A = new Item(); // Create instance (Item.id is now 1)
const B = new Item(); // Create instance (Item.id is now 2)
const C = new Item(); // Create instance (Item.id is now 3)
A.getID(); B.getID(); C.getID(); // 1; 2; 3
console.log(`Currently at: ${ Item.id }`); // Currently at: 3
what about such method?
var Greeter = (function ()
{
var numInstances;
function Greeter(message)
{
numInstances = (numInstances || 0) + 1;
this.greeting = message;
}
Greeter.prototype.greet = function ()
{
return "Hello, " + this.greeting;
};
Greeter.prototype.getCounter = function ()
{
return numInstances;
};
return Greeter;
})();
var greeter = new Greeter("world");
greeter.greet();
greeter.getCounter();
var newgreeter = new Greeter("new world");
newgreeter.greet();
newgreeter.getCounter();
greeter.getCounter();
Keeping a global count variable and incrementing every time is an option. Another option is to call counter method after each instance creation by hand (the worst thing I could imagine). But there is another better solution.
Every time we create an instance, the constructor function is being called. The problem is the constructor function is being created for each instance, but we can have a count property inside __proto__ which can be the same for each instance.
function MyObj(){
MyObj.prototype.addCount();
};
MyObj.prototype.count = 0;
MyObj.prototype.addCount = function() {
this.count++;
};
var a = new MyObj();
var b = new MyObj();
This is our a and b variables after all:
Eventually, JS is going to have built-in proxy capability, which will have low-level access to all kinds of things which happen in the background, which will never be exposed to front-end developers (except through the proxy -- think magic-methods in languages like PHP).
At that time, writing a destructor method on your object, which decrements the counter might be entirely trivial, as long as support for destruction/garbage-collection as a trigger is 100% guaranteed across platforms.
The only way to currently, reliably do it might be something like creating an enclosed registry of all created instances, and then manually destructing them (otherwise, they will NEVER be garbage-collected).
var Obj = (function () {
var stack = [],
removeFromStack = function (obj) {
stack.forEach(function (o, i, arr) {
if (obj === o) { arr.splice(i, 1); }
makeObj.count -= 1;
});
};
function makeObj (name) {
this.sayName = function () { console.log("My name is " + this.name); }
this.name = name;
this.explode = function () { removeFromStack(this); };
stack.push(this);
makeObj.count += 1;
}
makeObj.checkInstances = function () { return stack.length; };
makeObj.count = 0;
return makeObj;
}());
// usage:
var a = new Obj("Dave"),
b = new Obj("Bob"),
c = new Obj("Doug");
Obj.count; // 3
// "Dave? Dave's not here, man..."
a.explode();
Obj.count; // 2
a = null; // not 100% necessary, if you're never going to call 'a', ever again
// but you MUST call explode if you ever want it to leave the page's memory
// the horrors of memory-management, all over again
Will this pattern do what you want it to do?
As long as:
you don't turn a into something else
you don't overwrite its explode method
you don't mess with Obj in any way
you don't expect any prototype method to have access to any of the internal variables
...then yes, this method will work just fine for having the counter work properly.
You could even write a general method called recycle, which calls the explode method of any object you pass it (as long as its constructor, or factory, supported such a thing).
function recycle (obj) {
var key;
obj.explode();
for (key in obj) { if (obj.hasOwnProperty(key)) { delete obj[key]; } }
if (obj.__proto__) { obj.__proto__ = null; }
}
Note - this won't actually get rid of the object.
You'll just have removed it from the closure, and removed all methods/properties it once had.
So now it's an empty husk, which you could reuse, expressly set to null after recycling its parts, or let it be collected and forget about it, knowing that you removed necessary references.
Was this useful?
Probably not.
The only time I really see this as being of use would be in a game where your character might only be allowed to fire 3 bullets at a time, and he can't shoot a 4th until the 1st one on screen hits someone or goes off the edge (this is how, say, Contra worked, in the day).
You could also just shift a "disappeared" bullet off the stack, and reuse that bullet for any player/enemy by resetting its trajectory, resetting appropriate flags, and pushing it back onto the stack.
But again, until proxies allow us to define "magic" constructor/destructor methods, which are honoured at a low-level, this is only useful if you're going to micromanage the creation and destruction of all of your own objects (really not a good idea).
My solution is creating an object store instance count and a function to increase them in prototype.
function Person() {
this.countInst();
}
Person.prototype = {
constructor: Person,
static: {
count: 0
},
countInst: function() {
this.static.count += 1;
}
};
var i;
for (i = 0; i < 10; i++) {
var p = new Person();
document.write('Instance count: ');
document.write(p.static.count);
document.write('<br />');
}
Here is my plunker: https://plnkr.co/edit/hPtIR2MQnV08L9o1oyY9?p=preview
class Patient{
constructor(name,age,id){
Object.assign(this,{name, age, id});
}
static patientList = []; // declare a static variable
static addPatient(obj){
this.patientList.push(...obj); // push to array
return this.patientList.length; // find the array length to get the number of objects
}
}
let p1 = new Patient('shreyas',20, 1);
let p2 = new Patient('jack',25, 2);
let p3 = new Patient('smith',22, 3);
let patientCount = Patient.addPatient([p1,p2,p3]); // call static method to update the count value with the newly created object
console.log(Patient.patientList);
console.log(patientCount);

Understanding Classes and Inheritance in Javascript - New Pattern

I'm designing an OOP inheritance pattern for many applications I'm building. Javascript has many ways of doing this, but I stumbled on a pattern I really like. But now I'm struggling with the need for a separation of classes and instances.
I have a base object called Root. And it has a main method called inherit. To create a new object you use
var Person = Root.inherit({
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
Then to create an "instance" you would
var sally = Person.inherit({
name : "sally",
height : "5'6"
});
sally can .talk() and she can walk() and she has a .name and a .height
You can make more people the same way.
If you want a constructor you use
var Person = Root.inherit({
_construct : function() {
// do things when this object is inherited from
},
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
It also has the ability to have init, when the object is first defined in code (singletons use this)
var Person = Root.inherit({
_init : function() {
// called at runtime, NOT called if an object is inherited from me
},
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
So as you can see, everything uses .inhert(). There are no classes and no instances really. Everything is an instance of something. The only real problem I found so far is that there is no concept of "type", but you can always just check for a method if you need to. Also you can't protect a 'class', as a 'class' can be changed during execution if the developer accidentally changed it, or meant to change it.
So my question is: Is there a need in javascript to have an explicitly and controlled separation of class structure and instances of the class? Are there any issues with treating every object as an instance?
No there's no need since Javascript is a Prototypal based language, meaning that classes are not involved. You are just creating clones of the objects.
http://en.wikipedia.org/wiki/Prototype-based_programming
As far as the concept of type, the type is object.
A good read for more info about this would be Javascript Patterns by Stoyan Stefanov he has several different creational patterns that address your concerns, including examples that implement Design Patterns from the gang of four's design patterns.
http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752
So my question is: Is there a need in javascript to have an explicitly and controlled separation of class structure and instances of the class? Are there any issues with treating every object as an instance?
Not really, if you're happy with it, it's fine.
The more normal form of JavaScript inheritance does much the same thing. You'll frequently see structures like this (severely cut down for brevity):
function Base() {
}
Base.prototype.foo = function() {
};
function Derived() {
}
Derived.prototype = new Base();
...and of course, new Base() is also how you create instances of Base. So your system is quite similar.
Again, the above is a sketch, not a full example. For one thing, usually you'd see construction and initialization separated out, so you don't literally see Derived.prototype = new Base() so much as something that creates an object with Base's prototype but without actually calling Base (which Derived would do later), but you get the idea. Granted that statement somewhat weakens the similarity with your system, but I don't think it breaks it at all.
At the end of the day, it's all about objects (instances), which are either used directly (your sally) or indirectly by providing features to other objects (Person, Root) by cloning or by setting them up as the prototype of the other object.
Javascript's inheritance is prototypical which means everything object is an instance. You actually have to do extra work to get the classical inheritance.
This is how I work in javascript
// this is class
function person(){
// data is member variable
this.name = null;
this.id = null;
//member functions
this.set_name = _set_name;
this.get_name = _get_name;
this.set_id = _set_id;
this.get_id = _get_id;
function _set_name(name){
this.name = name;
}
function _get_name(name){
return this.name;
}
function _set_id(id){
this.id = id;
}
function _get_id(id){
return this.id;
}
}
// this is instance
var yogs = new person();
yogs.set_id(13);
yogs.set_name("yogs");
hope it may help
Start with some basic object...
// javascript prototypes - callback example - javascript objects
function myDummyObject () {
that = this;
} // end function myDummyObject ()
// begin dummy object's prototype
myDummyObject.prototype = {
that : this,
// add a simple command to our dummy object and load it with a callback entry
say : function () {
var that = this;
console.log('speaking:');
that.cb.run("doSay");
}
} // end myDummyObject proto
extend with a sub prototype..
// here we addon the callback handler... universally self sufficient object
var cb = {
that : this, // come to papa ( a link to parent object [ myDummyObject ] )
jCallback : new Array(new Array()), // initialize a javascript 2d array
jCallbackID : -1, // stores the last callback id
add: function(targetFnc, newFunc) {
var that = this;
var whichID = that.jCallbackID++;
// target, addon, active
that.jCallback[that.jCallback.length] = { 'targetFunc' : targetFnc, 'newFunc' : newFunc, 'active' : true, 'id': whichID };
return whichID; // if we want to delete this later...
}, // end add
run: function(targetFnc) {
var that = this;
for(i=0;i <= that.jCallback.length - 1;i++) // go through callback list
if( that.jCallback[i]['targetFunc'] == targetFnc && that.jCallback[i]['active'] == true )
that.jCallback[i]['newFunc'](); // run callback.
}, // end run
remove: function (whichID) {
var that = this;
console.log('removing:' + whichID);
for(i=0;i <= that.jCallback.length - 1;i++) // go through callback list
if( that.jCallback[i]['id'] == whichID )
that.jCallback[i]['newFunc'](); // run callback.
} // end remove
}
// add the object to the dummy object...
myDummyObject.prototype.cb = cb;
Example:
var testing = new myDummyObject();
testing.cb.add('doSay', function () { console.log('test: 213123123'); } );
// test remove...
var testid = testing.cb.add('doSay', function () { console.log('test: 12sad31'); } );
testing.cb.remove(testid);
testing.cb.add('doSay', function () { console.log('test: asdascccc'); } );
testing.cb.add('doSay', function () { console.log('test: qweqwe'); } );
testing.cb.add('doSay', function () { console.log('test: d121d21'); } );
testing.cb.add('doSay', function () { console.log('test: wwww'); } );
testing.say();
This always seemed the easiest for me to understand... Just create a new instance of the inherited class and then loop through its variables and methods and add them to the main one.
var myPerson = new Person()
var myPerson.firstName = 'john';
var myPerson.lastName = 'smith';
var myPerson.jobTitle = 'Programmer';
var Person = function(){
//Use this to inherit classes
this._extendedClass = new Person_Job();
for(var i in this._extendedClass){
this[i] = this._extendedClass[i];
}
delete this._extendedClass;
this.firstName = '';
this.lastName = '';
}
var Person_Job = function() {
this.jobTitle = '';
}

Categories

Resources