I have one simple object calculation function .I was pass the object resultant data in to another object function like the chain reaction
example like:
str.replace().replace().replace() They will pass the resultant data of first replace to 2nd replace like the chain reaction.
So i want to created the below code .But not working in my case .
See the below snippet
var m=function(data){
return {
str :data,
plus:function(b){
this.str = this.str+b;
return this.str;
},
min:function(a){
this.str = this.str-a
return this.str;
}
}
}
console.log(m(5).plus(1).min(3))
If 5 add with 1 is 6 .Then pass the 6 into min() function for reduce 3 .finally console.log result 3 .But It have some here .Please help to solve my problem.
Thanks
I suggest to use an object and return that object after a method call. For better use, you could implement toString and valueOf methods to use the return value directly.
What you need is to return the whole object, for all methods which a chainable.
var m = function(value){
var obj = {
value: value,
plus: function (b) {
obj.value += b;
return obj;
},
min: function(a) {
obj.value -= a;
return obj;
},
toString: function () { return obj.value; },
valueOf: function () { return obj.value; }
}
return obj;
}
console.log(m(5).plus(1).min(3).value);
alert(m(5).plus(1).min(3));
console.log(m(3).plus(7) - m(5).min(1));
var m=function(data){
return {
str :data,
plus:function(b){
this.str = this.str+b;
return this;
},
min:function(a){
this.str = this.str-a
return this;
}
}
}
console.log(m(5).plus(1).min(3).str)
For creating chain like method calls you need to return 'this' from the function after which you want to the chain to continue
Another closer way, we can return this separately, at initialisation, and every other method calls.
Doing it this way is a real chain, as this called in the plus and min function is the incoming object, it's not a recomposition.
We often see both styles.
function m(n) {
this.value = n.value
this.plus = (n) => {this.value = this.value + n.value; return this}
this.min = (n) => {this.value = this.value - n.value; return this}
return this // Only at initialisation
}
console.log(m({value: 5}).plus({value: 1}).min({value: 3}).value)
Related
i don't know how to call something like: let r = fun().func1(2).func2(2), without the use of new keyword. I know it via new keyword, something like let r = new fun().func1(2), but can I implement it with the syntax above.
Each function could return an object containing a function:
function fun() {
return {func1(num1) {
return {func2(num2) {
return num1 * num2;
}}
}}
}
let r = fun().func1(2).func2(2);
console.log(r);
You could build a fluent interface by returning an object with the function, you need. To get a result, you need to specify a function which returns a value instead of an object, or implement a toString or valueOf function.
const
fun = (result = 0) => {
const functions = {
add (value) {
result += value;
return functions;
},
multiply (value) {
result *= value;
return functions;
},
ans () {
return result;
}
}
return functions;
};
console.log(fun().add(2).multiply(3).ans());
var Obj = {
func1 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be CALLED
}
return this;
},
func2 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be NOT called
}
return this;
},
_hasChainedFunc : function() {
// code which detects if there is a chained function???
}
}
Obj.func1().func2();
Is there a possible implementation for function _hasChainedFunc()? This function should return true on the first call (because func2() is called afterwards), false on the second call.
In a more advanced version, _hasChainedFunc() may also returned the function which is actually called afterwards.
Technically you can never know in advance whether there's another call chained after the current call -- this plainly doesn't make sense because it implies you're aware of some code that's gonna be called before it's called. You can't do this without a pre-compiler, which I guess is not what you're after.
Conversely, it is possible to check whether there's been a previous call chained before the current call. This just requires you to keep some state in the object regarding the previous calls, and update it whenever you call a new function on it. If you only use one chain of calls, you can do this by making func1 and func2 change some state on the this object before returning it.
If you want to call multiple chains on the same object, you face the problem of how to detect the end of a chain. For this you will need to make each chained function return a wrapper around the original this, which would store the state about the previous calls.
If you use the wrapper approach, obj.func1().func2() calls func1 on obj, but func2 is called on a wrapper returned from func1 and this wrapper could be aware of the previous func1 call. If you later call obj.func2().func1() then func2 is now called on obj whereas func1 is called on the wrapper which is aware of the previous func2 call, etc.
(NOTE: This answer was originally posted by Scholle as part of the question. I extracted it from the question into an actual answer, as it should have been in the first place. It is not my solution, so I have marked it as Community Wiki.)
Scholle ultimately created a library that does what he wanted.
It's available on GitHub, and some documentation is here.
In short: Take an arbitrary JavaScript function and "chainify" it:
var Model = function() {};
Model.prototype.func1 = function() {
console.log('func1 has ' + this.c_getPredecessors().length + ' preceding functions');
return this.c_delay().c_chain(function() {
console.log('func1 has ' + this.c_getSuccessors().length + ' succeeding functions');
console.log('func1 processing...');
this.c_next();
});
};
Model.prototype.func2 = function() {
console.log('func2 has ' + this.c_getPredecessors().length + ' preceding functions');
return this.c_delay().c_chain(function() {
console.log('func2 has ' + this.c_getSuccessors().length + ' succeeding functions');
console.log('func2 processing...');
this.c_next();
});
};
Chainify and instantiate it,
and call some functions:
chainify(Model);
var Obj = new Model();
Obj.func1().func2();
Console output:
func1 has 0 preceding functions
func2 has 1 preceding functions
func1 has 1 succeeding functions
func1 processing...
func2 has 0 succeeding functions
func2 processing...
Of course, this is a simple example. It just demonstrates that every
functions is now capable to access information about what happens
before and after the current function call.
No, it's not possible.
It's semantically identically to:
var tmp = Obj.func1();
tmp.func2();
When Obj.func1() is called, there's no way for it to know whether the subsequent result will be used to call func2.
The best you could achieve is for func2 to detect whether func1 was previously called, but for it to work the way you've described would require func1 to be capable of predicting the future.
What you can do is add a member property indicating if it's the first call made on the object or not:
var Obj = {
_first : true,
func1 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be CALLED
}
return this;
},
func2 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be NOT called
}
return this;
},
_hasChainedFunc : function() {
var isFirst = this._first;
this._first = false;
return isFirst;
}
}
Obj.func1().func2();
However, this means you have to reset the state of the object before each call (by setting this._first back to true). You may want to rethink how you're going about this.
here's how i would do this:
var Obj = {
first:0, //<--- will store whether it's the first call
func1 : function() {
// some code
if (this._hasChainedFunc()) {
console.log("called1");
}
return this;
},
func2 : function() {
// some code
if (this._hasChainedFunc()) {
console.log("called2");
}
return this;
},
_hasChainedFunc : function() {
return (this.first++ > 0);
}
}
Obj.func1().func2();
and this seems to work:
called2
http://jsfiddle.net/2VThj/1/
Why would you want to do this?
That question aside, you could, rather than returning the actual object, make a clone of it, and add an attribute to tell you it is a returned version of the object. That is the only way I can think of. Sounds complex though, depending on how complex this object is.
Something like:
func1 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be CALLED
}
return deepCloneWithFlag(this);
},
_hasChainedFunc : function() {
return this.flag;
}
Nope. this won't work. you could possibly tell that func1() had at some point been called on this object, but you cannot tell WHEN it was called, i.e. right before func2
for example this:
obj.func1();
obj.func2();
is equivalent to your example call. And there is no way func1 could know that func2 will be called in the future.
I solved a problem similar to this with chain functions (docs) This allows true function chaining with the ability to "look-ahead" to see what's coming in the chain.
What you could do is have two separate classes, one for the first element in the chain and one for the remaining elements. Then all you would have to do is change the first class to return an equivalent object from the second class instead of the current object.
var Class1 = function(state){
return {
func1 : function() {
// some code
// block should be CALLED
return Class2(state)
},
func2 : function() {
// some code
// block should be NOT called
return Class2(state)
}
};
}
var Class2 = function(state){
return {
func1 : function() {
// some code
return this;
},
func2 : function() {
// some code
return this;
}
};
}
Class1(initial_state).func1().func2();
Althought knowing that a function will be called after another function is impossible in Javascript, here is a solution to chainify an object :
(function(window, undefined)
{
var chainify = function(prop)
{
return new chainify.init(prop);
};
/**
*
* #param prop :
* Properties to apply to the object
* #returns {chainify.init}
*/
chainify.init = function(prop)
{
for ( var key in prop)
this[key] = prop[key];
};
chainify.init.prototype = {
_attributes : {},
_chain_in_progress : false,
_chain_level : 1,
_chain_function : '',
/**
* Returns the chained object
*
* #param name -
* name of the previous function
* #this chainify.init
* #returns {chainify.init}
*/
_chain : function(name)
{
var tmp = chainify(this);
tmp._chain_in_progress = true;
tmp._chain_function = name || '';
_chain_level++;
return tmp;
},
get : function(key)
{
return this._attributes[key];
},
set : function(key, value)
{
this._attributes[key] = value;
return this;
},
attr : function(prop)
{
for ( var key in prop)
this._attributes[key] = prop[key];
return this;
},
};
// Make global
window.chainify = chainify;
})(window);
var myObject = window.chainify({
// f1() function is using _chain()
f1 : function(s)
{
// Do something
this.set('s1', s);
if (this._chain_in_progress) alert('f1 after ' + this._chain_function);
// return the chain by calling this._chain()
return this._chain('f1');
},
// f2() function is using _chain()
f2 : function(s)
{
this.set('s2', s);
if (this._chain_in_progress) alert('f2 after ' + this._chain_function);
return this._chain('f1');
},
// that() function is not using _chain(), but we return this so the chaining
// is not broken
that : function(s)
{
// Do something
return this;
}
});
// Check if the f1 function is working
myObject.f1('a'); // Set s1 to "a"
alert(myObject.get('s1')); // should be "a"
// check if the f2 chaining is working
myObject.f1('b').f1('c'); // f1 after f1
alert(myObject.get('s1')); // should be "c" -> changed on last f1 function
// Check if the f2 function is working
myObject.f2('a');
alert(myObject.get('s2')); // should be "a"
// check if the f2 and f1 chaining is working
myObject.f2('b').f1('c').f1('d').f2('e'); // f1 after f2, f1 after f1 ...
alert(myObject.get('s1')); // should be "d" -> changed on last f1 function
alert(myObject.get('s2')); // should be "e" -> changed last f2 function
// check the chain with that() -
myObject.that('b').f1('a').f1('z'); // f1 chained after f1
alert(myObject.get('s1')); // should be "z" -> changed on last f1 function
Is there a way to access properties in nested functions like that :
function func(){
this.new_func=function(){
console.log("something");
return 'something';
}
this.someValue=7;
return function(){
return "something_diff";
};
}
var obj=new func();
obj(); //works with returning "something diff"
obj.new_func(); // TypeError: obj.new_func is not a function
obj.someValue; // undefined
I need to delete whole "return function()..." part in order to access "someValue" and "new_func()". Why is it acting like that, and is there a way to somehow access that properties, while still returning another function ??
When you have a constructor that returns an object, that object replaces whatever you assigned to this. So indeed, the members new_func and someValue are lost.
To combine the returned function together with the other members, you can do this:
function func() {
var f = function() {
return "something_diff";
};
f.new_func = function() {
console.log("something");
return 'something';
}
f.someValue = 7;
return f;
}
var obj = new func();
console.log(obj());
obj.new_func();
console.log('someValue:', obj.someValue);
You can do it like this:
var parentFunction = function() {
var nestedFunction = function() {
var value = "nestedValue";
var moreValues = "more values";
return {
value: value,
moreValues: moreValues
}
}
var anotherNestedFunction = function() {
var anotherValue = "nestedValue";
return anotherValue;
}
return {
nested: nestedFunction,
another: anotherNestedFunction
}
}
Then:
var newFunction = new parentFunction();
var nested = newFunction.nested();
console.log("nested value: ", nested.value);
console.log("another nested value: ", newFunction.another);
Here is a working example:
Why is it acting like that, and is there a way to somehow access that properties, while still returning another function ??
Because of the pharenteis:
var obj=new func();
Basically you're firing your function and what is stored the variable obj is what the "func" returns.
In order to access to private properties, you should look at the Closures: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
Given the following piece of code:
function Foo() {};
Foo.prototype.one = fluent(function(a , b) {
return a + b;
});
Foo.prototype.two = fluent(function(c) {
var d = c + 0.15; //0.15 cause I just couldnt thougth anything else at this moment...
return d;
});
ok that's all good for the moment, now let's say fluent is a decorator function that allows me to implement it like this:
var test = new Foo();
test.one(10, 5).two(); //here is the problem...
Thinking as it was a promise, how can I modify this code in order to make the returned valued of one available on two??? meaning, c should be the returned valued of one(), while keeping the sample implementation.
Here is the fiddle;
I would propose the following definition of fluent. Note that if needed, the final return value is in this.$lastReturn:
function fluent(impl) {
return function() {
// Convert arguments to a real array
var args = Array.prototype.slice.call(arguments);
// Prepend the last return value for this object
if(typeof this.$lastReturn != 'undefined')
args.unshift(this.$lastReturn);
// Invoke the function and save the return value
this.$lastReturn = impl.apply(this, args);
// Return this to allow chaining of the next fluent call
return this;
}
}
This solution utilised the answer of Dark Falcon and makes a little extent to the feature of returning a value or the chain.
Javascript offers the possibillity to request a primitive value of the object, Object.prototype.valueOf()
. In this case it may be used to get a value in case we need a value and on other cases, there is the object returned.
For more information have a look to this article Object-to-Primitive Conversions in JavaScript.
Another addition is argument control at fluent and the call of the methods. If arguments are given, then the arguments are taken, if not given, then the this.$lastreturn is used.
function fluent(impl) {
return function () {
var args = Array.prototype.slice.call(arguments);
// Prepend the last return value for this object only if arg length is 0
if (!args.length && typeof this.$lastReturn !== 'undefined') {
args.unshift(this.$lastReturn);
}
this.$lastReturn = impl.apply(this, args);
return this;
}
}
function Foo() { };
Foo.prototype.one = fluent(function (a, b) {
return a + b;
});
Foo.prototype.two = fluent( function (c) {
return c + 0.77;
});
// this returns the primitive value
Foo.prototype.valueOf = function (c) {
return this.$lastReturn;
};
var test = new Foo();
var x = test.one(10, 5);
document.write(x + '<br>'); // 15
document.write(typeof x + '<br>'); // object
var y = x.two();
document.write(y + '<br>'); // 15.77
document.write(typeof y + '<br>'); // object
var z = y.two(35);
document.write(z + '<br>'); // 35.77
document.write(typeof z + '<br>'); // object
var Obj = {
func1 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be CALLED
}
return this;
},
func2 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be NOT called
}
return this;
},
_hasChainedFunc : function() {
// code which detects if there is a chained function???
}
}
Obj.func1().func2();
Is there a possible implementation for function _hasChainedFunc()? This function should return true on the first call (because func2() is called afterwards), false on the second call.
In a more advanced version, _hasChainedFunc() may also returned the function which is actually called afterwards.
Technically you can never know in advance whether there's another call chained after the current call -- this plainly doesn't make sense because it implies you're aware of some code that's gonna be called before it's called. You can't do this without a pre-compiler, which I guess is not what you're after.
Conversely, it is possible to check whether there's been a previous call chained before the current call. This just requires you to keep some state in the object regarding the previous calls, and update it whenever you call a new function on it. If you only use one chain of calls, you can do this by making func1 and func2 change some state on the this object before returning it.
If you want to call multiple chains on the same object, you face the problem of how to detect the end of a chain. For this you will need to make each chained function return a wrapper around the original this, which would store the state about the previous calls.
If you use the wrapper approach, obj.func1().func2() calls func1 on obj, but func2 is called on a wrapper returned from func1 and this wrapper could be aware of the previous func1 call. If you later call obj.func2().func1() then func2 is now called on obj whereas func1 is called on the wrapper which is aware of the previous func2 call, etc.
(NOTE: This answer was originally posted by Scholle as part of the question. I extracted it from the question into an actual answer, as it should have been in the first place. It is not my solution, so I have marked it as Community Wiki.)
Scholle ultimately created a library that does what he wanted.
It's available on GitHub, and some documentation is here.
In short: Take an arbitrary JavaScript function and "chainify" it:
var Model = function() {};
Model.prototype.func1 = function() {
console.log('func1 has ' + this.c_getPredecessors().length + ' preceding functions');
return this.c_delay().c_chain(function() {
console.log('func1 has ' + this.c_getSuccessors().length + ' succeeding functions');
console.log('func1 processing...');
this.c_next();
});
};
Model.prototype.func2 = function() {
console.log('func2 has ' + this.c_getPredecessors().length + ' preceding functions');
return this.c_delay().c_chain(function() {
console.log('func2 has ' + this.c_getSuccessors().length + ' succeeding functions');
console.log('func2 processing...');
this.c_next();
});
};
Chainify and instantiate it,
and call some functions:
chainify(Model);
var Obj = new Model();
Obj.func1().func2();
Console output:
func1 has 0 preceding functions
func2 has 1 preceding functions
func1 has 1 succeeding functions
func1 processing...
func2 has 0 succeeding functions
func2 processing...
Of course, this is a simple example. It just demonstrates that every
functions is now capable to access information about what happens
before and after the current function call.
No, it's not possible.
It's semantically identically to:
var tmp = Obj.func1();
tmp.func2();
When Obj.func1() is called, there's no way for it to know whether the subsequent result will be used to call func2.
The best you could achieve is for func2 to detect whether func1 was previously called, but for it to work the way you've described would require func1 to be capable of predicting the future.
What you can do is add a member property indicating if it's the first call made on the object or not:
var Obj = {
_first : true,
func1 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be CALLED
}
return this;
},
func2 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be NOT called
}
return this;
},
_hasChainedFunc : function() {
var isFirst = this._first;
this._first = false;
return isFirst;
}
}
Obj.func1().func2();
However, this means you have to reset the state of the object before each call (by setting this._first back to true). You may want to rethink how you're going about this.
here's how i would do this:
var Obj = {
first:0, //<--- will store whether it's the first call
func1 : function() {
// some code
if (this._hasChainedFunc()) {
console.log("called1");
}
return this;
},
func2 : function() {
// some code
if (this._hasChainedFunc()) {
console.log("called2");
}
return this;
},
_hasChainedFunc : function() {
return (this.first++ > 0);
}
}
Obj.func1().func2();
and this seems to work:
called2
http://jsfiddle.net/2VThj/1/
Why would you want to do this?
That question aside, you could, rather than returning the actual object, make a clone of it, and add an attribute to tell you it is a returned version of the object. That is the only way I can think of. Sounds complex though, depending on how complex this object is.
Something like:
func1 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be CALLED
}
return deepCloneWithFlag(this);
},
_hasChainedFunc : function() {
return this.flag;
}
Nope. this won't work. you could possibly tell that func1() had at some point been called on this object, but you cannot tell WHEN it was called, i.e. right before func2
for example this:
obj.func1();
obj.func2();
is equivalent to your example call. And there is no way func1 could know that func2 will be called in the future.
I solved a problem similar to this with chain functions (docs) This allows true function chaining with the ability to "look-ahead" to see what's coming in the chain.
What you could do is have two separate classes, one for the first element in the chain and one for the remaining elements. Then all you would have to do is change the first class to return an equivalent object from the second class instead of the current object.
var Class1 = function(state){
return {
func1 : function() {
// some code
// block should be CALLED
return Class2(state)
},
func2 : function() {
// some code
// block should be NOT called
return Class2(state)
}
};
}
var Class2 = function(state){
return {
func1 : function() {
// some code
return this;
},
func2 : function() {
// some code
return this;
}
};
}
Class1(initial_state).func1().func2();
Althought knowing that a function will be called after another function is impossible in Javascript, here is a solution to chainify an object :
(function(window, undefined)
{
var chainify = function(prop)
{
return new chainify.init(prop);
};
/**
*
* #param prop :
* Properties to apply to the object
* #returns {chainify.init}
*/
chainify.init = function(prop)
{
for ( var key in prop)
this[key] = prop[key];
};
chainify.init.prototype = {
_attributes : {},
_chain_in_progress : false,
_chain_level : 1,
_chain_function : '',
/**
* Returns the chained object
*
* #param name -
* name of the previous function
* #this chainify.init
* #returns {chainify.init}
*/
_chain : function(name)
{
var tmp = chainify(this);
tmp._chain_in_progress = true;
tmp._chain_function = name || '';
_chain_level++;
return tmp;
},
get : function(key)
{
return this._attributes[key];
},
set : function(key, value)
{
this._attributes[key] = value;
return this;
},
attr : function(prop)
{
for ( var key in prop)
this._attributes[key] = prop[key];
return this;
},
};
// Make global
window.chainify = chainify;
})(window);
var myObject = window.chainify({
// f1() function is using _chain()
f1 : function(s)
{
// Do something
this.set('s1', s);
if (this._chain_in_progress) alert('f1 after ' + this._chain_function);
// return the chain by calling this._chain()
return this._chain('f1');
},
// f2() function is using _chain()
f2 : function(s)
{
this.set('s2', s);
if (this._chain_in_progress) alert('f2 after ' + this._chain_function);
return this._chain('f1');
},
// that() function is not using _chain(), but we return this so the chaining
// is not broken
that : function(s)
{
// Do something
return this;
}
});
// Check if the f1 function is working
myObject.f1('a'); // Set s1 to "a"
alert(myObject.get('s1')); // should be "a"
// check if the f2 chaining is working
myObject.f1('b').f1('c'); // f1 after f1
alert(myObject.get('s1')); // should be "c" -> changed on last f1 function
// Check if the f2 function is working
myObject.f2('a');
alert(myObject.get('s2')); // should be "a"
// check if the f2 and f1 chaining is working
myObject.f2('b').f1('c').f1('d').f2('e'); // f1 after f2, f1 after f1 ...
alert(myObject.get('s1')); // should be "d" -> changed on last f1 function
alert(myObject.get('s2')); // should be "e" -> changed last f2 function
// check the chain with that() -
myObject.that('b').f1('a').f1('z'); // f1 chained after f1
alert(myObject.get('s1')); // should be "z" -> changed on last f1 function