So in previous questions I've been told to call/execute/start functions like thisFunc; instead of thisFunc();.
And I've found that sometimes that works and sometimes it doesn't.
<script type='text/javascript'>
var valgo = 0;
var thing = "";
var lastPost = document.getElementById(<? echo $_SESSION['countything']; ?>);
lastPost.style.opacity = valgo;
function valgogoer(thing){
valgo += .05;
if (lastPost.style.opacity < 1){
lastPost.style.opacity = valgo;
}
}
setInterval(function(){valgogoer(<? echo $_SESSION['countything']; ?>)}, 50);
// Somethings are leftover from when I was messing with it, like the parameter thing.
</script>
In this code (and please tell me if it's awful), because I'm using setInterval to call a function with a parameter, I found through research it must be called the way it is above.
So two questions
When am I actually supposed to use () in calling functions?
In the code above, how can I make it so that it stops executing that function after the opacity hits 1. Currently it's restrained to 1, but it's still being called, and I've got a feeling it's better to stop the function being called, than to have it being called but not doing anything.
Thanks!
You use the brackets when you want to call the function. But if just wanna pass the content of the function, you do not. Examples:
var a = function(){
return "I'm a function";
}
var b = a;//Equals to function(){return "I'm a function";}
var c = a();//Equals to "I'm a function"
In event handlers, you do not use the brackets because you have to say to the browser to execute the content of the function. If you put them, the browser will call the return value of the function, which may cause an error:
var a = function(){
alert("Welcome to my site");
}
window.onload = a();//Wrong, equals to undefined, since the a function doesn't return any value
window.onload = a;//Correct, calls the function a when the event is fired
This same thing happens when you call the setInterval method with a function as the parameter. That's why the brackets are so important
You use thisFunc() when you want to call the function. You use thisFunc when you want a reference to the function as a value.
When your function has no parameter, you can use the reference for a callback:
function thisFunc() {
// do something
}
window.setTimeout(thisFunc, 1000);
When your function has a parameter, you need to wrap it in another function to call it with the parameter value:
function thisFunc(param1) {
// do something
}
window.setTimeout(function(){ thisFunc(42); }, 1000);
You can of course wrap a parameterless function in a function too:
function thisFunc() {
// do something
}
window.setTimeout(function(){ thisFunc(); }, 1000);
You don't need to use an anonymous function to wrap a function, you can use a named function and get the reference to that:
function thisFunc(param1) {
// do something
}
function callFunc() {
thisFunc(42);
}
window.setTimeout(callFunc, 1000);
You use () when you want another function to execute your function
function log(arg) { console.log(arg); }
setTimeout(log, 1000) // Logs undefined after 1 second
log("hi"); // logs the String hi
The function is reusable so you could actually use it yourself
function logUsingTheLogMethod( callback ) {
if ( typeof callback === "function" ) {
callback( "This will log to the console!" );
callback( log === callback ); // Logs true
}
}
logUsingTheLogMethod( log );
This is a common pattern in JS, to use functions as callbacks in methods
Say you had some functions that did math, but you don't want to write a logging method for all of them.
function add(a,b,fn) {
if ( fn === log ) {
fn( a + b );
}
}
function subtract(a,b,fn) {
if ( fn === log ) {
fn( a - b );
}
}
add(1, 2, log); // logs 3
subtract(5, 4, log) // logs 1
or modify the function so it ensures it's a function instead of the log function and you can do anything with the response
function add(a,b,fn) {
if ( typeof fn === "function" ) {
fn( a + b );
}
}
// answer is automatically passed in by the calling add method
add( a, b, function ( answer ) {
// do ssomething with the answer
alert( answer );
});
Related
why this code run perfectly
function remember(number) {
return function() {
return number;
}
}
const returnedFunction = remember(5);
console.log( returnedFunction() );
// 5
but this code give me error
function remember(number) {
return number;
}
const returnedFunction = remember(5);
console.log( returnedFunction() );
// returnedFunction is not a function
In the first example, your function remember returns another function, which you then you can execute. In the second example, your function remember returns a number. That's why returnedFunction() runs fine in the first case, but throws an error in the second.
'use strict';
let worker = {
someMethod() {
return 4;
},
slow(x) {
return x * this.somemethod();
}
};
function wrapper(func) {
return function(x) {
let result = this.func(x); // **
return result;
};
}
worker.slow = wrapper(worker.slow);
alert( worker.slow(2) );
When I run this code I get this error:
TypeError: this.func is not a function
If I replace the problematic line at ** with this:
let result = func.call(this, x);
I get the expected output. In this case it's 8.
I'm wondering why the way it's written is the wrong way to get "this" ie the object worker. In other words, how does the call function get the right object i.e. worker ?
The reason it's failing is that in the problematic line (highlighted with // **), you're effectively calling worker.func(x), which does not exist; You're not referring to the passed in variable at all.
If you add a function (func) to your worker, e.g.
let worker = {
someMethod: function() {
return 4;
},
slow: function(x) {
return x * this.somemethod();
},
func: function (x) {
return x * 10;
}
};
And call as above e.g.
worker.slow = wrapper(worker.slow);
console.log( worker.slow(2) );
You'd find it works, though this is not what you really want!
In JavaScript, any function call obj.f(ArgumentList) will be desugared into f.call(obj, ArgumentList...)(see ecma-262 7.3.12)
When wrapper(worker.slow) got a call, the function slow is passed into the wrapper and it produces another function which captured func argument. However, that function returned by wrapper is not called yet.
At a moment of the function call alert( worker.slow(2) )
func mean the argument that got captured in the closure and func.call(this, x) means it will call that function with the current caller, which is worker.
Therefore, `func.call(this,x)` will be `func.call(worker, x) `
which works because `func` exists in the closure.
while this means the reference to a current caller to the function(x){ ... }
Hence, `this.func(x)` will be `worker.func(x)`
which `func` does not exist in `worker`.
if you try to insert console.log(func) and console.log(this)
in that function, you will see the difference.
Is it possible to pass a callback function that does not exist yet? My goal is to have a common function that will wait for another callback function to exist, when it does exist, it should execute it. This is what I have so far, but I can't figure out how to pass the function in that doesn't exist as a function yet.
function RunTemplateFunction(callback, userInfo) {
if ($.isFunction(callback)) {
callback(userInfo);
} else {
var myInterval = setInterval(function () {
if ($.isFunction(callback)) {
clearInterval(myInterval);
callback(userInfo);
}
}, 200);
}
}
I run the function like this:
RunTemplateFunction(MyFunctionToRun, GetUserInfo());
I get MyFunctionToRun is undefined for obvious reasons, I also tried the workaround of passing the function as a string and then convert the string to a function using eval(). But that throws the same error. I also thought of using the new function(), but that actually creates a new function.
Any help is appreciated. thank you.
If you call RunTemplateFunction by undefined there is no way we can see, is callback is defined or not, as we don't have reference to anything.
If you can modify the declaration to accept object as below, we can achieve what we want
function RunTemplateFunction(options, userInfo) {
if ($.isFunction(options.callback)) {
console.log('called1',userInfo);
options.callback(userInfo);
} else {
var myInterval = setInterval(function () {
if ($.isFunction(options.callback)) {
console.log('Called dynamically!!');
clearInterval(myInterval);
options.callback(userInfo);
}
}, 200);
}
}
var options = {}
RunTemplateFunction(options,{user:122});
options.callback = function(){
console.log("I'm called!!");
}
This will print
Called dynamically!!
I'm called!!
EDIT:
We can also call callback function in following way without setInterval, it will look different but options.callback variable is replaced by template.callMe function and its instantaneous also.
function TemplateRunner(userInfo){
this.callMe = function(cb){
this.templateFunction(cb);
}
this.templateFunction = function(callback){
callback(userInfo);
}
}
var template = new TemplateRunner({user:100})
template.callMe(function(user){
console.log('call me1',user);
});
template.callMe(function(user){
console.log('call me2',user);
})
This will print
call me1 {user: 100}
call me2 {user: 100}
Can I call a timeout function on the returned element in this if statement?
var data = 'some stuff';
if(data){
return jQuery('<div class="thisDiv"></div>').html(data);
}
I've tried the following:
if(data){
setTimeout(function() {
return jQuery('<div class="thisDiv"></div>').html(data);
}, 100);
}
But I get this error in my console:
Uncaught TypeError: Cannot read property 'nodeType' of undefined
The return statement will return from the anonymous function you passed into the setTimeout function, not the function enclosing the scope of the if statement. Try passing a callback into the function containing the if statement, then calling that callback with the data as a parameter.
function delayedReturn(callback) {
if(data) {
setTimeout(function() {
callback(jQuery('<div class="thisDiv"></div>').html(data));
}, 100);
}
}
No. You cannot use setTimeout to delay when a function will return. It is not a sleep function. It puts a function on a queue to run later, it doesn't stop all processing for a period of time.
function a() {
return 1;
}
var x = a();
In the above you have a single function which has a return statement. The value it returns is assigned to x.
function b() {
setTimeout(function c() {
return 1;
}, 1000);
}
var y = b();
Now you have two functions. b has no return statement, so it returns undefined and undefined is stored in y.
b uses setTimeout to call c, and c has a return statement. setTimeout doesn't do anything with return values though, so the return value of c is discarded.
Any time you are dealing with asynchronous functions, you have to do something with the data inside the asynchronous callback (such as call another function and pass the data as an argument). There is no going back, it is too late for that.
You could return a Promise from b though. That would allow other code to use the value of y to bind event handlers that will fire when the timeout expires.
You certainly can, you'd need to remove the return and use a valid selector to target your div.
Something like this would work:
HTML
<div class="thisDiv">test</div>
Javascript:
var data = 'some stuff';
if(data){
setTimeout(function() {
jQuery('.thisDiv').html(data);
}, 100);
}
You can see it working here: https://jsfiddle.net/ckkz1wbf/
Question, Why are you using:
jQuery('<div class="thisDiv"></div>')
Are you try to create an element, if that the case, you could use delay from jquery.
function fn(){
var data = 'some stuff';
if(data){
return jQuery('<div class="thisDiv"></div>').delay(100).html(data);
}
}
Perhaps an odd question but here it goes: I have a function which I call periodically and within that function I need to know which iteration I'm in, or how many times the function has been called. A simplified version of the problem:
jQuery( document ).ready( function(){
setInterval( "myFunction()", 3000 );
});
function myFunction()
{
alert( "I have been called X times" );
}
So, how do I figure out the X in the above code?
Easy version: make a global variable like in codeling's answer. The problem - if some other code also defines a global variable with the same name, you're both in trouble.
Easy extended version - give the variable a crazy name that nobody will ever use: calledTimesED7E69A7B141457CA8908A612E3D7A3A
Clever version: append that variable to an existing global variable. Remember - everything's an object in Javascript!
$(function(){ setInterval(myFunction, 3000); });
function myFunction()
{
myFunction.calledTimes++;
alert( "I have been called " + myFunction.calledTimes + " times" );
}
myFunction.calledTimes = 0;
Traditional version: use scoping to hide that variable.
$(function()
{
var calledTimes = 0;
setInterval(function()
{
calledTimes++;
alert( "I have been called " + calledTimes + " times" );
}, 3000);
});
This hides "myFunction" though, so let's try again with a tricky kind of scoping:
var myFunction = null;
(function()
{
var calledTimes = 0;
myFunction = function()
{
calledTimes++;
alert( "I have been called " + calledTimes + " times" );
}
})();
$(function () { setInterval(myFunction, 3000); });
... and there are a zillion other ways you would hide that variable with scoping. Just pick your favorite.
You could simply use a global variable, which is increased each time you call the function:
var myFuncCalls = 0;
function myFunction()
{
myFuncCalls++;
alert( "I have been called " + myFuncCalls + " times" );
}
As soon as your code gets a little more complex (or if you use a lot of other libraries), you should, however, consider using scoping as shown in the other answers here (best explained in the one by Vilx).
Here's another interesting solution that doesn't use an external variable. The best part about this is you can leave any pre-existing functions untouched and call them as you would normally. That means if you're attempting to "tap in" to an function in an existing library, this will work very well for you. It adds an unobtrusive counter and allows you to continue calling existing functions normally; even with arguments!
// no js library required
// pre-existing function
var a = function(){
console.log("pre-existing function function");
console.log("arguments:", arguments);
};
// add counter func
var addFnCounter = function(target){
var swap = target;
var count = 0;
return function(){
swap.apply(null, arguments);
count++;
console.log("func has been called " + count + " times");
console.log("\n");
};
};
// usage
a = addFnCounter(a);
// call a() as you would normally
a();
a(1,2,3);
a('hello', 'world');
// using your setInterval example
setInterval(a, 3000);
Output
pre-existing function function
arguments: []
func has been called 1 times
pre-existing function function
arguments: [1, 2, 3]
func has been called 2 times
pre-existing function function
arguments: ["hello", "world"]
func has been called 3 times
setInterval output
pre-existing function function
arguments: []
func has been called 4 times
pre-existing function function
arguments: []
func has been called 5 times
pre-existing function function
arguments: []
func has been called 6 times
See it working here on jsfiddle
You'll have to use a closure.
Normally you would use a static variable. in Javascript it would look something like:
jQuery( document ).ready( function(){
setInterval( myFunction, 3000 );
});
var myFunction = (function(){
var count = 0;
return function(){
count++
alert( "I have been called " + count + " times");
}
})();
Demonstration: http://jsfiddle.net/MZQ83/2/
A static variable is cleaner and it won't pollute your outer scope either, compared to a closure or a decorator as in other answers.
var foo = function(){
alert( ++foo.count || (foo.count = 1) );
}
// test
function callTwice(f){ f(); f(); }
callTwice(foo) // will alert 1 then 2
or
callTwice( function bar(){
alert( ++bar.count || (bar.count = 1) );
}); // will alert 1 then 2
the second one is a named anonymous function. And note this syntax:
var foo = function bar(){ /* foo === bar in here */ }
Create a global variable and initialize by zero. then increment by one when myfunction() called. Display that variable instead of X.
ES6 / ES2015
You can use a Proxy for your function utilising the apply() trap:
const addCounter = fn => {
let count = 0; // keep count
//define handler
const handler = {
apply() {
//do something with this counter
console.log(`I have been called ${++count} times `);
return Reflect.apply(...arguments); //call the function normally
}
}
//wrap the function into a proxy that uses the handler and return it
return new Proxy(fn, handler);
}
setInterval( addCounter(myFunction), 1000 );
function myFunction() { //sample operation - move an image
const img = document.querySelector("img");
let offset = img.offsetLeft + 10;
if (offset > 100) //return to start
offset = 0;
img.style.left = `${offset}px`;
}
img {
position: absolute;
}
.as-console-wrapper {
max-height: 45px !important;
}
<img src="https://picsum.photos/150" />
You can use an Immediately Invoking Function Expression (or IIFE) to create a closure around the counter function. You can do it like this with ES6 Arrow functions:
const counterFunction = (() => {
let counter = 0;
return () => console.log(++counter);
})();
counterFunction();
counterFunction();
counterFunction();
Or with normal function expressions:
var counterFunction = (function() {
var counter = 0;
return function() {
console.log(++counter);
};
})();
counterFunction();
counterFunction();
counterFunction();
Read more about IIFEs
Read more about closures
There is an inbuilt function in JS called console.count()
My approach would add a property “count” to the function itself.
Just add one line at the beginning of your function you want to have tracked calls.
function func() {
func.count = (func.count || 0) + 1;
// first time you call the function func.count is undefined so use 0 instead
console.log("hi");
}
func();
console.log(func.count) // 1
func();
func();
func();
console.log(func.count) // 4
Functions are objects in javascript after all. No pollution of global namespace, no wrapping or closures needed, very simple to understand and to write.