This question already has answers here:
How can I chain my method calls?
(5 answers)
Closed 6 years ago.
I have this object:
const Foo = {
bar(x) {
},
baz(x) {
},
}
How can I rewrite this object to be able to call it's methods like this:
Foo.bar(x).baz(y);
instead of calling them like this:
Foo.bar(x);
Foo.baz(y);
Like in the jQuery where you can call one function after another...
$('bac').addClass('x').removeClass('y');
You will have to return the object itself with each function, so as you could call the function on it again (that's also what jQuery does).
const Foo = {
bar(x) {
return this;
},
baz(x) {
return this;
},
}
You should return this at the end of each function. In this context this refers to the Foo object itself.
const Foo = {
bar(x) {
return this;
},
baz(z) {
return this;
}
}
Example:
Foo.bar(x).baz(z);
is executed as:
Foo.bar(x) // <-- returns 'Foo'
.baz(z) // <-- call 'baz' function of 'Foo'
You Should Return The Object Itself From The Method To Call Another Method Again:
const Foo = {
bar(x) {
alert("BAR");
return this;
},
baz(x) {
alert("BAZ");
return this;
},
}
onload = function() {
Foo.bar().baz();
}
This is known as a Fluent API
In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is an implementation of an object oriented API that aims to provide more readable code.
A fluent interface is normally implemented by using method cascading (concretely method chaining)
In this case it is implemented by returning the self-object this:
const foo = {
bar(x) {
console.log("bar")
return this; // here
},
baz(x) {
console.log("baz")
return this; // and here
}
}
foo.bar(10).baz(20);
Related
I am confused by this question and not even the JavaScript MDN is clarifying the concept for me.
There is a function called invokeMethod and in that function I have to create an Object. The Object includes a Method. I need to invoke the Method in the Object using bracket notation but nothing needs to be returned.
Here is the Question and my code. I keep getting error messages when I try to call the method in the function parentheses.
Question: method is a string that contains the name of a method on the object
Invoke this method using bracket notation.
Nothing needs to be returned.
Input Example:
{ foo: function() {} }, 'foo'
My code:
function invokeMethod(object, method) {
// code here
const obj = {
name: 'kung',
foo: function(){
console.log('foo');
}
};
}
invokeMethod(obj[foo]);
Check if this help.
function invokeMethod(object, method) {
// object definitions
const obj = {
name: 'kung',
foo: function(){
console.log('foo');
}
};
// conditional invokation
switch(object){
case "obj":
if(typeof obj[method] == "function") return obj[method]();
default:
console.log("Given object not found!");
}
}
// call method
invokeMethod("obj", "foo");
***If the object itself is to be passed as parameter:
function invokeMethod(object, method) {
if(typeof object[method] === "function")
object[method]();
else
console.log('Invalid function name!');
}
invokeMethod({ foo: function() {console.log('foo');} }, 'foo');
Maybe this could help.
Look at your function I'm seen that you have as arguments two elements object and method. So, your functions it's bad doing this
function invokeMethod(object, method) {
// code here
const obj = {
name: 'kung',
foo: function(){
console.log('foo');
}
};
}
if you are going to receive the obj-function, you should have just this,
function invokeMethod(method)
Now, Following your example, I'm going to think that you really want to receive the obj-function. So, in that case, you should do this.
const obj = {
name: 'kung',
foo: function(){
console.log('foo');
}
};
function invokeMethod(obj, method) {
if((method in obj) && typeof obj[method] ==="function"){
return obj[method]();
}
}
invokeMethod(obj, 'foo');
This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
class Foo {
constructor() {
this.foobar = "foobar";
}
bar() {
let _this = this;
return function() {
try {
alert("Attempt 1: "+foobar);//ReferenceError: foobar is not defined
myMethod();
} catch(err) {console.log(err);}
try {
alert("Attempt 2: "+this.foobar);//TypeError: this is undefined
this.myMethod();
} catch(err) {console.log(err);}
try{
alert("Attempt 3: "+_this.foobar);//Works!
_this.myMethod();
} catch(err) {console.log(err);}
}();
}
myMethod() {
alert("myMethod()");
}
}
new Foo().bar();
The above example is very simplified - the anonymous function inside bar() was a jQuery call originally, but for the sake of the question I didn't include that.
Why don't attempts 1 and 2 work? Do I have to use the _this trick to reference class variables/methods? How do I reference class variables/methods from nested functions?
Are you familiar with how the this keyword works in JavaScript? It's value will depend on how the function is called, not in how it is defined. For example, if you do the following:
var dog = {
greeting:"woof",
talk:function (){
console.log(this.greeting);
}
};
var cat={
greeting:"meow",
talk:dog.talk
};
dog.talk();
cat.talk();
You will see that when the talk function is called as a method of an object, that object will be used as the value of this.
The same happens with ES6 classes, where class methods are still JavaScript functions and the rules for deciding the value of this still apply. If you want to avoid declaring an auxiliar variable, you should look into using bind:
var mammal = {
greeting:"<noise>",
getTalk:function (){
return function(){
console.log(this.greeting);
};
},
getTalkBinded:function (){
return (function(){
console.log(this.greeting)
}).bind(this);
}
};
var dog={
greeting:"woof",
talk:mammal.getTalk(),
talkBinded:mammal.getTalkBinded()
};
var cat={
greeting:"meow",
talk:mammal.getTalk(),
talkBinded:mammal.getTalkBinded()
};
dog.talk();
cat.talk();
dog.talkBinded();
cat.talkBinded();
You are returning self-execution function execution result and during that function execution this it global context(not your class object). to make it work use () => {}() arrow function call syntax, as it captures current context, or function() { }.bind(this)().
See this simple example,
function a(){
this.someProp = 5;
console.log(this);
var _this = this; //so we explicitly store the value of `this` to use in a nested function
return function(){
//value of `this` will change inside this function
this.anotherProp = 6;
console.log(this);
//to use the methods and props of original function use `_this`
console.log(_this)
}
}
var c = a.call({}) //prints {someProp: 5}
c.call({}) //prints {anotherProps: 6} {someProp: 5}
Is there any difference between these two snippets apart from just pure preference in which you use? As I've seen both used a lot and am not sure how/why they differ other than just preference in terms of readability.
object.foo = function () {
//code
}
foo : function () {
//code
}
This:
object = {
foo : function () {
// code
}
}
is the complete way to write the second statement, meaning you define the function in the initialization of the object.
This code:
object.foo = function () {
//code
}
can be used both as a shorthand, and if you want to declare the function dynamically after the declaration of the object.
They do exactly the same thing in the example you've given, but there are some slight differences which explain why there are seemingly 2 ways to do the same thing.
Take this example...
var obj = {
foo: function() {
// do something
}
};
You can then extend that object like this...
obj.bar = function() {
// do something different
};
But if you did this...
obj = {
bar: function() {
// do something different
}
};
... you would lose the function foo. So one method is for explicitly declaring an object, complete with properties and functions, and the other method can be used for extending an existing object.
Just to be perfectly clear, this is incorrect syntax...
var obj = {
foo = function() { // it should be foo: function() {}
// do something
}
};
I just saw this code example from the crypto-library of node.js and wondered how this kind of "concatenated" function-calls are implemented?
crypto.createHash('sha256').update(password).update(salt).digest('base64');
The return value of one function is an object (probably the original object, this here). A property of that object is another function.
var myObj = {
foo: function() {
alert("foo");
return this;
},
bar: function() {
alert("bar");
return this;
}
};
myObj.foo().bar().bar().foo().bar();
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...