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?
I usually settle with returning an object with functions as properties:
You can have inheritance by calling the newCat function and extend the object you get:
If you want a global cats object:
Now you can call:
Variation 1 - Mixin
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
obj instanceof SomeType
will return trueCons
private
, notprotected
, subtypes can't access themInheritance
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
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
Cons
Inheritance
You can inherit a object prototyping it.
If you are on a old browser you will need to garantee
Object.create
works:To know if a object is a prototype of another you can use
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.
You can re-assign the prototype insteadd of adding each method if you are not inheriting and remember to re-assign the constructor property:
Or use _.extend or $.extend if you have underscore or jquery in your page
The
new
keyword under the hood simply does this:What you have is a function than has no methods; it just has a
prototype
property with a list of functions, thenew
operator means to create a new object and use this function's prototype (Object.create
) andconstructor
property as initializer.Pros
Cons
Inheritance
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
andchild instanceof SomeType
will return bothtrue
Curiosity: Under the hood
instanceof
operator does isVariation 4 - Overwrite
__proto__
When you do
Object.create(obj)
under the hood it doesThe
__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
Cons
__proto__
key can change the object's prototypeInheritance
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:So when we do
SomeType.call(this)
we are passing the objectthis
to functionSomeCall
, as you remember this function will add methods to objectthis
.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.It's not a best practice because not everybody knows about it, but sometimes it helps. But if you reassign the prototype...
A.prototype
is a new object, a instance ofObject
than prototypesObject.prototype
andObject.prototype.constructor
isObject
. Confusing, right? :PSo if you overwrite the prototype and don't reset the "constructor" property, it will refer to
Object
instead ofA
, and if you try to use the "constructor" property to access some static method you may get crazy.