Accessing 'this' of an object inside promise callback (then) - javascript

I want to create an object in Javascript.
One of the methods should execute a promise chain. Each of the methods in the chain have to access a config variable that is a member of the object.
The problem is, the this operator is changed in PromiseMethod2 and I can't access the config variable (It works correctly in PromiseMethod1).
Here's my code:
var SomeObject(config) {
var that = this;
that.config = config;
}
SomeObject.prototype.SomeMethod = function() {
var that = this;
that.PromiseMethod1()
.then(that.PromiseMethod2)
.catch(console.error);
}
SomeObject.prototype.PromiseMethod1 = function() {
var that = this;
config = that.config;
return SomePromise();
}
SomeObject.prototype.PromiseMethod2 = function(someParams) {
var that = this;
config = that.config;
params = someParams;
return SomePromise();
}
var someObject = new SomeObject(someConfig);
someObject.SomeMethod().then(function () {
console.log('Done!');
}
I want to use the method delegate in the chain instead of just executing:
that.PromiseMethod1().then(function(response) { return that.PromiseMethod2(that, response); };
I can't use the bind method because it looks like it gets rebinded when the callback is executed.
Is there a solution to this?
Why's there a difference between PromiseMethod1 and PromiseMethod2?

My real recommendation is not to use this or new at all (and you can use Object.create if you still want inheritance):
var SomeObject = function(config) {
return {
PromiseMethod1: function(){
return somePromise(config.foo);
},
PromiseMethod2: function(x){
return someOtherPromise(config.bar, x);
}
}
}
var instance = SomeObject({config: true});
instance.PromiseMethod1().then(instance.PromiseMethod2);
Here I'm using closures, and their ability to enclose variables of their parent lexical scope, to my advantage. Rather than relying on JavaScript to magically inject a this into my function at run-time based on which object the function is called on, because as demonstrated by your problem, that doesn't always work.
However, I know that its an unconventional way to work, so if you'd rather stick with this, you'll need to use bind in order to tell JavaScript which magical this-value the function belongs to:
var SomeObject function(config) {
this.config = config;
}
SomeObject.prototype.PromiseMethod1 = function(){
return somePromise(this.config.foo);
}
SomeObject.prototype.PromiseMethod1 = function(x){
return someOtherPromise(this.config.bar, x);
}
var instance = new SomeObject({config: true});
instance.PromiseMethod1().then(instance.PromiseMethod2.bind(instance)); //<- :(
In your example SomeMethod you're not actually using bind. You still need to bind because you're passing the function into .then(f), and the code which receives the function doesn't know anymore which object it should use for the this. Now look at my earlier recommended code again. There are no thisses in there, so those functions don't rely at all on which object they're being called on, you can pass them around as higher-order-functions as much as you want without ever having to bind or that = this. :)

I would say that's impossible. You try to mix 2 different approaches: method chaining and promises chaining. I'd recommend to review your architecture.
The only visible thing (but personally I don't like it) if you have a full control over all promises that you want to use is to pass config values through the whole promises chain.
SomeObject.prototype.init = function() {
var that = this;
return new Promise(function(resolve, reject) {
resolve(that.config)
});
}
SomeObject.prototype.PromiseMethod1 = function(config, params) {
return SomePromise(config, params);
}
SomeObject.prototype.PromiseMethod2 = function(config, someParams) {
return SomePromise(config, someParams);
}
SomePromise = function(config, params) {
return new Promise(function(resolve, reject) {
//some code here
resolve(config, newParamsFromSomeCode)
});
}
Then you'll be able to call:
that.init().then(that.PromiseMethod1).then(that.PromiseMethod2);
But again, it doesn't look like a good code...

Related

A native way of adding custom JavaScript functions into a method-calls chain

I would like to known if there is a native way of doing this :
Object.prototype.chain = function(f) { return f.call(this) }
function fun1() {
doSomethingWithObject(this)
return this
}
function fun2() {
doSomethingElse(this)
return this
}
someObject
.method1('something')
.method2()
.chain(checkSomething() ? fun1 : fun2)
.method3()
But I do not feel like changing the prototype of Object. Is there a way to do this without modifying the prototype of Objects or the other constructors that I use (and am not the developer of)
Edits :
I feel I do not explain very well, so let' add some details :
What I would like to do is to use some APIs I do not define. someObject is defined like the following, with chainable methods :
var someObject = {
method1: function(val) {
// do something
return this
},
method2: function() {
// do something
return this
},
method3: function() {
// do something
return this
}
}
Now imagine I cannot change this code, because this object is from a library, and so I don't want to. Then, imagine that I would like to chain methods and some custom functions (see my first snippet) for many more different objects. The simplest thing to do is to attach a chain method to Object.prototype.
But I think that it could result in conflicts in the future. I am looking for a way to do the same thing without touching the prototype.
I'm surprised there are no answers to this to be honest.
There are many ways to natively introduce chaining. I like to use the revealing module pattern.
So I create a basic model (Go ahead and chuck this in your chrome of firefox console)
var Dog = function(name) {
var self = this;
this.name = name;
var core = {
getName:function(){
return self.name;
}
};
this.movement = function(){ //this function will be exposed including its returned functions for chaining
console.log(self.name + " is getting restless... ");
var jump = function(){
console.log(self.name + " jumps around ");
return this //returns the movement scope
};
var run = function(){
console.log(self.name + " has decided to run");
return this //returns the movement scope
};
return {
jump:jump,
run:run
};
}
console.log("A Pup has been born, we shall call him... " + name);
return{
movement:self.movement //only .movement is exposed to the outside world
};
}
Now create a new dog using var p = new Dog("doggyName");
now, you can chain functions. Try:
p.movement().jump().run().jump().run();
You should get the console logged text that corresponds with each function.
By returning the scope of this after executing your movement function you expose the additional functions that are returned in that scope (see the comments in the code). These can then be chained onto the end of your current function provided they are in the same scope. This allows you to scope specific parts of your code. For example with this dog, all movement is scoped to self.movement, you could have all eating scoped to self.eat and so on
Read up on the revealing module pattern. Though this is not the only way to do it.
The wrapper is something that will wrap any object to make it compatible with "chaining" and will add another chain method that will allow you to plug external functions and still get the chaining.
Check this example:
function myObj() {
this.state = {
a: 1
};
this.method1 = function () {
console.log("1");
}
this.method2 = function () {
console.log("2");
}
this.method3 = function () {
console.log("3");
}
this.method4 = function () {
console.log(this.state);
}
}
function objectChainWrapper(obj) {
this.chain = function (fn) {
fn.call(obj);
return this;
}
for (var prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop] == 'function') {
this[prop] = (function (methodName) {
return function () {
obj[methodName].call(obj);
return this;
}
}(prop))
}
}
}
var obj = new myObj();
var wrapper = new objectChainWrapper(obj);
var chainMethod = function(){ console.log('chain') };
var chainMethodState = function(){ console.log(this.state) };
wrapper.method1().method2().chain(chainMethodState).method3().chain(chainMethod).method4();
JSFIDDLE.
To "plug" an unbound function into the object's method chain you can assign it to a property and call that:
function fn() {
document.write('hi ');
return this;
}
someObj = {
meth1: function() {
document.write('meth1 ');
return this;
},
meth2: function() {
document.write('meth2 ');
return this;
}
}
someObj
.meth1()
[someObj._=fn, '_']()
.meth2()
This doesn't look very pretty if you ask me. A more readable option is to add the chain method on the fly, like:
function chainable(obj) {
obj.chain = function(fn) {
return fn.call(this);
}
return obj;
}
chainable(someObj).meth1().chain(fn).meth2()

How to access an instance variable within a Promise callback?

Let's say I have a basic dumb javascript class :
var FunctionX = function(configs) {
this.funcConfigs = configs;
}
FunctionX.prototype.getData = function() {
return $.get('/url');
}
FunctionX.prototype.show = function(promise) {
console.log(this.funcConfigs); // <-- this here is the promise itself, I'm looking to get the instance's configs
}
FunctionX.prototype.setup = function() {
this.GetData().then(show);
}
var f = new FunctionX({ "a": "b" });
f.setup();
Now I'm trying here in the show function to access the instance variable "funcConfig". "This" is the promise, and "funcConfigs" directly returns undefined.
I tried to resolve this issue with a .resolveWith(this) but it does not solve this issue.
How can I access the instances variables in this scope context?
In agreement with user2864740, the issue is most likely caused because this is not what you expect it to be when show is invoked as a callback. To make this work properly, you need to capture the proper this in a closure (e.g. var that = this;), and invoke it explicitly.
In other words...
FunctionX.prototype.setup = function() {
var that = this;
this.getData().then(function () {
that.show();
});
}
EDIT: For a slightly cleaner syntax (using underscore.js):
FunctionX.prototype.setup = function() {
var that = this;
this.getData().then(_.bind(this.show, this));
}

Making JavaScript private methods accessible to its public methods

I understand there are couple of patterns to make JavaScript 'class-like'.
I would like to take the 'extending by prototype' way... simply because it looks more neat. I am not worried about performance much here...
In the below example I have a class (basically function) MetricsChart. I have couple of public methods and one private method (basically a reusable method).
Here from the public method (drawOrAdd) I can't access the private method (_convertArrayToTable), how can I do that?
function MetricsChart(containerId, chartType) {
this._container = document.getElementById(containerId);
this._chartType = chartType;
this._isChartDrawn = false;
this._chartData = null;
var _convertArrayToTable = function (data) {
return google.visualization.arrayToDataTable(data);
}
}
MetricsChart.prototype.drawOrAdd = function(data)
{
if (!this.isChartDrawn()) {
var chart = new google.visualization.LineChart(this._container);
if (chart) {
var table = _convertArrayToTable(data);
console.log(table);
this._isChartDrawn = true;
}
}
}
MetricsChart.prototype.isChartDrawn = function () {
return this._isChartDrawn;
}
MetricsChart.prototype.getChartData = function () {
}
One way I accidentally found was to enclose the public methods inside the MetricsChart class itself...
It works for me :): I can access the public methods outside and the public method can access the private method (serves the purpose).
Below code... Is this right? Am I doing anything wrong?
function MetricsChart(containerId, chartType) {
this._container = document.getElementById(containerId);
this._chartType = chartType;
this._isChartDrawn = false;
this._chartData = null;
var _convertArrayToTable = function (data) {
return google.visualization.arrayToDataTable(data);
}
MetricsChart.prototype.drawOrAdd = function (data) {
if (!this.isChartDrawn()) {
var chart = new google.visualization.LineChart(this._container);
if (chart) {
var table = _convertArrayToTable(data);
console.log(table);
this._isChartDrawn = true;
}
}
}
MetricsChart.prototype.isChartDrawn = function () {
return this._isChartDrawn;
}
MetricsChart.prototype.getChartData = function () {
}
}
So, here a couple of things, in order to understand what you have done precisely.
First of all:
function foo() {
var i = 0;
function bar() {
return true;
}
}
What's happening here: every time the function foo is called, it creates in its scope a new variable i, and a new function bar. The function bar and the variable i are in its scope, it means they're local: there is no way, with this code, to access to either i or bar outside the function foo. Also because, once the function foo is terminated, both i and bar are disposed.
So, this is why you cannot access from your "public" method to the "private" one, and I hope it's more clear now. The only way for a function to access to a function or variable is that there is a reference shared in the same scope. So, this is what you have done in your last example: you define your "public" methods in the same scope where you define your "private" method. In this way they can access each other. However, the way you have done, has a big downside. As I said previously, the function bar is created every time the function foo is called. In a "class" example, it means:
function MyClass() {
function myprivate() {}
MyClass.prototype.mypublic = function () { return myprivate() }
}
It means that every time you're creating an instance of MyClass, you're creating two new functions, and you're rewrite all the time the prototype of your "class". This is far from be a good approach. In fact, if you have something like:
var a = new MyClass();
var _mypublic = a.mypublic;
var b = new MyClass();
console.log(_mypublic === b.mypublic) // false
console.log(_mypublic === a.mypublic) // false too!
So, you guess right but you executed wrong. What you need here is a the "module pattern": nowadays you can use CommonJS module in nodejs or AMD in browser and so on, but the basic idea is defined a "scope" and exports from this scope only what you want. In your case, you could have:
// this is your "module"
;(function(exports) {
// your local (private) function
var _convertArrayToTable = function (data) {
return google.visualization.arrayToDataTable(data);
}
function MetricsChart(containerId, chartType) {
this._container = document.getElementById(containerId);
this._chartType = chartType;
this._isChartDrawn = false;
this._chartData = null;
}
MetricsChart.prototype.drawOrAdd = function(data) {
if (!this.isChartDrawn()) {
var chart = new google.visualization.LineChart(this._container);
if (chart) {
var table = _convertArrayToTable(data);
console.log(table);
this._isChartDrawn = true;
}
}
}
// you decided to exports to the main scope what you want
exports.MetricsChart = MetricsChart;
}(this)); // here `this` is the global object
And that's it. You have created a closure, using the "module pattern", and from the "public" method you can access to the "private" function, because they're defined in the same scope. But because you do not do that in the "class" constructor, you don't redefine them every time you instantiate a new object. Therefore, the previous example written in this way, will give the right result:
var a = new MyClass();
var _mypublic = a.mypublic;
var b = new MyClass();
console.log(_mypublic === b.mypublic) // true
console.log(_mypublic === a.mypublic) // true
What you've done isn't necessarily "wrong"...it just looks weird. Also, you won't be able to access "MetricsChart.prototype.*" until after you've created an instance of "MetricsChart". Depending on how you are using this object, it may not matter.
That being said, another way is to keep your original structure, but move the following outside of the constructor:
var _convertArrayToTable = function (data) {
return google.visualization.arrayToDataTable(data);
}
It would still be private to your module which should be good enough (you are using modules right?).
What you have done works perfectly.
You can't inherit private methods in any OOP language in terms of overriding them or accessing them directly. They are private. So it makes no sense to have them prototyped for inheritance purposes. You have wrapped them in function scope so they are as "private" as they need to be.
To access the private methods use privilege methods. Check this document: http://javascript.crockford.com/private.html.
About your code check this answer:
Setting javascript prototype function within object class declaration
p.s.
function Test()
{
var p = function(pv)
{
//
}
this.e = function (ap) { p(ap) }
}
var n = new Test();
n.e("e"); // It is legal call
n.p(); // will throw
But if you declare a private function in c-tor it will be executed on first creation of object of this type. When declare a methods in prototype this methods are add before any code execution. In general the browser first check the js file to collect all methods for prototype and than execute any code. So when you declare a prototype methods into c-tor this methods will be available only after first creation of the object of those type. ( Sorry for my English ).
Check this situation:
function Test()
{
alert(this.ST_A);//alert undefined
alert(this.ST_B);//alert 2
Test.prototype.ST_A = 1;
alert( this.ST_A)//alert 1
}
Test.prototype.ST_B = 2;
In first pass the browser will populate Test with ST_B and ST_B will be available anywhere any time. After than in second pass the browser will start to execute the code in this time ST_A will not be visible until the browser execute the Test.prototype.ST_A = 1;

