JavaScript class methods in an array or object - javascript

I am currently working on a project where I want to deference an array of functions (function references) and excecute the function.
This does only work, if I don't call another class method within the function.
Otherwise I get "Uncaught TypeError" and I can't figure out how to solve this error.
Here's my code sample 'working' the same way my original project does:
After calling function2 the engine cannot find this.log...
Do you have ideas? Thank you very much in advance.
KR, Robert
class ArrayWithFunctions {
constructor() {
this.functionTable = [
this.function1,
this.function2,
];
}
execute(index) {
return (this.functionTable[index])();
}
log(chars) {
console.log(chars);
}
function1() {
console.log('I am Function 1.');
}
function2() {
this.log('I am Function 2.');
}
}
let example = new ArrayWithFunctions();
example.execute(0);
example.execute(1);

This is an example of Javascript's execution contexts in action. In this situation, to avoid losing the correct reference to the class, you can bind the functions when putting them inside the array, or initialize them as arrow functions:
Example 1: Bind them in the constructor:
constructor() {
this.functionTable = [
this.function1.bind(this),
this.function2.bind(this),
];
}
Example 2: Create them as arrow functions:
class ArrayWithFunctions {
// ...
function1 = () => {
console.log('I am Function 1.');
}
function2 = () => {
this.log('I am Function 2.');
}
}

You can use arrow functions to dodge scoping issues:
function2 = () => {
this.log('I am function 2.');
}

Related: How to access the correct `this` inside a callback (and you might also want to take a look at How does the "this" keyword work?).
In this case you can simply set the correct this value by calling the function with .call:
return this.functionTable[index].call(this);

Related

Lookup map functions being called during declaration

I am trying to implement a switch statement alternative using a map object and the functions that are supposed to be called according to the condition are being called while I'm declaring the map
Here is a simplified code of what I implemented
someMethodName(someParams, otherParams) {
const verifyThis = callExternalApi(someParams);
const customSwitch = {
oneValue: this.doThis(otherParams),
anotherValue: this.doThat(otherParams),
};
const possibleValues = ["oneValue", "anotherValue"];
if (possibleValues.includes(verifyThis))
return customSwitch[verifyThis];
return this.defaultCase(otherParams);
}
I put a console.log in the methods to be called and found out that they are all being called, supposedly while I'm declaring customSwitch, and then one of the methods are being called when going through the if clause.
How do I work around this to avoid calling my methods?
Use an object whose values are functions which, when called, invoke the other functions:
const customSwitch = {
oneValue: () => this.doThis(otherParams),
anotherValue: () => this.doThat(otherParams),
};
and invoke when returning by doing
return customSwitch[verifyThis]();

How to pass current scope to a function reference?

I have the following code that constructs a string and adds an event to a button that shows said string :
function initEvents() {
const message = processSomeString();
myButton.addEventListener( () => {
//Some other code
alert(message);
})
}
The above works because in memory the anynomous event function is stored along with its outer scope.
I would like to remove the nested anonymous function to improve readability, but then how do I attach the message variable to referenced function?
Preferably in a modern way, considering ES6+
Function.prototype.bind() wouldn't be ideal since I need the this reference to not change in my actual context.
function initEvents () {
const message = processSomeString();
myButton.addEventListener(myButtonClick);
}
function myButtonClick () {
//Some other code
alert(message??);
}
Use .bind:
function initEvents () {
const message = 'any string' //processSomeString();
// pass `myButton` as first argument of `.bind`
// so that in your `myButtonClick()` you still have reference to `this`
myButton.addEventListener('click', myButtonClick.bind(myButton, message));
}
function myButtonClick(message, e){
console.log(`this: ${this}`);
console.log(`message: ${message}`);
}
initEvents();
<button id="myButton">Button</button>
Please note that in your code, this line: myButton.addEventListener(myButtonClick) won't work because you lack one "eventType" argument for .addEventListener.
Edit to fit question:
To preserve this keyword reference, simply pass this as first argument:
function initEvents () {
const message = 'any string' //processSomeString();
// For JS beginners, just read the documentation link above for explanation
myButton.addEventListener('click', myButtonClick.bind(this, message));
}
function myButtonClick(message, e){
console.log(`this: ${this}`);
console.log(`message: ${message}`);
}
initEvents();
<button id="myButton">Button</button>
You can't pass the scope, you'll need to pass arguments:
function myButtonClick(message) {
//Some other code
alert(message);
}
function initEvents() {
const message = processSomeString();
myButton.addEventListener(() => myButtonClick.call(this, message));
// or:
myButton.addEventListener(myButtonClick.bind(this, message));
}
Though note that I find it weird to preserve this here. That would only make sense if both functions are methods on the same object, in which case .bind(this) is a common idiom. If they are unrelated functions, passing the this context this way is… unexpected.

