Using the each function to pass results to another function - javascript

I guess this might be a noob question but when using the each iterator, is it possible to send the results to a predefined function? I have only seen examples where the function is defined in the parantheses. Here is what I would like to do:
function setCheckboxes(key, value) {
....some code....
}
context.find('input[type="checkbox"]').each(setCheckboxes(key, value));
Is this possible? Or do I have to implement it this way:
context.find('input[type="checkbox"]').each(function(key, value) {
....some code....
});

You can just give the function reference as the callback for each.
context.find('input[type="checkbox"]').each(setCheckboxes);
In your callback setCheckboxes key will be the index and value will be the element (DOM element).
This is no different from writing an anonymous function, where you get the same 2 arguments, in this case you are just giving a reference to a function that expects the same 2 arguments. So the context inside the callback i.e setCheckboxes will be the DOM element.

You should be able to do:
function setCheckboxes(key, value) {
....some code....
}
context.find('input[type="checkbox"]').each(function(key, value){
setCheckboxes(key, value);
});

Related

Passing an array.push function in javascript

I have a problem passing an array.push function in javascript having a code like this:
const array = [];
addToArray("works", (e) => array.push(e));
addToArray("notWorks", array.push);
doConsoleLog("hello", console.log);
function addToArray(element, pushFn) {
pushFn(element);
}
function doConsoleLog(message, log) {
log(message);
}
Just curious how's that first call of addToArray works, but second causes TypeError: Cannot convert undefined or null to object. How is it possible? Type of array.push is a function. It is not possible to pass functions directly like in the case of console.log above, which works pretty well?
push is a method of array. When invoked, it uses this as a reference to the object it is being called on. If you pass it around like a normal function, you will lose that reference, the method will use the value of this defined at the moment of the call (inside addToArray, this is probably document.window), and will therefore fail.
In order to pass around a method, you need to bind it to the object you want it to operate on, in this case array. This is true for any object method in JavaScript. Function.prototype.bind() exists exactly for this purpose: it "binds" a function (in this case your method) to a given value of this, in order to work correctly.
const array = [];
addToArray("now it works", array.push.bind(array));
// or
addToArray("now it works", Array.prototype.push.bind(array));
function addToArray(element, pushFn) {
pushFn(element);
}
Once you pass a function like you did in the second case, it executes itself immediately, and array.push doesn't really mean something.
A callback function should be executed later on in the outer function.
Unlike the second example, in the first one you don't execute the function immediately, but only when you call it inside the outer function.
Your code have a lot of mistakes. What exactly should do this code? if you want to push new items in array use spread operator
const array = [...[], "works", "notWorks"]
const array = [];
addToArray("works", (e) => array.push(e));
addToArray("notWorks", array.push);
doConsoleLog("hello", console.log);
function addToArray(element, pushFn) {
pushFn(element); //function must return something
}
function doConsoleLog(message, log) {
log(message); //function must return something
}

It there a way to leave a function argument undeclared