javascript is it possible to use a string to call a object function

I have a generic function which can speak to multiple other functions in appropriate objects is it possible to use a string to call the appropriate function.
var string = "save";
var generic = (new function (string) {
string."alert()";
return this;
})
var save = (new function (string) {
this.alert = (function () {
alert("your document has been saved")
return this
})
return this
})
var notSaved = (new function (string) {
this.alert = (function () {
alert("your document has not been saved")
return this
})
return this
})
I am using it for a far more complex set up but here is an example. Is this possible?
Sure you can. Try something like this:
window[string].alert();
Looking at your code it's hard to tell what you're actually trying to achieve. Nonetheless, here are a few ideas that may be relevant.
First, let's make a couple of objects:
var rabbit = {
name: 'Peter',
hop: function () {
return this.name + ' hopped!'
},
jump: function () {
return this.name + ' jumped!'
}
}
var hairy_maclary = {
name: 'Hairy Maclary',
jump: function () {
return this.name + ' jumped over the fence!'
}
}
Now, you could define a function which invokes the hop method on whichever object is passed to it:
function hop(object) {
return object.hop()
}
hop(rabbit) // 'Peter hopped!'
I'm not sure why you'd do this rather than invoking hop directly, but perhaps you want to do extra stuff before or afterwards.
If you wanted to you could create a completely generic function which would invoke a given method on a given object:
function invokeMethod(object, method) {
object[method]()
}
invokeMethod(hairy_maclary, 'jump') // 'Hairy Maclary jumped over the fence!'
This is a really strange thing to want to do, though. Perhaps you could provide more of an idea of what you're actually trying to do, since your example code is rather odd.
You can enclose your functions within some object so you can access by passing name of the property using some variable (in this case named string), eg. like that:
var string = 'notSaved';
var funcs = {};
funcs.save = new function(){
this.alert = function(){
alert('called save.alert()');
};
return this;
};
funcs.notSaved = new function(){
this.alert = function(){
alert('called notSaved.alert()');
};
return this;
};
funcs[string].alert();
See working example on jsfiddle.
If your variables are global (they should not), they are also automatically enclosed within window object, so you can call them also like that: window[string].alert(). This will not work for non-global functions (in this case my solution seems to be the only one not using eval()).
eval("alert('test');");
You can call functions with eval. Even you can declare functions.
eval("function test(){ alert("test");}");
test();

