Initialize Mootools class with parameters from array - javascript

I have a Mootools class:
var Foo = new Class({
initialize: function(param1, param2) {
// do stuff
}
});
The values to initialize Foo with are in an array:
a = ['value1', 'value2'];
How can I use the values from a to initialize an instance of Foo?

I'd go with extending the proto of the class so it does not care (see Felix' answer).
var Foo = new Class({
initialize: function(param1, param2) {
console.log(param1, param2);
}
});
(function(){
var oldFoo = Foo.prototype.initialize;
Foo.implement({
initialize: function(){
var args = typeOf(arguments[0]) == 'array' ? arguments[0] : arguments;
return oldFoo.apply(this, args);
}
});
}());
new Foo(['one', 'two']); // one two
new Foo('three', 'four'); // three four
It involves less hacking and is probably easier to understand/maintain than creating special constructor abstractions.
if you can, you can even do
var Foo2 = new Class({
Extends: Foo,
initialize: function () {
var args = typeOf(arguments[0]) == 'array' ? arguments[0] : arguments;
this.parent.apply(this, args);
}
});
new Foo2(['one', 'two']);
new Foo2('three', 'four');
Thus, making a very clear abstraction without modifying the parent proto and expectation - and keeping pesky SOLID principles assholes happy :D

There is no direct way of calling a constructor with an array of arguments to be expanded, like you do it with Function.apply.
If you create a new instance of your class with new Foo(), MooTools calls the constructor (initialize) implicitly passing it the arguments you called Foo() with. However, initialize is still present as a method of the instance, so you could simply call it "again" like so:
var myFoo = new Foo();
myFoo.initialize.apply(myFoo, ['value1', 'value2']);
But this is really bad practice, because a constructor is normally not meant to be called twice and chances are that you run into problems.
Another way is to create the instance without letting MooTools call the constructor. First you need a plain instance and then call initialize as a method of the instance. This is rather hackish, but could be realized like this:
var Foo = new Class({
initialize: function(param1, param2) {
this.param1 = param1;
this.param2 = param2;
},
getParams: function() {
console.log(this.param1 + ', ' + this.param2);
}
});
Class.createInstance = function(klass, args) {
klass.$prototyping = true;
var inst = new klass();
klass.$prototyping = false;
inst.initialize.apply(inst, args);
return inst;
}
var myFoo = Class.createInstance(Foo, ['a', 'b']);
// returns "a, b"
myFoo.getParams();
$prototyping is the switch for MooTools to not call the constructor.

Related

Mass create methods for an object

I know that a new method for an object can be declare like so:
var MyObject = function() {return new MyObject.prototype};
MyObject.prototype.exists = function() {alert("The object exists.")};
How can I create many methods as a bunch for MyObject instead of one by one?
I have tried:
MyObject.prototype = {
exists: function() {alert("The object exists.")},
isBorn: function() {alert("The object is born.")},
isDead: function() {alert("The object has left our world.")}
}
Calling MyObject.exists() returns: Uncaught TypeError: MyObject.exists is not a function
What I am trying to do:
I am trying to do something like jQuery does.
jQuery is defined like so:
jQuery = function(selector, context) {included)
return new jQuery.fn.init(selector, context);
}
We don't say var j = new jQuery; when we call it like jQuery("#foo").
Then the files says:
jQuery.fn = jQuery.prototype = {
jquery: version,
constructor: jQuery,
length: 0,
toArray: function() {
return slice.call( this );
}
...
}
Isn't toArray() a method of the jQuery object? Why doesn't it show the same error when I call it.
When the jQuery function is called, you're not creating an instance of jQuery which is why you don't use the new keyword. Instead, you're returning an instance of jQuery.fn.init.
Follow it down and you'll see that the prototype of init being declared:
init.prototype = jQuery.fn;
And the definition for jQuery.fn is:
jQuery.fn = jQuery.prototype = { ... };
Which means that (new jQuery.fn.init(selector, context)) has all the methods from jQuery.prototype.
So, toArray is not a method of the jQuery object, but rather a method on the prototype of the return value from calling jQuery().
You can achieve the same thing in fewer steps by manually assigning the prototype of the return value.
function MyObject() {
var obj = {};
return Object.setPrototypeOf(obj, MyObject.prototype);
}
MyObject.prototype.toArray = function() {};
MyObject().toArray();
You were very close, you just have to create a new instance of the object for it to inherit from its own prototype chain.
var myObj = function () {};
myObj.prototype = {
a: function () { console.log(1) },
b: function () { console.log(2) },
c: function () { console.log(3) }
};
var myObject = new myObj();
myObject.a(); // 1
myObject.b(); // 2
myObject.c(); // 3
The first one is still better because prototype objects have predefined properties (currently only constructor, but later the standard can be extended), and totally overwriting the prototype object will effectively remove those properties. But still it can be shortened like:
function Foo() {}
const p = Foo.prototype;
console.log(Object.getOwnPropertyNames(p));
p.exists = function() { console.log("exists"); };
p.isBorn = function() { console.log("isBorn"); };
(new Foo).exists();
But hey, it's 2016! We have javascript classes in most major browsers (check compatibility at MDN)!
class Foo {
exists() { console.log("exists"); }
isBorn() { console.log("isBorn"); }
}
(new Foo).exists();

