I've got a two-part question.
One: can I use the last variable I set to update the value on the line after if (!last) {? i.e., something like last = size;?
var j$ = jQuery.noConflict();
function updateCount() {
var self = j$(this),
last = self.data('last'),
size = self.val().length,
span = j$('.currentCount');
if (!last) {
self.data('last', size);
} else if (last != size) {
span.text(size);
self.data('last', size);
}
}
j$('textarea[id$=textBody]').on('propertychange change click keyup input paste', updateCount);
Secondly, can I chain my .on('propertychange ... line to have updateCount run as soon as the script is loaded?
Question 1:
No, you can not use simply the assignment to the variable because there is no data-binding in jQuery. So updating last variable will never update the data-last of the jQuery object.
Question 2:
This is what I am used to do:
j$('textarea[id$=textBody]').on('propertychange change ...', updateCount).change();
Where change() automatically triggers the function.
For Q1: No you can't. If you want data binding to work, you can try AngularJS where 2 way data binding between UI and model is possible.
Q2: My solution would be something like this using immediate function
$('textarea[id$=textBody]').on('propertychange change click keyup input paste', (function(){
updateCount();
return updateCount;
}()));
The last variable has a copy of the value in self.data('last'), it is not a pointer, so you would have to do something like this:
last = size;
self.data('last', last);
For the second question, you can trigger the event or just call the function:
j$('textarea[id$=textBody]').trigger('propertychange');
// or
j$('textarea[id$=textBody]').each(updateCount);
Been trying to instantiate an object (called "isSize" below) and assign it to another existing variable (called "sizeObject"), here is the first object ("isSize") within a function:
function Size(isSize) {
this.isSize = 80;
setSize(this.isSize);
}
And here's the second variable of which I want to assign the previous variable to:
var sizeObject;
I've been trying various ways such as the following:
function createSize(isSize){
var isSize = new sizeObject();
}
Anyone got any ideas? Many thanks
If I understand your comment correctly, here is what you are looking for:
// this is the constructor of the `Size` class
function Size() {
this.isSize = 80;
}
function createSize() {
// add this line:
var sizeObject = new Size();
}
It's very hard to understand quite what you're asking, but this:
var sizeObject = new Size(20);
...will create a new object with a isSize property on it with the value 20 if you change Size to:
function Size(initialSize) {
this.isSize = initialSize;
}
(E.g., so it actually uses the argument you give it, rather than using an hardcoded 80.)
Size in the above is a constructor function. You use constructor functions via new.
Lets consider this example:-
function X(){
var Y = function(arg1,arg2){
document.write(arguments.length);
document.write(arg2);
};
Y(arguments);
}
x(1,2,3,4,5);
/*Outputs 1 and undefined respectively.
Because here i am actually passing an array like-object to Y. */
By using apply here i am getting the desired results.
function X(){
var Y = function(arg1,arg2){
document.write(arguments.length);
document.write(arg2);
};
Y.apply(this,arguments);
}
x(1,2,3,4,5) //outputs 5 and 2
I want to create an apply like method that takes an Array of argument and invoke that function by passing arguments as seperate parameter values.
Like:
var arr=[1,2,3,4];
Y.apply_like_method(arr);
//and returns like Y(1,2,3,4)
Given this code:
var arr=[1,2,3,4];
Y.apply_like_method(arr);
//and returns like Y(1,2,3,4)
To make that work:
Function.prototype.apply_like_method = function(args) {
return this.apply(this, args);
}
Disclaimer: For illustration purposes only.
In other words, there's no way around .apply().
Just for shits and giggles using eval.
function myApply(fun, ar){
var i, r = [];
for(i=0; i<ar.length; ++i)
r[i] = 'ar['+i+']';
eval('fun('+r.join(',')+');');
}
You want to use the call method instead. See the MDN. What you are describing though is a hybrid of the call method and apply method; you want the ability to supply parameters individually, but to supply them to the function as an array. That, to my knowledge, doesn't exist currently and it would be easier to use apply/call as it was originally intended, or use a javascript object to pass the params into the 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
Here's the problem - I know function by name (and that function has already been loaded form an external script), but I don't have an actual function object avail for me to call. Normally I would call eval(function_name + "(arg1, arg2)"), but in my case I need to pass an object to it, not a string.
Simple example:
var div = document.getElementById('myDiv')
var func = "function_name" -- this function expects a DOM element passed, not id
How do I execute this function?
Thanks!
Andrey
Never use eval, it´s evil (see only one letter difference)
You can simply do:
var div = document.getElementById('myDiv');
var result = window[function_name](div);
This is possible because functions are first class objects in javascript, so you can acces them as you could with anyother variable. Note that this will also work for functions that want strings or anything as paramter:
var result = window[another_function_name]("string1", [1, "an array"]);
You should be able to get the function object from the top-level window. E.g.
var name = "function_name";
var func = window[name];
func( blah );