"Friend Classes" in javascript

I have a Factory class that creates a Widget object. The Factory object needs to callback a "private method" of the Widget object at a later time to pass it some ajax info. So far, the only implementation I've come up with is to create a public method in the Widget that returns the private method to the factory, and then deletes itself, the Factory then returns the new Widget while retaining a pointer to the private method. Here is a simplified example:
function Factory()
{
var widgetCallback = null;
this.ajaxOperation = function()
{
//some ajax calls
widgetCallback('ajaxresults');
}
this.getNewWidget = function()
{
var wid = new Widget();
widgetCallback = wid.getCallback();
return wid;
}
function Widget()
{
var state = 'no state';
var self = this;
var modifyState = function(newState)
{
state = newState;
}
this.getState = function()
{
return state;
}
this.getCallback = function()
{
delete self.getCallback;
return modifyState;
}
}
}
Is there a better way to achieve the effect I'm after or is this a fairly reasonable approach? I know it works, just curious if I'm stepping into any pitfalls I should be aware of.
this.getNewWidget = function() {
var val = new Widget(),
wid = val[0],
widgetCallback = val[1];
return wid;
}
function Widget() {
var state = 'no state';
var self = this;
var modifyState = function(newState) {
state = newState;
}
this.getState = function() {
return state;
}
// Return tuple of Widget and callback
return [this, modifyState];
}
Just get your constructor to return a Tuple<Widget, function>
Alternative just use closure scope to edit widgetCallback directly in your Widget constructor
function Factory() {
var widgetCallback = null;
this.ajaxOperation = function() {
//some ajax calls
widgetCallback('ajaxresults');
}
this.getNewWidget = function() {
return new Widget();;
}
function Widget() {
var state = 'no state';
var self = this;
// set it directly here!
widgetCallback = function(newState) {
state = newState;
}
this.getState = function() {
return state;
}
}
}
I'm not familiar enough with object oriented JavaScript (I use mostly one-or-two liners inside GWT code) to actually give an Real Answer (But I found that my response were a bit long for a comment...)
I think self-modifying classes, sounds like a major potential for gotcha's.
I personally prefer languages such as JavaScript, Ruby, etc. that are not restrictive in what you can do (even if I have to use Java+GWT at work, hehe), but where you rely self discipline to not do stupid things. I would rather prefix the method name with "_" (and simply avoid using it where I should not), than try to enforce private methods. Since JavaScript by nature is very unrestricted in what crazy things you may do, it requires a lot of discipline anyway.
If you deleted a method after use; to kind-of-protecting it, could you not just as easily add a new method to do the same? You would still rely on your (and others) self discipline and sanity anyway, aren't you?

Categories

Resources