TypeError: "listener" argument must be a function. Using npm pixelmatch in node JS [duplicate]

How do I pass a function as a parameter without the function executing in the "parent" function or using eval()? (Since I've read that it's insecure.)
I have this:
addContact(entityId, refreshContactList());
It works, but the problem is that refreshContactList fires when the function is called, rather than when it's used in the function.
I could get around it using eval(), but it's not the best practice, according to what I've read. How can I pass a function as a parameter in JavaScript?
You just need to remove the parenthesis:
addContact(entityId, refreshContactList);
This then passes the function without executing it first.
Here is an example:
function addContact(id, refreshCallback) {
refreshCallback();
// You can also pass arguments if you need to
// refreshCallback(id);
}
function refreshContactList() {
alert('Hello World');
}
addContact(1, refreshContactList);
If you want to pass a function, just reference it by name without the parentheses:
function foo(x) {
alert(x);
}
function bar(func) {
func("Hello World!");
}
//alerts "Hello World!"
bar(foo);
But sometimes you might want to pass a function with arguments included, but not have it called until the callback is invoked. To do this, when calling it, just wrap it in an anonymous function, like this:
function foo(x) {
alert(x);
}
function bar(func) {
func();
}
//alerts "Hello World!" (from within bar AFTER being passed)
bar(function(){ foo("Hello World!") });
If you prefer, you could also use the apply function and have a third parameter that is an array of the arguments, like such:
function eat(food1, food2) {
alert("I like to eat " + food1 + " and " + food2 );
}
function myFunc(callback, args) {
//do stuff
//...
//execute callback when finished
callback.apply(this, args);
}
//alerts "I like to eat pickles and peanut butter"
myFunc(eat, ["pickles", "peanut butter"]);
Example 1:
funct("z", function (x) { return x; });
function funct(a, foo){
foo(a) // this will return a
}
Example 2:
function foodemo(value){
return 'hello '+value;
}
function funct(a, foo){
alert(foo(a));
}
//call funct
funct('world!',foodemo); //=> 'hello world!'
look at this
To pass the function as parameter, simply remove the brackets!
function ToBeCalled(){
alert("I was called");
}
function iNeedParameter( paramFunc) {
//it is a good idea to check if the parameter is actually not null
//and that it is a function
if (paramFunc && (typeof paramFunc == "function")) {
paramFunc();
}
}
//this calls iNeedParameter and sends the other function to it
iNeedParameter(ToBeCalled);
The idea behind this is that a function is quite similar to a variable. Instead of writing
function ToBeCalled() { /* something */ }
you might as well write
var ToBeCalledVariable = function () { /* something */ }
There are minor differences between the two, but anyway - both of them are valid ways to define a function.
Now, if you define a function and explicitly assign it to a variable, it seems quite logical, that you can pass it as parameter to another function, and you don't need brackets:
anotherFunction(ToBeCalledVariable);
There is a phrase amongst JavaScript programmers: "Eval is Evil" so try to avoid it at all costs!
In addition to Steve Fenton's answer, you can also pass functions directly.
function addContact(entity, refreshFn) {
refreshFn();
}
function callAddContact() {
addContact("entity", function() { DoThis(); });
}
I chopped all my hair off with that issue. I couldn't make the examples above working, so I ended like :
function foo(blabla){
var func = new Function(blabla);
func();
}
// to call it, I just pass the js function I wanted as a string in the new one...
foo("alert('test')");
And that's working like a charm ... for what I needed at least. Hope it might help some.
I suggest to put the parameters in an array, and then split them up using the .apply() function. So now we can easily pass a function with lots of parameters and execute it in a simple way.
function addContact(parameters, refreshCallback) {
refreshCallback.apply(this, parameters);
}
function refreshContactList(int, int, string) {
alert(int + int);
console.log(string);
}
addContact([1,2,"str"], refreshContactList); //parameters should be putted in an array
You can also use eval() to do the same thing.
//A function to call
function needToBeCalled(p1, p2)
{
alert(p1+"="+p2);
}
//A function where needToBeCalled passed as an argument with necessary params
//Here params is comma separated string
function callAnotherFunction(aFunction, params)
{
eval(aFunction + "("+params+")");
}
//A function Call
callAnotherFunction("needToBeCalled", "10,20");
That's it. I was also looking for this solution and tried solutions provided in other answers but finally got it work from above example.
Here it's another approach :
function a(first,second)
{
return (second)(first);
}
a('Hello',function(e){alert(e+ ' world!');}); //=> Hello world
In fact, seems like a bit complicated, is not.
get method as a parameter:
function JS_method(_callBack) {
_callBack("called");
}
You can give as a parameter method:
JS_method(function (d) {
//Finally this will work.
alert(d)
});
The other answers do an excellent job describing what's going on, but one important "gotcha" is to make sure that whatever you pass through is indeed a reference to a function.
For instance, if you pass through a string instead of a function you'll get an error:
function function1(my_function_parameter){
my_function_parameter();
}
function function2(){
alert('Hello world');
}
function1(function2); //This will work
function1("function2"); //This breaks!
See JsFiddle
Some time when you need to deal with event handler so need to pass event too as an argument , most of the modern library like react, angular might need this.
I need to override OnSubmit function(function from third party library) with some custom validation on reactjs and I passed the function and event both like below
ORIGINALLY
<button className="img-submit" type="button" onClick=
{onSubmit}>Upload Image</button>
MADE A NEW FUNCTION upload and called passed onSubmit and event as arguments
<button className="img-submit" type="button" onClick={this.upload.bind(this,event,onSubmit)}>Upload Image</button>
upload(event,fn){
//custom codes are done here
fn(event);
}
By using ES6:
const invoke = (callback) => {
callback()
}
invoke(()=>{
console.log("Hello World");
})
If you can pass your whole function as string, this code may help you.
convertToFunc( "runThis('Micheal')" )
function convertToFunc( str) {
new Function( str )()
}
function runThis( name ){
console.log("Hello", name) // prints Hello Micheal
}
You can use a JSON as well to store and send JS functions.
Check the following:
var myJSON =
{
"myFunc1" : function (){
alert("a");
},
"myFunc2" : function (functionParameter){
functionParameter();
}
}
function main(){
myJSON.myFunc2(myJSON.myFunc1);
}
This will print 'a'.
The following has the same effect with the above:
var myFunc1 = function (){
alert('a');
}
var myFunc2 = function (functionParameter){
functionParameter();
}
function main(){
myFunc2(myFunc1);
}
Which is also has the same effect with the following:
function myFunc1(){
alert('a');
}
function myFunc2 (functionParameter){
functionParameter();
}
function main(){
myFunc2(myFunc1);
}
And a object paradigm using Class as object prototype:
function Class(){
this.myFunc1 = function(msg){
alert(msg);
}
this.myFunc2 = function(callBackParameter){
callBackParameter('message');
}
}
function main(){
var myClass = new Class();
myClass.myFunc2(myClass.myFunc1);
}

