In my ongoing saga to understand more about Object Oriented Javascript - I came across a question about creating a class to respond to the following API:
var foo = new bar().delay(750).start().then(onComplete);
var bar = function() {
this.delay(function(per) {
//...
};
}
Can someone with more experience than me please describe how to create class that would respond to this? I have never seen chaining like this and can't find any information online :(
This chaining is accomplished by returning this in your functions :
this.delay = function(per) {
//...
return this;
};
If you want to stick to first line code, then your constructor should be named bar :
var bar = function() {
this.delay = function(per) {
//...
return this;
};
this.start = function() {
...
return this;
};
}
See demonstration (open the console)
The secret to method chaining is to return this from each method that you want to be able to chain with. That allows the next method to be this.method() automatically. Your definition of the bar object would look something like this shell:
function bar() {
// bar initialization code here
}
bar.prototype = {
delay: function(amt) {
// delay code here
return(this);
},
start: function() {
// start code here
return(this);
},
then: function(fn) {
// then code here
fn();
return(this);
}
};
var foo = new bar().delay(750).start().then(onComplete);
In your example, new bar() is executed and it returns a pointer to the new bar object.
Using that new object pointer, the .delay(750) method is called on that object. That method then also returns the object so the .start() method is called on the return value from .delay(750) which is still the same object and so on...
Related
I have a class-like function
var myapp = function() {
this.method = function() {
//Do something...
}
}
To reference myapp from within methods, the first line in the myapp function is
var self = this;
So a method in myapp can reference the "class" safely
this.anothermethod = function() {
self.method();
}
The full code:
var myapp = function() {
var self = this;
this.dosomething = function(Callback) {
Callback();
}
this.anothermethod = function() {
//Pass a callback ("self" is required here)...
this.dosomething(function() {
self.complete();
)};
}
this.complete = function() {
console.log('All done!');
}
}
My question is: can I assign var self = this; from outside the declaration of myapp? I don't want to set self every single time I write a "class".
Kind of like this:
var library = function() {
this.loadclass = function(Name) {
var tempclass = window[Name];
library[Name] = new tempclass();
library[Name].self = library[Name];
}
}
var myapp = new library();
myapp.loadclass('myapp');
myapp.myapp.dosomething();
It doesn't work as expected. self equals window for some reason.
I know it's a little abnormal programming, but can it be done?
Note about using self: I remember why I started using it. I wanted to reference the base class (this) from within callbacks inside methods. As soon as you try to use this within a function within a method, it then references the method, not the base class.
Unless you are detaching the methods from the object and calling them as plain functions, you don't need a self variable at all. The method can reach its object using the this keyword:
var myapp = function() {
this.method = function() {
//Do something...
}
this.anothermethod = function() {
this.method();
}
}
No, you can't really; not the way you're creating objects at least.
You can sort of do this, by enumerating all the functions on the object and binding them to the object itself. Something like this:
Object.keys(obj)
.filter(function(n) { return typeof obj[n] == "function" })
.forEach(function(n) { obj[n] = obj[n].bind(obj) })
This function will go over the public, enumerable properties of obj and make sure that any functions on it are bound to obj; i.e. this is now bound to obj.
A primer on this
When you call new, this within the constructor gets bound to the newly created object. If you do need a reference to this as it was bound at constructor time, you do need to keep away a reference to it.
Functions in JavaScript are bound to wherever it is called. Here's an example:
var foo = new function() {
this.bar = function() {
return 'bar'
}
this.baz = function() {
return this.bar()
}
}
console.log(foo.bar()) // bar
console.log(foo.baz()) // bar
var bar = function() {
return "window"
}
var baz = foo.baz
console.log(baz()) // window
When we call foo.baz() it'll look to foo for the implementation of bar, but when calling foo.baz through a "detached" reference, it'll look to whatever the global object is (in this case the browser window object) and call bar from there. Because we defined bar in the global context, it then returns window.
The practice of assign a variable called self is so that it doesn't matter how you call your methods, because you always reference the this at the time of creation through the self variable. You don't have to write things this way, but then you should understand that references to this may change under your feet.
I thought I understood the javascript prototype object and how to use it, but now I've run into something that has me a little stumped. When trying to run the code below mpo.testFire() fires with no issues, but I get the error Uncaught TypeError: Object # has no method 'fireAlert' when trying to invoke mpo.fireAlert() which I thought was part of the prototype:
<body>
Click Me
</body>
// Click handler, create new object
// call parent method and prototype method
$("#testBtn").click(function(e) {
e.preventDefault();
var mpo = new Myobject();
mpo.testFire();
mpo.fireAlert();
});
Myobject = function () {
var testFire = function () {
alert('testFire');
};
return {
testFire:testFire
};
};
Myobject.prototype = function() {
var fireAlert = function() {
alert('made it to fireAlert');
};
return {
fireAlert:fireAlert
};
}();
If I change the code and move everything to the object's prototype like the code below everything works as expected:
$("#testBtn").click(function(e) {
e.preventDefault();
var mpo = new Myobject();
mpo.testFire();
mpo.fireAlert();
});
Myobject = function () {
// constructor logic here maybe?
};
Myobject.prototype = function() {
var fireAlert = function() {
alert('made it to fireAlert');
};
var testFire = function () {
alert('testFire');
};
return {
fireAlert:fireAlert,
testFire:testFire
};
}();
I'm guessing there is a scope issue since in the first example I return an interface from the parent object. Can anyone explain why the first example does not work?
You are returning an object literal from your first implementation of MyObject constructor which knows nothing of the prototype chain MyObject is part of. In the second implementation the empty constructor returns the new context that was created which is in fact a MyObject object which knows about the appropriate prototype chain
You're returning an object literal
return {
testFire:testFire
};
which "overrides" the result from new (because it's an object. Returning, for example, a string literal would return the created object).
This is in ES5 spec 13.2.2.
I'm fairly certain this isn't possible, but wanted to see if anyone had some ingenious ideas as to how to make it possible.
I want the following code to work:
var x = new foo();
x.a.getThis() === x; // true
In other words, I want x.a.getThis to have a reference to this being x in this case. Make sense?
In order to get this to work one level deep is simple:
function foo(){}
foo.prototype.getThis = function(){ return this; }
var x = new foo();
x.getThis() === x; // true
One thing, I want this to work as a prototype, no "cheating" by manually binding to this:
function foo(){
this.a = {
getThis : (function(){ return this; }).bind(this)
};
}
Although the above is a perfect functional example of what I'm trying to achieve, I just don't want all the extra functions for each instance :)
FYI, the actual use case here is that I'm creating classes to represent Cassandra objects in node and I want to be able to reference a super-column --> column-family --> column via foo.a.b and keep a reference to foo in the deep function.
You can't do this without a forced bind of some kind. You say you don't want to "cheat" but this breaks the standard rules about what this is, so you have to cheat. But JS lets you cheat, so it's all good.
BTW, for what it's worth coffee script makes this so trivial.
foo = ->
#a = getThis: => this
The fat arrow => preserves the context of this for from the scope it was called in. This allows you to easily forward the context to another level.
That code gets compiled to this JS:
var foo;
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
foo = function() {
return this.a = {
getThis: __bind(function() {
return this;
}, this)
};
};
Which basically just does what you say you do not want to do.
Or if the value doesn't have to this specifically, you can set the "owner" in the child object.
var A = function(owner) {
this.owner = owner;
};
A.prototype.getThis = function() {
return this.owner;
};
var Foo = function() {
this.a = new A(this);
};
var foo = new Foo();
if (foo.a.getThis() === foo) {
alert('Happy dance');
} else {
window.location = 'https://commons.lbl.gov/download/attachments/73468687/sadpanda.png';
}
http://jsfiddle.net/4GQPa/
And the coffee script version of that because I am a passionate and unreasonable zealot for it:
class A
constructor: (#owner) ->
getThis: -> #owner
class Foo
constructor: -> #a = new A(this)
foo = new Foo()
if foo.a.getThis() is foo
alert 'Happy Dance'
else
window.location = 'https://commons.lbl.gov/download/attachments/73468687/sadpanda.png'
Impossible to do reliably without binding the value at the start since the value of a function's this is set by the call. You can't know beforehand how it will be called, or which functions need a special or restricted call to "preserve" the this -> this relationship.
The function or caller's this may be any object, there may not be a this -> this at all. Consider:
var x = {
a : {
b: function() {return this;}
}
}
When you call x.a.b(), then b's this is a. But if you do:
var c = x.a.b;
c(); // *this* is the global object
or
x.a.b.call(someOtherObject);
What is the value of this -> this in these cases?
Answering my own question because someone else may find it useful. Not sure if I'll end up going with this or Squeegy's solution. The functions are only ever defined once and then the containing object is cloned and has parent = this injected into it:
function foo(){
var self = this, nest = this.__nestedObjects__ || [];
nest.forEach(function(prop){
self[prop] = extend({ parent : self }, self[prop]);
});
}
// bound like this so that they're immutable
Object.defineProperties(foo.prototype, {
bar : {
enumerable : true,
value : {
foobar : function(){
return this.parent;
},
foo : function(){},
bar : function(){}
}
},
__nestedObjects__ : { value : ['bar'] }
});
var fooInst = new foo();
console.log(fooInst.bar.foobar() == fooInst);
or based on Squeegy's solution:
function foo(){
for(var cls in this.__inherit__){
if(!this.__inherit__.hasOwnProperty(cls)){ continue; }
this[cls] = new (this.__inherit__[cls])(this);
}
}
var clsA;
// bound like this so that they're immutable
Object.defineProperties(foo.prototype, {
__inherit__ : { value : {
bar : clsA = function(parent){
Object.defineProperty(this, '__parent__', { value : parent });
}
}
}
});
clsA.prototype = {
foobar : function(){
return this.__parent__;
}
};
var fooInst = new foo();
console.log(fooInst.bar.foobar() == fooInst);
i have JavaScript components, that has following architecture:
var MyComponent = function(params)
{
setup(params);
this.doSomething()
{
// doing something
};
function setup(params)
{
// Setup
// Interaction logic
var _this = this; // "this" points to DOMWindow, not to created object
$(".some-element").click(function(){
_this.doSomething(); // it craches here, because of above
});
}
};
When something, being controlled by interaction logic, happens, sometimes i must forward execution to "public" methods of component.
In this situation, i have a problem with "this" pointer.
Sample code demonstrates it:
var Item = function()
{
this.say = function()
{
alert("hello");
};
this.sayInternal = function()
{
_sayInternal();
};
function _sayInternal()
{
this.say();
};
};
To test it,
Create an object:
var o = new Item();
This works fine:
o.say(); // alerts "hello"
This crashes:
o.sayInternal();
I get an error:
TypeError: Result of expression 'this.say' [undefined] is not a function.
I think, such a behaviour takes place, because _sayInternal() function is declared (and not assigned to object, like "this.say = function()"). This way, it is shared across all created objects and acts like a static function in C++.
Is this true ?
No, sayInternal is not shared between created objects. But you are right, the created objects don't have access to sayInternal as it is not assigned to them. This function is only local to the constructor function.
this always refers to the context a function is invoked in. If you call it like func(), then this refers to the global object (which is window in browser). If you set the function as property of an object and call it with obj.func(), then this will refer to obj.
If you assign a "bound" function to a variable and call it:
var method = obj.func;
method();
then this will again refer to the global object. In JavaScript, functions are like any other value, they don't have a special relationship to the object they are assigned to.
You can explicitly set the context with call or apply:
var MyComponent = function(params)
{
setup.call(this, params); // <- using `call`
this.doSomething()
{
// doing something
};
function setup(params)
{
// Setup
// Interaction logic
var _this = this; // "this" to new created object
$(".some-element").click(function(){
_this.doSomething();
});
}
};
or in you other example:
var Item = function()
{
this.say = function()
{
alert("hello");
};
this.sayInternal = function()
{
_sayInternal.call(this);
};
function _sayInternal()
{
this.say();
};
};
That said, this approach to assign functions to objects is not good, because every instance will have its own this.sayInternal function. So for the Item code above, every creation of an instance involves creating three functions too, which is a waste of memory.
Making use of prototype inheritance would be a better way:
var Item = function() {
};
Item.prototype = (function() {
function _sayInternal() {
this.say();
};
return {
say: function() {
alert("hello");
},
sayInternal: function(){
_sayInternal.call(this);
}
}
}());
This way, _sayInternal is only created once and all instances inherit (refer to) the prototype, so say and sayInternal also exist only once. The "trick" with the immediate function makes _sayInternal only accessible by say and sayInternal.
I have the following code example to use an object that receives the action from the callback. Doesn't seem like this is a good design pattern. Or is it?
When setTimeOut() fires on the function after 1 second, it uses the objInstance global variable (DOM scope) to access the ClassExample object instance. Can someone recommend a better way to utilize callbacks within an object oriented design?
The whole idea is so I can use the callback to update data within my object instance (increment a variable for example).
function ClassExample{
this.initiate = function() {
setTimeOut(objInstance.afterTimeOut,1000); //using the objects global handle
}
this.afterTimeOut = function() {
alert("Received!");
}
}
var objInstance = new ClassExample(); //instance
objInstance.initiate();
No, you're not. You'll want to do this:
this.initiate = function() {
setTimeOut(objInstance.afterTimeOut,1000); //using the objects global handle
}
Now, if "afterTimeout" needs the proper object context, you could do this:
this.initiate = function() {
var instance = this;
setTimeout(function() { instance.afterTimeOut(); }, 1000);
}
OK well you changed the question considerably with that little edit :-) If I were you, I'd just do this (like my original second example):
this.initiate = function() {
var instance = this;
setTimeout(function() { instance.afterTimeOut(); }, 1000);
}
Then you don't need any ugly global variables around at all.
edit — Stackoverflow user #Christoph comments that this isn't particularly pretty. One thing that might help would be to use a "bind" facility, as provided by newer browsers natively (as a method on the Function prototype) or by some libraries (Prototype or Functional for example). What "bind" lets you do is create a little wrapper function like I've got above:
this.initiate = function() {
setTimeout(this.afterTimeOut.bind(this), 1000);
}
That call to "bind" returns a function that is effectively the same sort of thing as the little wrapper I coded explicitly in the example.
function ClassExample{
this.afterTimeOut = function() {
alert("Received!");
}; // Don't forget these
setTimeOut(afterTimeOut, 1000); // Don't use () if you're passing the function as an argument
}
var objInstance = new ClassExample(); //instance
That way you don't need the initiate() method.
If you really want the initiate() method, I'd do it like this:
function ClassExample{
var self = this;
self.afterTimeOut = function() {
alert("Received!");
};
self.initiate = function() {
setTimeOut(self.afterTimeOut, 1000);
};
}
var objInstance = new ClassExample(); //instance
objInstance.initiate();
This is how I'd do it to allow timer reuse and minimize the number of closures:
function Timer(timeout, callback) {
this.timeout = timeout;
this.callback = callback;
}
Timer.prototype.run = function(thisArg /*, args... */) {
var argArray = Array.prototype.slice.call(arguments, 1);
var timer = this;
setTimeout(function() {
timer.callback.apply(thisArg, argArray);
}, timer.timeout);
};
var timer = new Timer(1000, alert);
timer.run(null, 'timer fired!');
And just for fun, a golfed version which is functionally equivalent, but replaces the object with a closure:
function delay(func, timeout) {
return function() {
var self = this, args = arguments;
setTimeout(function() { func.apply(self, args); }, timeout);
};
}
delay(alert, 1000).call(null, 'timer fired!');
You are right it is not the optimal way of doing what you are aiming for. however i have to wonder why you need to break the callstack as part of the initiation, it seems very academic.
apart from that if i had to do that, i'd probably use a closure like so:
function ClassExample{
this.initiate = function() {
setTimeOut((function(self) { return function() { self.afterTimeout();}})(this),1000); //using the objects global handle
}
this.afterTimeOut = function() {
alert("Received!");
}
}
var objInstance = new ClassExample(); //instance
objInstance.initiate()
this.initiate = function() {
var instance = this;
setTimeOut(function() {
instance.afterTimeOut();
}, 1000);
};
By saving this to a local variable, you can avoid using the global handle at all. Also this prevent the afterTimeout() from losing it's this.
Building on Znarkus answer...
I really don't know in which environment his code is running but for me the first approach just do not works. I got: 'ReferenceError: afterTimeOut is not defined'...
The second one, nevertheless, is really cool... I just changed setTimeOut for setTimeout (using lowercase 'o') and included parenthesis after the class name definition turning the first line of code into 'function ClassExample(){'; solved my problem.
My snippet of example code:
Oop with private behaviour, intern callback calling and etc.
function MyTry (name){
// keep this object pointer... that's the trick!
var self = this;
// create private variable
var d = new Date()toJSON().slice(0, 10);
// create a private function
function getName(){return name}
// create public access method
self.hello = function(){alert('Hello '+getName()+'!\nToday is: '+d)}
// note instance method hello passed as a callback function!
self.initiate = function(){setTimeout(self.hello, 3000)}
}