I am looking for a way to declare a function without declaring one or more parameters. This would be used in cases where you're implementing a function where you don't care what the value of (for instance) the first argument is.
For example, given this function:
function foo(this_arg_is_unused, important_arg) {
doSomethingWith(important_arg);
}
Is there some way to declare it more like this?
function foo( , important_arg) {
doSomethingWith(important_arg);
}
I realize I could easily do this:
function foo() {
doSomethingWith(arguments[1]);
}
However that starts becoming less readable and it would be more difficult to (for instance) use fn.js to curry the arguments.
I'm currently thinking perhaps I could just use a visual mnemonic to indicate the argument is not used:
function foo(ø, important_arg) {
doSomethingWith(important_arg);
}
However this may also have readability issues.
Real world example:
The callback function used by jQuery's .each() takes two arguments, the first is either the index or property name in the array/object and the second is the value. To manipulate some div elements you might do something like this:
$($('div').each(function(index, value) {
console.log(value); // equivalent to doSomething(this)
}));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Nothing here</div>
Using an arrow function (where using arguments[] is not possible)
$($('div').each((ø, value) => console.log(value)));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Nothing here</div>
It there a way to leave a function argument undeclared?
No. Just omitting it is a syntax error.
Perhaps I could just use a visual mnemonic to indicate the argument is not used
Yes, that's the right way. The idiomatic name for unused parameters is the underscore _, known from other languages where it has a special meaning (and can even be used multiple times):
function foo(_, important_arg) {
Real world example: the callback function used by jQuery's .each()
Yes, jQuery has messed up the arguments order of the callback, usually the value goes first. In jQuery, the value goes in the zeroeth argument - the this value, so idiomatic jQuery is
$('div').each(function() {
console.log(this);
});
If you cannot use this for some reason, you will have to use the second parameter; there's no way around this.
You can't leave empty spaces in function arguments. A placeholder argument works well.
If you don't want to do that, you could write a higher-order function that wraps a function to expect a first, throwaway argument:
function withExtraArg(f, thisValue = null) {
return (x, ...args) => f.call(thisValue, ...args);
}
And write your function taking a natural number of arguments:
function withExtraArg(f, thisValue = null) {
return (x, ...args) => f.call(thisValue, ...args);
}
// your function
function log (value) {
console.log(value)
}
$($('div').each(withExtraArg(log)));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Nothing here</div>

Javascript Window Function Pass "this" as Parameter

I am looping thru a JSON object and I want to set clicks on fields based on a function named in the JSON Object. The function called will by window[] will be parameterised instead of hardcoded.
for (var key in JSONOBJ) {
func = window["minRule"](this);
$('#'+ key).click(func);
}
The function being called is
function minRule(elem){
alert(elem.name);
}
and I want it applied to
<input type='text' name='FIELDINJSONOBJECT' id='FIELDINJSONOBJECT'/>
However when I refresh the page the function is being called for some reason and hasnt binded to the click. Also the alert(elem.name) is returning undefined. How do I pass this as the parameter to a function called with window[$FUNCTIONAME]
Regards,
Tom
I think what you are looking for is
$.each(JSONOBJ, function(key, value){
$('#'+ key).click(function(){
window["minRule"](value);
});
})
In your case you are invoking the function minRule in the loop with parameter this where it points to the current functions scope and the value returned by it (in this case undefined as the click handler), that is the reason it is not working

Setting a JavaScript function as a parameter for use with another function?

I'm learning lots of javascript these days, and one of the things I'm not quite understanding is passing functions as parameters to other functions. I get the concept of doing such things, but I myself can't come up with any situations where this would be ideal.
My question is:
When do you want to have your javascript functions take another function as a parameter? Why not just assign a variable to that function's return value and pass that variable to the function like so:
// Why not do this
var foo = doStuff(params);
callerFunction(foo);
//instead of this
callerFunction(doStuff);
I'm confused as to why I would ever choose to do things as in my second example.
Why would you do this? What are some use cases?
Here's yet another example. Does some formatting operations on an array:
function pctFormatter(num) {
return num + '%';
}
function centsFormatter(num) {
return num + '.00';
}
function formatThisArray(array, formatter) {
var output = [];
for(var i = 0; i < array.length; i++) {
output.push( formatter(array[i]) );
}
return output;
}
formatThisArray([1,2,3], pctFormatter);// returns ['1%', '2%', '3%']
formatThisArray([1,2,3], centsFormatter);// returns ['1.00', '2.00', '3.00']
Handlers/listeners are a good example.
More generally, you can pass a function f as a parameter to function g when you don't know yet if g will need to call f, how many times it will need to call it, and/or with which parameters.
Examples:
sort algorithms: comparison function
regular expressions: replace function
callbacks (e.g. event handlers)
You'd do it when you don't have the params to pass, but the callerFunction() does.
A callback to an AJAX request is one use case.
function myCallback(response) {
// do something with the response
}
myAJAX('http://example.com/foo.json', myCallback)
This lets myAJAX to the work of making the request, and waiting for the response. Then it invokes myCallback and passes it the response when that response finally arrives.
// Why not do this
var foo = doStuff(params);
callerFunction(foo);
//instead of this
callerFunction(doStuff);
First example will run the function doStuff with params and the assign the result to foo. callerFunction will be called with parameter foo (which is now a result of dooStuff);
Second example will call callerFunction and pass doStuff as a parameter. The callerFunction might or might not call the doStuff.
Well, sometimes you don't know who the caller of a function will be until it's called - this precludes passing pre-calculated values.
A couple of examples that spring to mind are:
(a) setTimeout or setInterval - you want to call a specific function after a specified period, either one-shot, or repeatedly. If the function called returned a value that had a dependance on time, there are instances where you couldn't possibly pre-calculate the value - it needs to be done at the scheduled time. So, we tell the functions which of our own functions to call at the specified time.
(b) when loading (or at least attepmpting to) various resources. We can give the element a function that is to be executed when loading is successful, and another when it fails. You don't actually know when the effort to load a resource has finished until either of these two (user-supplied) functions are called. In the case of many resources, this is where you increment the counters that maintain the number of successful/failed load attempts.
(c) the NodeList returned by calls to getElementsByClass or getElementsByTagName. It's not an actual (javascript native) Array object. As such, you can't call the forEach method on it, like you can with an array. To get around this, I use the following helper function:
// getElementsByTagName, getElementsByClass - both return a NodeList
// it is accessed in the same way as an array - with the [] operators, but it's
// not an array object - this is a function that allows us to still iterate through it
// in much the same way.
function forEachNode(nodeList, func)
{
var i, n = nodeList.length;
for (i=0; i<n; i++)
{
func(nodeList[i], i, nodeList);
}
}
This allows me to get a list of nodes and then call some user-defined function on each of them. In use, it looks like this:
var allAnchors = document.getElementsByTagName('a');
forEachNode(allAnchors, showNodeTextVal);
function showNodeTextVal(curElem, curIndex, origList)
{
alert(curElem.innerText);
}
Or more simply:
var allAnchors = document.getElementsByTagName('a');
forEachNode(allAnchors, function(curElem){alert(curElem.innerText);} );
This is a much clearer, less error-prone situation than it would be if we didn't use this helper function. To achieve the same functionality, we'd need to code the following:
var nodeList = document.getElementsByTagName('a');
var i, n = nodeList.length;
for (i=0; i<n; i++)
{
alert(nodeList[i].innerText);
}
Most common case is handlers in JQuery:
function clickHandler(e){
// handle click on e.Target
}
$("#button").click(clickHandler);
$(function(){
// do ready state initialization
});
callerFunction(doStuff);
with this code you give a "pointer" of the function doStuff to the function callerFunction
you can use it like this:
function callerFunction(doStuff) {
var x = doStuff(...);
...;
}
you can so use the function in the function and not only the return value of doStuff.
greetings!
When do you want to have your javascript functions take another
function as a parameter?
It's useful for callbacks for example:
function add( a, b, callback ) {
callback( a, b );
return a + b;
}
function added( a, b ) {
alert('You just added two numbers: '+ a +' and '+ b);
}
alert( add( 1, 2, added ); // Will alert the message and then the result.
This a very simple example but it's very useful with asynchronous functions so you can run code after it has finished without interrupting the script.
You need to pass functions themselves, not return values, when you want to have your code really deal with functions as functions - code to execute. Consider this pseudo-code example:
function saveToLocalStorage(data) {...//saves to local storage}
function saveToServer(data) {...//saves via AJAX to server}
function saveToAmazonS3(data) {.../saves to Amazon S3 }
function multiSave(data, saverFunctions) {
saverFunctions.forEach(function (saverFunction) {
saverFunction(data);
});
}
multiSave({user: "tim"}, [saveToLocalStorage, saveToServer, saveToAmazonS3]);
In this case, I want the actual functions themselves to be passed around and for other code to later invoke them. When we do this, a function such as multiSave is called a higher-order function because it deals with other functions directly. Because of the way multiSave works, I can easily put some checkboxes in the UI next to local/server/S3 and allow the user to choose where their data goes in a way that would be less elegant if I was unable to pass functions around as arguments.
When you're passing a function as an argument, that argument is not the return value of that function, but it's the function itself, you can call it as much as you like, with any argument you like, or you can assign it to an event. You say you want some practical use cases, here's a short list of very common situations, all requiring a function to be passed as an argument.
Let's take a look at your average jQuery code, and count the number of times where a function is passed as an argument:
$(document).ready(function()//<-- 1
{
$('#foo').on('click',function()//2
{
});
$.each(something,function()//3
{});
//and so on
});
If you don't use jQuery, then try event delegation
document.body.addEventListener('click',function(e)
{
e = e || window.event
console.log('This function was passed as an argument to the addEventListener method');
},false);
Or even the simple Array.prototype.sort function (/method):
anArray.sort(function(a,b)
{
return (a > b ? 1 : -1);
});
Or in cases where you need to make an ajax call, instead of creating a new XMLHttpRequest object on the spot, you might want a single function that sets the xhr object up, and pass the url, data and onreadystatechange callback as arguments:
function makeXHR(url,data,callback)
{
try
{
var xhr = new XMLHttpRequest();
}
catch(e)
{
//etc...
}
xhr.onreadystatechange = callback;
}
makeXHR('some/url','foo=bar',function()
{
if (this.readyState === 4 && this.status === 200)
{
//do stuff
}
});
In all of these examples, I've created the functions in-line, of course referencing a function (by just passing its name) works just fine, too:
makeXHR('some/url','foo=bar',defaultXhrCallback);
These are just a few of thousands of use cases where you can/have to pass a function as an argument to another function

jshashtable.each use existing function

So I have a Hashtable defined (with jshashtable.js):
hashy = new Hashtable();
I put some keys in it:
hashy.put("hi", "yay");
hashy.put("hello", "yes");
Now I want to iterate it with .each, as the doc says:
hashy.each(iterator());
But it says 'object is not a function'
Now, if I do this:
hashy.each(function() { });
It works, but is there a way to call an existing function this way?
I just realized the most obvious answer would be to do:
hashy.each(function() { iterator(); });
Assuming your iterator function is something like the following:
function iterator(key, value) {
// Do something with key and/or value
}
... then just pass the function in without the parentheses. With the parentheses, you're executing the function immediately (just once) and passing the returned value into each(), which is probably not what you intended.
hashy.each(iterator);

Categories