How to call a function from outside the main function?

I am currently trying to learn javascript and what I want to achieve is to call a function, from outside the main function. For a better idea, I left the code which I am currently exercising on. I will be extremely grateful If someone can explain to me why exactly this function is not working. Thank you in advance.
function One_Main(){
function Alpha(){
console.log("Alpha");
}
}
One_Main();
function Two_Main(){
Alpha();
}
Two_Main();
Alpha() is in the scope of One_Main, you can't see it from the global scope. To call Alpha() from outside of One_Main you need to declare it outside of that function.
function Alpha(){
console.log("Alpha");
}
function One_Main(){
Alpha();
}
One_Main();
function Two_Main(){
Alpha();
}
Two_Main();
It's not working because Alpha is not visible outside of One_Main.
To make it visible, you can define One_Main as an object, then make Alpha a property of One_Main.
To fix your code, do this:
function One_Main() {
this.Alpha = function() {
console.log("Alpha");
}
}
// Make it visible
Alpha = new One_Main().Alpha;
function Two_Main() {
Alpha();
}
Two_Main();
ES2015 Style
class One_Main {
constructor() {}
static Alpha() {
console.log("Alpha");
}
}
// Make it visible
Alpha = One_Main.Alpha;
function Two_Main() {
Alpha();
}
Two_Main();
As a simple property in pure JS
function One_Main() {}
One_Main.Alpha = function() {
console.log("Alpha");
}
// Make it visible
Alpha = One_Main.Alpha;
function Two_Main() {
Alpha();
}
Two_Main();
You might want to read about scoping in javascript to understand the problem.
https://scotch.io/tutorials/understanding-scope-in-javascript
The function Alpha is not visible inside the Two_Main function
PS: Debugging is useful to learn more about the error. In Chrome you can right click and select Inspect element and look at the console to debug javascript.
Checkout https://raygun.com/blog/debug-javascript/ for more information
I dont know what tutorial are you studying, maybe you are reading about currying method, if that is the case, you can make:
function One_Main(){
function Alpha(){
console.log("Alpha");
}
return Alpha;
}
One_Main();
function Two_Main(){
One_Main()();
}
Two_Main();