javascript prototype overriding a method calls the base method

I have three objects extending each other. Base - > A -> childA. They all have a method test in the prototype. When I call A.test or childA.test the Base.test is called. I wonder what are the options each object to call its own method. Here is the code:
$(document).ready(function(){
function Base(){
};
Base.prototype.test = function(){
console.log("base");
};
function A(){
};
A.prototype.test = function(){
console.log("A");
};
function ChildA(){
};
ChildA.prototype.test = function(){
console.log("ChildA");
};
var base = new Base();
var a = new A();
var childA = new ChildA();
$.extend( a, base );
$.extend( childA, a );
a.test();
childA.test();
}
);
and fiddle: http://jsfiddle.net/pjWjy/84/
So when I call base.test - > log base; a.test -> log a; childA -> log childA;
That's not really how you do prototypical inheritance with constructor functions in JavaScript (it's not inheritance at all, just copying methods between instances). With any of the standard inheritance patterns, you'd be getting the right test.
Here's an example:
// On old browsers like IE8, we need to shim Object.create
if (!Object.create) {
Object.create = function(proto, props) {
if (typeof props !== "undefined") {
throw "The second argument of Object.create cannot be polyfilled";
}
function ctor() { }
ctor.prototype = proto;
return new ctor();
};
}
// Define our Base constructor
function Base() {
}
// Define Base#test
Base.prototype.test = function() {
snippet.log("Base#test");
};
// Derive A from Base
function A() {
Base.call(this);
}
A.prototype = Object.create(Base.prototype);
A.prototype.constructor = A;
// Define A#test
A.prototype.test = function() {
snippet.log("A#test");
};
// Derive ChildA from A
function ChildA() {
A.call(this);
}
ChildA.prototype = Object.create(A.prototype);
ChildA.prototype.constructor = ChildA;
// Define ChildA#test
ChildA.prototype.test = function() {
snippet.log("ChildA#test");
};
// Run
var b = new Base();
b.test();
var a = new A();
a.test();
var ca = new ChildA();
ca.test();
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
If you're going to be doing a lot of inheritance like this with constructor functions, you might be interested in my helper script Lineage, which makes things more concise and well-contained, and simplifies "supercalls" (chaining to the parent's version of a method). But of course, that script will be outdated soon by ES6's class feature.

Javascript prototype on properties

