In my JavaScript code I have a lazy instantiation object AAA. I want make new object BBB and inherits from AAA.
How it's make?
standard javascript inheritance may be achieved with prototypes
BBB.prototype = new AAA();
But in this way you can not access parent methods if they are overridden. For this reason I'm using static property superclass e.g.
function AAA() {}
AAA.prototype = {
foo: function() {return 'foo';}
}
function BBB() {}
BBB.superclass = AAA.prototype;
BBB.prototype = {
foo: function() { return BBB.superclass.foo() + "bar";}
}
b = new BBB();
b.foo() //returns foobar
I like to cheat, this will create objects inheriting from a common o. I took the liberty of renaming variables you asked in your question.
var o = {
happy: true,
fun: true,
time: true
}
var AAA = {
happy: false
};
AAA.__proto__ = o;
console.log( 'happy', AAA.happy );
console.log( 'fun', AAA.fun );
Related
I have a scenario, where I need to create objects dynamically.
In my example, an object meta contains the name for the constructor function to be used during initialization Object.create().
At the moment using the following code, I am able to create the objects dynamically but the property name is not defined.
I need that property on the result;
What is wrong in my script? Do you know a better way to achieve the same result?
(function () {
var costructors = {
A: function () {
this.name = 'A';
console.log(this.name);
},
B: function () {
this.name = 'B';
console.log(this.name);
},
C: function () {
this.name = 'C';
console.log(this.name);
}
},
meta = {
A: true,
B: true,
C: true,
},
result = [];
function createObjs() {
Object.keys(meta).forEach(function (type) {
var obj = Object.create(costructors[type].prototype);
result.push(obj);
}.bind(this));
}
createObjs.call(this);
console.log(result);
})();
You haven't defined a prototype for any of the constructors, so you're not creating the name in your instances, since you're creating an object from their prototype, not from their constructor. Try
Object.create(constructors[type])
An alternative without using Object.create would be:
var obj = new costructors[type]();
instead of:
var obj = Object.create(costructors[type].prototype);
Actually, Object.create does not call the constructor function, but only creates a new object from the given prototype. Any member variables can be provided via a property object:
var obj = Object.create(
constructors[type].prototype,
{ 'name' : { value: 'A', writable: true}}
);
I know that in several languages like C++, you can create classes with multiple inheritance (or at least simulate it using interfaces like in Java). In JavaScript, is it possible to define an interface that can be implemented on a class? If so, what would be the best way to approach doing this, ideally incorporating the prototype chain somehow. Would below work, or is there a better way?
function Gizmo() {
console.log('Gizmo constructed');
}
Gizmo.prototype.wamboozle = function () {
console.log('wamboozle');
};
function EventEmitter() {
console.log('EventEmitter constructed');
this.events = {};
}
EventEmitter.prototype.on = function (name, callback) {
this.events[name] ? this.events[name].push(callback) : (this.events[name] = [callback]);
};
EventEmitter.prototype.emit = function (name, event) {
if (this.events[name]) {
this.events[name].forEach(function (callback) {
callback(event);
});
}
};
// set up inheritance and implementation
// maybe this could be a possibility?
Doohickey.prototype = Object.create(Gizmo.prototype);
Object.getOwnPropertyNames(EventEmitter.prototype).forEach(function (member) {
Doohickey.prototype[member] = EventEmitter.prototype[member];
});
function Doohickey() {
console.log('Doohickey constructed');
Gizmo.call(this); // initialize base class
EventEmitter.call(this); // initialize interface
}
Doohickey.prototype.turlywoops = function () {
console.log('turlywoops');
};
var myOwnDoohickey = new Doohickey();
// member function works
myOwnDoohickey.turlywoops();
// inherited member function works
myOwnDoohickey.wamboozle();
// interface member functions work
myOwnDoohickey.on('finagle', function (trick) {
console.log(trick);
});
myOwnDoohickey.emit('finagle', {
hello: 'world!'
});
// both true
console.log(myOwnDoohickey instanceof Doohickey);
console.log(myOwnDoohickey instanceof Gizmo);
// don't mind if this isn't necessarily true, though it would be nice
console.log(myOwnDoohickey instanceof EventEmitter);
Using something like underscore.js, you could create a new object based on two unrelated prototypes and use it as a prototype. In this example, properties/methods defined in obj2 will overwrite any in obj1 in the result object.
function IAmMulti(){
}
IAmMulti.prototype=_.extend(_.clone(Obj1.prototype),_.clone(Obj2.prototype));
Here's an example of that: JavaScript inheritance with _.extend()
You can't inherit more than 1 prototype at any level (you can have a stack of inheritance though), and interfaces have no meaning since javascript is a dynamic language and the entire prototype chain is searched for matching names. There's no notion of accessing an object through an interface.
In JavaScript you can define up to one Object which will be inherited by your Object. That Object's inheritance is also inherited by your object, etc, in a long chain.
function Foo() {
this.fooThisProp = 'tfoo';
}
Foo.prototype = Object.create(null);
Foo.prototype.fooProtoProp = 'pfoo';
function Bar() {
Foo.call(this);
this.barThisProp = 'tbar';
}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.barProtoProp = 'pbar';
function Baz() {
Bar.call(this);
this.bazThisProp = 'tbaz';
}
Baz.prototype = Object.create(Bar.prototype);
Baz.prototype.bazProtoProp = 'pbaz';
var obj = new Baz();
obj; // {barThisProp: "tbar", bazThisProp: "tbaz", fooThisProp: "tfoo"}
obj.bazProtoProp; // "pbaz"
obj.barProtoProp; // "pbar"
obj.fooProtoProp; // "pfoo"
obj instanceof Baz; // true
obj instanceof Bar; // true
obj instanceof Foo; // true
You could always apply a constructor to an Object which isn't an instance so wouldn't inherit from that constructor. Just be careful the constructor doesn't assume the existance of inherited methods etc,
var fizz = {};
Bar.call(fizz);
fizz; // {barThisProp: "tbar", fooThisProp: "tfoo"}
fizz.barProtoProp; // undefined
fizz.fooProtoProp; // undefined
fizz instanceof Bar; // false
fizz instanceof Foo; // false
If you want to write a method wrapper to do things then you can use pretty much any Object in any context
function Buzz() {}
Buzz.prototype = Object.create(null); // Buzz separate from Foo, Bar, Baz
Buzz.prototype.bazLook = function (key) {
return Baz.prototype[key]; // or do something else with the value
}
var buzz = new Buzz();
buzz.bazLook('fooProtoProp'); // "pfoo"
MyGlobalObject;
function TheFunctionICanUseRightAwaySingleForAllInstansesAndWithoutInstanse() {
function() {
alert('NO CONSTRUCTOR WAS CALLED');
}
};
The Long-named function must be callable from MyGlobalObject, which in turn must be available as a global (to window) variable in all times after script was loaded. It should support extensibility in accordance with latest standards.
I'm at architectural dilemma of how to built JS base for an application (almost 100% JS).
We need an object i.e. window.MyObject (like a module, like jQuery) so
It can be created with
VAR1
var MyGlobalObjConstructor = function(){
this.GlobalFunctionInObject = function(){
alert('called with MyGlobalObj.GlobalFunctionInObject()');
}
};
window.MyGlobalObj = new MyGlobalObjConstructor();
Is MyGlobalObj extensible? Can I create child objects, which will inherit current state of MyGlobalObj (extended functions/properties MyGlobalObj.NewFunc e.g.)? What is the main difference between using prototype (VAR3)?
By GlobaldFunction I mean single instance for all initialized/instantiated (possibly instantializable) instances..
Or with
VAR2
var MyGlobalObj = {
GlobalFunctionInObject: function...
GlobalFunctionInObject2: function...
};
MyGlobalObj.GlobalFunctionInObject();
// here I lose all hierarchy elements, no prototype,
// can I use GlobalFunctionInObject2 in GlobalFunctionInObject?
Or with
VAR3
var MyGlobalConstuctor = function(){} // already 'well-formed' object
MyGlobalConstuctor.prototype.GlobalFunctionInObject = function...
};
var MyGlobalObj = new MyGlobalConstuctor();
// so I'm sceptical to NEW, because I have ALREADY wrote my functions
// which I expect to be in memory, single instance of each of them,
// so creating MyObject2,3,4 with NEW MyGC() makes no sense to me.
// DO I REALLY HAVE TO USE "MyGlobalConstuctor.prototype." FOR EACH FUNCTION?!!!!
What's the difference defining MyGlobalObj as a function and as an object (result of func or VAR2)?
OR VAR4?
I see in Chrome Debugger both prototype and __proto__ special fields. I've read that that's OK, but why are they not saved in a single prototype?
So, what is the correct/optimal way to implement window.MyObject, so one could MyObject.MyFunction(); What are the differences (pro/contra) of variants 1 2 and 3?
Variation 1 - Mixin
function SomeType() {
var priv = "I'm private";
this.publ = "I'm public";
this.action = function() {
return priv + this.publ;
};
}
var obj = new SomeType();
With this method you are creating a new object every time you call new SomeType(), creating all its methods and adding all this method to the new object. Every time you create an object.
Pros
It looks like classical inheritance so it's easy to understand to Java-C#-C++-etc people.
It can have private variables per instance since you have one function closure per each object you create
It allows multiple inheritance, also known as Twitter-mixins or functional mixins
obj instanceof SomeType will return true
Cons
It consumes more memory as more objects you create because with each object you are creating a new closure and creating each of it's methods again.
Private properties are private, not protected, subtypes can't access them
No easy way to know if a object has some Type as superclass.
Inheritance
function SubType() {
SomeType.call(this);
this.newMethod = function() {
// can't access priv
return this.publ;
};
}
var child = new SubType();
child instanceof SomeType will return false there is no other way to know if child has SomeType methods than look if it has them one by one.
Variation 2 - Object literal with prototyping
var obj = {
publ: "I'm public",
_convention: "I'm public too, but please don't touch me!",
someMethod: function() {
return this.publ + this._convention;
}
};
In this case you are creating a single object. If you are going to need only one instance of this type it can be the best solution.
Pros
It's quick and easy to understand.
Performant
Cons
No privacy, every property is public.
Inheritance
You can inherit a object prototyping it.
var child = Object.create(obj);
child.otherMethod = function() {
return this._convention + this.publ;
};
If you are on a old browser you will need to garantee Object.create works:
if (!Object.create) {
Object.create = function(obj) {
function tmp() { }
tmp.prototype = obj;
return new tmp;
};
}
To know if a object is a prototype of another you can use
obj.isPrototypeOf(child); // true
Variation 3 - Constructor pattern
UPDATE: This is the pattern ES6 classes are sugar syntax of. If you use ES6 classes you are following this pattern under the hood.
class SomeType {
constructor() {
// REALLY important to declare every non-function property here
this.publ = "I'm public";
this._convention = "I'm public too, but please don't touch me!";
}
someMethod() {
return this.publ + this._convention;
}
}
class SubType extends SomeType {
constructor() {
super(/* parent constructor parameters here */);
this.otherValue = 'Hi';
}
otherMethod() {
return this._convention + this.publ + this.otherValue;
}
}
function SomeType() {
// REALLY important to declare every non-function property here
this.publ = "I'm public";
this._convention = "I'm public too, but please don't touch me!";
}
SomeType.prototype.someMethod = function() {
return this.publ + this._convention;
};
var obj = new SomeType();
You can re-assign the prototype insteadd of adding each method if you are not inheriting and remember to re-assign the constructor property:
SomeType.prototype = {
constructor: SomeType,
someMethod = function() {
return this.publ + this._convention;
}
};
Or use _.extend or $.extend if you have underscore or jquery in your page
_.extend(SomeType.prototype, {
someMethod = function() {
return this.publ + this._convention;
}
};
The new keyword under the hood simply does this:
function doNew(Constructor) {
var instance = Object.create(Constructor.prototype);
instance.constructor();
return instance;
}
var obj = doNew(SomeType);
What you have is a function than has no methods; it just has a prototype property with a list of functions, the new operator means to create a new object and use this function's prototype (Object.create) and constructor property as initializer.
Pros
Performant
Prototype chain will allow you to know if a object inherits from some type
Cons
Two-step inheritance
Inheritance
function SubType() {
// Step 1, exactly as Variation 1
// This inherits the non-function properties
SomeType.call(this);
this.otherValue = 'Hi';
}
// Step 2, this inherits the methods
SubType.prototype = Object.create(SomeType.prototype);
SubType.prototype.otherMethod = function() {
return this._convention + this.publ + this.otherValue;
};
var child = new SubType();
You may think it looks like a super-set of Variation 2... and you'll be right. It's like variation 2 but with a initializer function (the constructor);
child instanceof SubType and child instanceof SomeType will return both true
Curiosity: Under the hood instanceof operator does is
function isInstanceOf(obj, Type) {
return Type.prototype.isPrototypeOf(obj);
}
Variation 4 - Overwrite __proto__
When you do Object.create(obj) under the hood it does
function fakeCreate(obj) {
var child = {};
child.__proto__ = obj;
return child;
}
var child = fakeCreate(obj);
The __proto__ property modifies directly the object's hidden [Prototype] property. As this can break JavaScript behaviour, it's not standard. And the standard way is preferred (Object.create).
Pros
Quick and performant
Cons
Non-standard
Dangerous; you can't have a hashmap since the __proto__ key can change the object's prototype
Inheritance
var child = { __proto__: obj };
obj.isPrototypeOf(child); // true
Comment questions
1. var1: what happens in SomeType.call(this)? Is 'call' special function?
Oh, yes, functions are objects so they have methods, I will mention three: .call(), .apply() and .bind()
When you use .call() on a function, you can pass one extra argument, the context, the value of this inside the function, for example:
var obj = {
test: function(arg1, arg2) {
console.log(this);
console.log(arg1);
console.log(arg2);
}
};
// These two ways to invoke the function are equivalent
obj.test('hi', 'lol');
// If we call fn('hi', 'lol') it will receive "window" as "this" so we have to use call.
var fn = obj.test;
fn.call(obj, 'hi', 'lol');
So when we do SomeType.call(this) we are passing the object this to function SomeCall, as you remember this function will add methods to object this.
2. var3: With your "REALLY define properties" do you mean if I use them in functions? Is it a convention? Because getting this.newProperty without it being defined at the same level with other member functions is not a problem.
I mean any property your object will have that is not a function must be defined on the constructor, not on the prototype, otherwise you will face one of the more confusing JS problems. You can see it here, but it's outside of the focus of this question.
3. Var3: what happens if I don't re-assign constructor?
Actually you might not see the difference and this is what makes it a dangerous bug. Every function's prototype object has a constructor property so you can access the constructor from an instance.
function A() { }
// When you create a function automatically, JS does this:
// A.prototype = { constructor: A };
A.prototype.someMethod = function() {
console.log(this.constructor === A); // true
this.constructor.staticMethod();
return new this.constructor();
};
A.staticMethod = function() { };
It's not a best practice because not everybody knows about it, but sometimes it helps. But if you reassign the prototype...
A.prototype = {
someMethod = function() {
console.log(this.constructor === A); // false
console.log(this.constructor === Object); // true
this.constructor.staticMethod();
return new this.constructor();
}
};
A.prototype is a new object, a instance of Object than prototypes Object.prototype and Object.prototype.constructor is Object. Confusing, right? :P
So if you overwrite the prototype and don't reset the "constructor" property, it will refer to Object instead of A, and if you try to use the "constructor" property to access some static method you may get crazy.
I usually settle with returning an object with functions as properties:
var newCat = function (name) {
return {name: name, purr: function () {alert(name + ' purrs')}};
};
var myCat = newCat('Felix');
myCat.name; // 'Felix'
myCat.purr(); // alert fires
You can have inheritance by calling the newCat function and extend the object you get:
var newLion = function (name) {
var lion = newCat(name);
lion.roar = function () {
alert(name + ' roar loudly');
}
return lion;
}
If you want a global cats object:
var cats = (function () {
var newCat = function (name) {
return {
name: name,
purr: function () {
alert(name + ' is purring')
}
};
};
return {
newCat: newCat
};
}());
Now you can call:
var mySecondCat = cats.newCat('Alice');
I have two files: BaseClass.js and DerivedClass.js. Contents as below
//---------------------BaseClass.js----------------------------
(function () {
BaseClass= function() { };
BaseClass.prototype.getTestVar = function() {
return 'base test variable';
};
})();
//----------------DerivedClass.js----------------------------
(function () {
DerivedClass= function() { };
DerivedClass.inherits(BaseClass);
DerivedClass.prototype = new BaseClass();
DerivedClass.prototype = {
newvar : 'derived func variable ',
getNewVar : function() { return this.newvar; }
};
})();
In my html file 'test.html' I have the following
var dc = new DerivedClass();
alert(
'The value in newvar of derived class ' + dc.getNewVar() +
' base class variable ' + dc.getTestVar()
);
I get the Javascript error that dc.getTestVar() is not a function.
Any help in solving this is highly appreciated.
At this point:
DerivedClass.prototype = new BaseClass();
DerivedClass.prototype = {
newvar : 'derived func variable ',
getNewVar : function() { return this.newvar; }
};
You're first setting the prototype to the BaseClass, but then overwriting it with a new object. Try this instead:
DerivedClass.prototype = new BaseClass();
DerivedClass.prototype.newvar = 'derived func variable ';
DerivedClass.prototype.getNewVar = function() { return this.newvar; };
Check out these few lines:
DerivedClass.prototype = new BaseClass();
DerivedClass.prototype = {
newvar : 'derived func variable ',
getNewVar : function() { return this.newvar; }
};
First it assigns a new BaseClass as the prototype, but then the next line overwrites that prototype with a fresh object. Perhaps you need to assign DerivedClass.prototype.newvar and DerivedClass.prototype.getNewVar separately — assuming that falls in line with whatever classical inheritance library you're using that provides the inherits method.
That is,
DerivedClass.prototype = new BaseClass();
DerivedClass.prototype.newvar = 'derived func variable';
DerivedClass.prototype.getNewVar = function() { return this.newvar; }
Still, this seems like a mix of classical and prototypal inheritance. Consider reading up on the documentation of that classical inheritance library and see if there's a more consistent way of doing this sort of thing.
For example, if you're using Crockford's classical inheritance (a guess from the inherits keyword), this seems to be his intended way to declare a method:
DerivedClass.method('getNewVar', function () { return this.newvar });
Granted, that's exactly equivalent to what you're already doing, but, if we're gonna use his library, may as well use his style for consistency.
I often use Crockford's prototypal pattern when writing JavaScript programs. I thought I understood all the "gotchas" involved, but I discovered one I didn't think about before. I'd like to know if anyone has a best practice for handling it.
Here's a simple example:
// Here's the parent object
var MyObject = {
registry: {},
flatAttribute: null,
create: function () {
var o, F = function () {};
F.prototype = this;
o = new F();
return o;
}
};
// instance is an empty object that inherits
// from MyObject
var instance = MyObject.create();
// Attributes can be set on instance without modifying MyObject
instance.flatAttribute = "This is going to be applied to the instance";
// registry doesn't exist on instance, but it exists on
// instance.prototype. MyObject's registry attribute gets
// dug up the prototype chain and altered. It's not possible
// to tell that's happening just by examining this line.
instance.registry.newAttribute = "This is going to be applied to the prototype";
// Inspecting the parent object
// prints "null"
console.log(MyObject.flatAttribute);
// prints "This is going to be applied to the prototype"
console.log(MyObject.registry.newAttribute);
I want to feel safe that any changes that appear to be made to the instance don't propagate up the inheritance change. This is not the case when the attribute is an object and I'm setting a nested property.
A solution is to re-initialize all object attributes on the instance. However, one of the stated advantages of using this pattern is removing re-initialization code from the constructor. I'm thinking about cloning all the object attributes of the parent and setting them on the instance within the create() function:
{ create: function () {
var o, a, F = function () {};
F.prototype = this;
o = new F();
for (a in this) {
if (this.hasOwnProperty(a) && typeof this[a] === 'object') {
// obviously deepclone would need to be implemented
o[a] = deepclone(this[a]);
}
}
return o;
} };
Is there a better way?
There is a very simple solution to ensuring that they are instance variables only, which is to use the this keyword in the constructor.
var MyObject = {
flatAttribute: null,
create: function () {
var o, F = function () {
this.registry = {}
};
F.prototype = this;
o = new F();
return o;
}
};
this ensures that all properties of "instance.registry.*" are local to the instance because the lookup order for javascript opjects is as follows.
object -> prototype -> parent prototype ...
so by adding a variable to the instance in the constructor function named "registry" that will always be found first.
another solution, which I think is more elegant is to not use crockford's (java style) constructors and use a layout that reflects javascripts object system more naturally. most of those gotchas are from the misfit between practice and language.
// instance stuff
var F = function () {
this.registry = {}
};
F.prototype = {
// static attributes here
flatAttribute: null,
methodA: function(){
// code here 'this' is instance object
this.att = 'blah';
}
};
var instanceA = new F();
instanceA.registry['A'] = 'hi';
var instanceB = new F();
instanceB.registry['B'] = 'hello';
instanceA.registry.A == 'hi'; // true
instanceB.registry.B == 'hello'; // true
F.prototype.registry == undefined; // true
Will this give you the expected result? Here I am not using an Object literal, but an instantly instantiated constructor function for the parent object (Base):
var Base = ( function(){
function MyObject(){
this.registry = {},
this.flatAttribute = null;
if (!MyObject.prototype.create)
MyObject.prototype.create = function(){
return new this.constructor();
};
}
return new MyObject;
} )(),
// create 2 instances from Base
instance1 = Base.create(),
instance2 = Base.create();
// assign a property to instance1.registry
instance1.registry.something = 'blabla';
// do the instance properties really belong to the instance?
console.log(instance1.registry.something); //=> 'blabla'
console.log(instance2.registry.something === undefined); //=> true
But it's all a bit virtual. If you don't want to use the new operator (I think that was te whole idea of it), the following offers you a way to do that without the need for a create method :
function Base2(){
if (!(this instanceof Base2)){
return new Base2;
}
this.registry = {},
this.flatAttribute = null;
if (!Base2.prototype.someMethod){
var proto = Base2.prototype;
proto.someMethod = function(){};
//...etc
}
}
//now the following does the same as before:
var instance1 = Base2(),
instance2 = Base2();
// assign a property to instance1.registry
instance1.registry.something = 'blabla';
// do the instance properties really belong to the instance?
console.log(instance1.registry.something); //=> 'blabla'
console.log(instance2.registry.something === undefined); //=> true
Example in a jsfiddle
I always like to keep in mind that object.Create is one option, and not the only way of achieving non-classical inheritance in javascript.
For myself, I always find that Object.create works best when I want to inherit elements from the parent objects prototype chain (i.e. methods that I'd like to be able to apply to the inheriting object).
--
For simple "Own Property" inheritance, Object.create is largely unnecessary. When I want to inherit own properties, i prefer to use the popular Mixin & Extend patterns (which simply copy one object's own properties to another, without worrying about prototype or "new").
In the Stoyan Stefanov book "Javascript Patterns" he gives an example of a deep extend function that does what you're looking for recursively, and includes support for properties that are arrays as well as standard key/value objects:
function extendDeep(parent, child){
var i,
toStr = Object.prototype.toString,
astr = "[object Array]";
child = child || {};
for (i in parent) {
if (parent.hasOwnProperty(i)) {
if (typeof parent[i] === "object") {
child[i] = (toStr.call(parent[i]) === astr) ? [] : {};
extendDeep(parent[i], child[i]);
} else {
child[i] = parent[i];
}
}
}
return child;
}
If you're using jQuery, jQuery.extend() has an optional "deep" argument that lets you extend an object in near-identical fashion.
i think you're using prototypal inheritance to simulate a classic, Object Oriented inheritance.
What are you trying to do is to stop the prototype method lookup which limits its expressiveness, so why using it? You can achieve the same effect by using this functional pattern:
var MyObject = function() {
// Declare here shared vars
var global = "All instances shares me!";
return {
'create': function() {
var flatAttribute;
var register = {};
return {
// Declare here public getters/setters
'register': (function() {
return register;
})(),
'flatAttribute': (function() {
return flatAttribute;
})(),
'global': (function() {
return global;
})()
};
}
};
}();
var instance1 = MyObject.create();
var instance2 = MyObject.create();
instance1.register.newAttr = "This is local to instance1";
instance2.register.newAttr = "This is local to instance2";
// Print local (instance) var
console.log(instance1.register.newAttr);
console.log(instance2.register.newAttr);
// Print global var
console.log(instance1.global);
console.log(instance2.global);
Code on jsFiddle