Can I put a method as the argument in the setInterval function?

Preety straight forward question, though I can't find the answer anywhere
I tried these two ways:
setInterval(function(){object/*or this*/.method()},500)
and
setInterval('object/*or this*/.method()',500)
setInterval in fact expects a method as the first argument, though there is an alternative syntax where the first argument can be a string of code (not recommended by most)
If you're having issues with that code, it may have to do with the scope of 'this'
setInterval(function(){this.method()},500)
In the above code, 'this' will refer to the closure itself, and wouldn't be the same as 'this.method' occurring outside of that closure. For example, the following would work:
function MyClass() {
this.thingy = 'yep this is a thingy'
}
var myClass = new MyClass()
// Will log 'MyClass yep this is a thingy'
setInterval(function() { console.log('MyClass', myClass.thingy) }, 1000)
Whereas the following will not work (presuming instantiating the object and calling foo()):
function MyOtherClass() {
this.thingy = 'also a thingy'
}
// Will log 'MyOtherClass undefined'
MyOtherClass.prototype.foo = function() {
setInterval(function() { console.log('MyOtherClass', this.thingy) }, 1000)
}
The second example will work if we get around using 'this' within the closure (presuming instantiating the object and calling bar()):
MyOtherClass.prototype.bar = function() {
var that = this
setInterval(function() { console.log('MyOtherClass', that.thingy) }, 1000)
}
Also be sure that setInterval is being passed the name of a function:
setInterval(someFunction, 500)
rather than executing a function as an argument
setInterval(someFunction(), 500)
This last line of code is usually a mistake, unless someFunction() returns a function itself ;)
The difference between your 2 ways for passing a function to setInterval is whether you want to pass your function as refrence of just copy of it. Allow me to explain it by example:
-1 Referring(demo):
var obj = {
testMethod: function () {
console.log('function (testMethod): intial output');
}
}
setInterval(function () {
obj.testMethod()
}, 1000);
obj.testMethod = function () {
console.log('function (testMethod): changed output');
}
when you run this code, the result 'll be execution of the modified version of testMethod. Because here you dont copy the function! Instead, you refer to it. So whenever function implementation is changed, the last modified version is executed.
-2 Copying(demo):
var obj = {
testMethod: function () {
console.log('function (testMethod): intial output');
}
}
setInterval(obj.testMethod, 1000);
obj.testMethod = function () {
console.log('function (testMethod): changed output');
}
Here all you do is you are passing a copy of the last defined version of the function testMethod to setInterval. So whatever changes you do to testMethod, the result of setInterval will not be changed.

Categories