I'd like to have an object with multiple levels of methods and properties. The top level will have properties and methods. Some of these properties will then act as name-spaces for second level methods and properties.
e.g.
//first level methods
base.doStuff();
base.doMore();
//second level methods
base.level2.doStuff();
Doing the first level is straight forward:
function Base(foo) {
this.foo = foo;
}
Base.prototype.doStuff = function () {
console.log(this.foo);
}
Base.prototype.doMore = function () {
console.log(this.foo);
}
base = new Base("bar");
base.doStuff();
Is it possible to get a second level, where in the function expression the "this" keyword points back to the Base constructor?
It's much easier to do this without prototypes:
function Base() {
var base = this;
base.level2 = {
moreStuff: function() {
// use "base" instead of "this" here
}
};
}
This can be combined with either prototypical methods, as in your example, or methods defined directly on base in the constructor. The downside of this is that you are creating the method functions every time you instantiate a new object, so you miss some of the shared-prototype goodness of standard prototypical methods.
You could create a new prototype-based object to be your level2:
function Level2() {}
Level2.prototype.moreStuff = function() {
// do stuff
}
function Base() {
this.level2 = new Level2();
}
But the methods of base.level2 won't be bound to base unless you bind them explicitly. Various libraries have bind support (e.g. Underscore's _.bind), or you can do it in plain JS:
function Base() {
var base = this;
base.level2 = new Level2();
base.level2.moreStuff = function() {
return Level2.prototype.moreStuff.apply(base, arguments);
}
}
You could further simplify here, but you're always going to have to make new methods bound in one way or another, because JS is never going to assign this in base.level2.moreStuff() to base without explicit binding - so in most cases the first option is the easiest and cleanest.
But really, is it worthwhile just for namespacing? If there's no functional value, it's a lot harder than simply calling your methods level2MoreStuff(), etc.
Well,
base.doStuff();
is calling doStuff in context of base. It is the same as
base.doStuff.call(base);
You can call and apply any function, for overriding this:
var base = new Base();
var someFun = function () {
console.log (this === base); // true
};
someFun.call(base);
Further anonymous example:
var anObj = {
method0: function () {
console.log (this === anObj); // true
}
};
anObj.method1 = function () {
console.log (this === anObj); // true
};
anObj.method0();
anObj.method1();
So the "second level" points this to level2, not to the "first level" object.
This is a really bad idea, but here goes:
function Base() {
this.name = 'Base';
this.level2 = new Level2(this);
}
Base.prototype.whatsMyName = function(){
alert(this.name);
};
function Level2(base) {
this.name='Level2';
for(var func in Level2.prototype) {
this[func] = Level2.prototype[func].bind(base);
}
}
Level2.prototype.whatsMyName = function(){
alert(this.name);
};
var b = new Base();
b.whatsMyName(); //Base
b.level2.whatsMyName(); //Also Base
You can see it running here: http://jsfiddle.net/zLFgd/1/

Pattern needed: create new object that returns an executeable function and inherits from a prototype

Scenario 1 - everything works:
var AwesomeObject = function()
{
var self = this;
self.whatstuff = 'really awesome';
}
AwesomeObject.prototype.doStuff = function()
{
var self = this;
console.log('i did '+self.whatstuff+' stuff');
return self;
}
var awesome = new AwesomeObject(); //returns a new AwesomeObject
awesome.doStuff(); // prints 'i did really awesome stuff' on the console
Now i want it even awesomer:
var AwesomeObject = function()
{
var f = function() { console.log('i am awesome'); }
var self = f;
self.whatstuff = 'really awesome';
return self;
}
AwesomeObject.prototype.doStuff = function()
{
var self = this;
console.log('i did '+self.whatstuff+' stuff');
return self;
}
var awesome = new AwesomeObject(); //returns the interal f object
awesome(); // prints 'i am awesome'
awesome.doStuff(); // throws an error
new AwesomeObject should return an executable function itself, so that i can say 'awesome();'
but i want it to inherit the AwesomeObject.prototype, too.
adding self.prototype = AwesomeObject.prototype; does not help.
var AwesomeObject = function()
{
var f = function() { console.log('i am awesome'); }
var self = f;
self.whatstuff = 'really awesome';
self.prototype = AwesomeObject.prototype;
return self;
}
ok i can copy the AwesomeObject.prototype functions - one after the other - into the scope of f
var AwesomeObject = function()
{
var f = function() { console.log('i am awesome'); }
var self = f;
self.whatstuff = 'really awesome';
self.doStuff = function() { AwesomeObject.prototype.doStuff.apply(self,arguments); }
return self;
}
but i think there must be a better way, a better pattern, what is it?
this issue drives me crazy, help would be really appreciated.
in general: how to create a function object that
can be created with new
returns a function object that can be executed
inherits all properties and methods of a given prototype
?
is there a way?
thx
Franz
A very simple pattern is a factory.
var AwesomeObject = (function() {
var AwesomeObject = function() {
this.whatstuff = 'really awesome';
};
AwesomeObject.prototype.doStuff = function() {
console.log('i did ' + this.whatstuff + ' stuff');
return this;
};
return function() {
var o = new AwesomeObject();
var f = function() { console.log("I am awesome"); };
for (var k in o) {
f[k] = o[k];
}
return f;
};
})();
var foo = AwesomeObject();
foo();
foo.doStuff();
Live Example.
The idea is that you seperate your function and your object into two things. Your object exists in the local scope of your function and the function can use the object.
The object itself inherits completely through the prototype.
The key is do forward all properties/methods of the object onto the function.
This is the cleanest solution.
When a property is resolved the prototype chain is traversed as you probably know.
But if you have an object awesome and try to evaluate awesome.doStuff, then awesome.prototype will never be queried for the property. You can verify this in your example, "doStuff" in awesome => false but "doStuff" in awesome.prototype => true.
So what you're doing is not changing the implicit properties of awesome, you are changing its prototype, meaning any objects created by doing new awesome will have that property. Verification: "doStuff" in new awesome() => true. And this makes sense, since there is no way to distinguish between a constructor or a regular function when using f/awesome.
The procedure when resolving a property p on an object o is roughly as follows:
Check whether p is defined on o
Check whether p is defined on o.__proto__ (usage of __proto__ is non-standard but widely implemented, except for jscript last time i checked and it has now been deprecated in SpiderMonkey)
Check whether p is defined on o.constructor.prototype
Check whether p is defined on o.constructor.prototype.prototype
etc
So one solution would be to simply set o.__proto__ = AwesomeClass.prototype. Think of __proto__ as a hidden intermediary object between an object and its prototype. Each instance receives its own unique __proto__ object. But this is deprecated and non-standard like I said.
We could also set the values in Function.prototype but that would override other Function properties and affect all Function instances. We don't want that.
So what's left? Not much it turns out. There is no way to set the complete prototype of an object while retaining it's inherited prototype. You will need to iterate through your prototype and copy all properties. Fortunately this will allow instanceof to behave as expected when working with chains of constructors, as well as allowing inheritance/overriding of properties properly.
The problem is really that there is no built-in way to copy the properties of an object into another one, and that there is no standard way to change an object's prototype chain ad-hoc (__proto__).
So use __proto__, or iterate through the prototype.
I don't think there is a good way to do this. I would redesign your program to avoid it.
However, here is a bad, platform-dependent solution (works on V8 using non-standard __proto__ property):
var PrototypeToBeInherited = {'inheritedProperty': 'inheritedPropertyValue'};
f = function() {
return "result";
};
f.__proto__ = PrototypeToBeInherited;
f()
=> "result";
f.inheritedProperty
=> "inheritedPropertyValue"
For your requirement that it must be created with "new", just wrap it in function:
F = function() {
return f;
}
var instance = new F();

How to make a JavaScript singleton with a constructor without using return?

I currently know two ways to construct singletons in JavaScript. First:
var singleton = {
publicVariable: "I'm public",
publicMethod: function() {}
};
It is perfect except that it does not have a constructor where I could run initialization code.
Second:
(function() {
var privateVariable = "I'm private";
var privateFunction = function() {}
return {
publicVariable: "I'm public",
publicMethod: function () {}
}
})();
The first version does not have private properties nor does it have a constructor, but it is faster and simpler. The second version is more complex, ugly, but has a constructor and private properties.
I'm not in a need for private properties, I just want to have a constructor. Is there something I am missing or are the two approaches above the only ones I've got?
function Singleton() {
if ( Singleton.instance )
return Singleton.instance;
Singleton.instance = this;
this.prop1 = 5;
this.method = function() {};
}​
Here is my solution with closures:
function Singleton() {
Singleton.getInstance = (function(_this) {
return function() { return _this; };
})(this);
}
Test:
var foo = new Singleton();
var bar = Singleton.getInstance();
foo === bar; // true
If you are just looking for a place to initialise your singleton, how about this?
var singleton = {
'pubvar': null,
'init': function() {
this.pubvar = 'I am public!';
return this;
}
}.init();
console.assert(singleton.pubvar === 'I am public!');
Simple and elegant.
var singleton = new function() { // <<----Notice the new here
//constructorcode....
this.publicproperty ="blabla";
}
This is basically the same as creating a function, then instantly assiging a new instace of it to the variable singleton. Like var singleton = new SingletonObject();
I highly advice against using singletons this way in javscript though because of the execution order is based on where in the file you place the object and not on your own logic.
What about this?
var Singleton = (function() {
var instance;
// this is actual constructor with params
return function(cfg) {
if (typeof instance == 'undefined') {
instance = this;
this.cfg = cfg;
}
return instance;
};
})();
var a = new Singleton('a');
var b = new Singleton('b');
//a === b; <-- true
//a.cfg <-- 'a'
//b.cfg <-- 'a'
I make it an actual Singleton with static functions and no this like so:
class S {
//"constructor"
static init() {
//Note: Since it's a singleton, there's no "this" instance.
//Instead, you store variables directly on the class.
S.myVar = 7;
}
static myOtherFunc() {
alert(S.myVar);
}
}
//Immediately call init() to make it the "constructor".
//Alternatively, you can call init() elsewhere if you'd
//like to initialize it at a particular time.
S.init();
//Later:
S.myOtherFunc();
S.myVar = 10;

Categories