Javascript/JQuery: Assign a whole line of code to a function parameter? - javascript

Is it possible to assign a whole line of code to a function parameter? Take this example:
function testFunc(parameter1){
parameter1;
}
testFunc($(".someClass").text("someText"));
When the function is used with that parameter, can the parameter1 be replaced by the line of code?
I'm new with JavaScript and jQuery, so I'm just curious if this is possible. I did not see any questions like this asked before. But if it was asked, a link to the question would be appreciated. Thanks

Sounds like you are inventing the callback :)
Pass an actual function and call it with ();
function testFunc(callback){
callback();
}
testFunc(function(){$(".someClass").text("someText");});

Yes it can be done , as jQuery will eveluate it and return a object.

The key insight here is that a function can be treated like any other variable.
For example:
var i = 1;
var f = function() { console.log('hello!'); };
Here f is a value, just like i is, but you can invoke it just like any other function:
f(); // prints 'hello!' in the console
Because it is a value, you can pass it to another function:
function g(h) { h(); }
g(f); // prints 'hello!' in the console
Take the time to ensure you understand the above code. I've deliberately used vague names so you can learn the mechanics. Let me know if you have any questions.

Arguments aren't assigned to functions, they are passed/sent/[insert other synonym here].
Anything that is an expression (any code which evaluates to some value) can be passed around.
In your exemple $(".someClass").text("someText") is an expression which evaluates to a jQuery object, so you can use this unit of code as a function's argument without any doubt.
However, if you want to pass around some code which has to be executed as part of an existing function's process, you must use a function expression which encapsulates that behavior.
E.g.
function executor(task) {
task();
}
executor(function () {
//code to be executed by the executor
});

Yes you can pass function callback like regular primitive variable
In your case you should check param type before execution
function testFunc(parameter1){
if(typeof parameter1==="undefined"){
//arguments[0] will fall here
console.log("No arguments case. parameter1 not defined")
}
else //function check
if(typeof parameter1==="function"){
//you can parameter function here.
return parameter1();
}
else{
//regular case value or object, other than function types fall here
console.log("not a function, received param type: "+ typeof(parameter1));
return parameter1;
}
}
$(function (){
//let us say you have below vars
var primitiveVar="test",
fun = function(){console.log("function fun call")};
//no args here
testFunc();
//sending primitiveVar
testFunc(primitiveVar);
//below is your call with jQuery Obj
testFunc($(".someClass").text("someText"));
});

Related

Why am I able to define same function twice in javascript?

I have a javascript file in which I write a bunch of jquery functions. I have a function to return the angular scope. I found out that if I were to write the same function twice, the code still executes.
function getngScope()
{
alert(2);
return angular.element($('#data-area')).scope();
}
function getngScope()
{
alert(1);
return angular.element($('#data-area')).scope();
}
When I call getngScope() I get "1" alerted and the scope returned. Why does it have this behavior?
The second definition of an Object overwrites the first one. In general the last definition of an object overwrites all previous definitions.
Functions in JavaScript are Objects:
(function () {}) instanceof Object === true
When you create a new global function f it's equivalent to creating a property in the window object and assigning the function definition to that variable, if you create a function:
function myFun() { console.log('my function') };
and then check the value of window.myFun you'll notice it is the same function as myFun:
window.myFun === myFun // true
You'll also notice that modifying window.myFun changes/overwrites myFun.
E.g.
function myFun() { console.log('myFun') };
myFun(); // Prints: 'myFun'
// Overwrite myFun
window.myFun = function () { console.log('NoFun') };
myFun(); // Prints: 'NoFun'
The second definition of the function takes precedence.
I recommend you read the chapter on Functions from JavaScript: the good parts by Crockford.
functions are data in memory stack, so when you define another function with the same name, it overrides the previous one.
Well obviously you’re not meant to define the same function twice. However, when you do, the latter definition is the only 1 that applies. Try not to do that. Find another way other than giving two functions the same name.
The second function replaced the first function,you could always change this by modifying the name of the function ,if not you can add multiple arguments ..if that is ever needed...and for the explaination to this behaviour,unlike other programming languages javascript doesnt return any errors while being executed..so u can assume that it just corrects itself during the execution by overwriting the function.

Why do you have to wrap a callback with an anonymous function?

My html contains two forms overlapping each other, one used as add form and one as edit form. I use jQuery to show and hide them with the following code:
var editForm = $("#edit-form");
var addForm = $("#add-form");
var showEditForm = function() {
editForm.fadeIn(function() {
addForm.fadeOut();
});
};
var showAddForm = function() {
editForm.fadeOut(function() {
addForm.fadeIn();
});
};
I wanted to make the code more compact so I set the fadeOut() call directly on the fadeOut() callback by doing like this:
var showEditForm = function() {
editForm.fadeIn(addForm.fadeOut);
};
var showAddForm = function() {
editForm.fadeOut(addForm.fadeIn);
};
But this productes the following error Uncaught TypeError: Failed to execute 'animate' on 'Element': Valid arities are: [1], but 4 arguments provided. but why doesn't that work?
That's because calling a function as a property of an object is a special syntax, that calls the function with the object as context.
When you call a function like this:
obj.func();
then this will be a reference to obj inside the function.
If you get the reference to the function, and then call it:
var f = obj.func;
f();
then this will be a reference to the global context, i.e. the window object.
By using editForm.fadeIn(addForm.fadeOut); you get the reference to addForm.fadeOut and send to the fadeIn method. It's no longer associated with the object, so it will be called with the global context instead of the object as context.
You can use the proxy method to associate the function with the object, so that it will be called with the correct context:
var showEditForm = function() {
editForm.fadeIn($.proxy(addForm.fadeOut, addForm));
};
var showAddForm = function() {
editForm.fadeOut($.proxy(addForm.fadeIn, addForm));
};
I suspect the problem is that addForm.fadeOut is being called with a bad combination of arguments, when its passed to the fadeIn function (and vice versa).
The classic example of this pitfall seems to be:
["0", "1", "2", "3"].map(function(i) {return parseInt(i);})
This, works as expected and gives [1,2,3,4] as a result. You might expect that you could shorten this, much as you did above, and write
["0", "1", "2", "3"].map(parseInt);
Unfortunately; this evaluates to [0, NaN, NaN, NaN]. The problem, is that .map calls any function provided it with three arguments: the value, the index, and the array itself, and parseInt takes up to two arguments: the value, but also the radix/base to parse in. (e.g. radix 2 to parse a string as binary) So what actually happens is essentially:
[
parseInt("0", 0), //0, radix is ignored
parseInt("1", 1), //NaN, what is base 1?
parseInt("2", 2), //NaN, 2 isn't valid binary
parseInt("3", 3) //NaN, 3 isn't valid ternary/base-3
]
I suspect, based on the error message, that the same thing is going on here. The "arity" of a function is the number of arguments passed to it, so the error message here says that 4 arguments were provided, when only one was expected.
In general with functions that take optional arguments, you need to be careful before passing them to other functions directly, or else you can't control what arguments it will be called with.
Fiddle: http://jsfiddle.net/jmj8tLfm/
addForm.fadeIn and addForm.fadeOut are being called without specifying the this context that would normally be passed when you call addForm.fadeIn(). Try .bind()-ing the this variable appropriately as follows:
var showEditForm = function() {
editForm.fadeIn(addForm.fadeOut.bind(addForm));
};
var showAddForm = function() {
editForm.fadeOut(addForm.fadeIn.bind(addForm));
};
If you are writing in vanilla js. The reason as to why you need too pass the callback function in an anonymous function has to do with function invocation.
Take a look at this example:
const firstFunc = (callback) => {
setTimeout(function() {
console.log('yes');
console.log(callback())
}, 3000);
}
const secondFunc = () => console.log('great');
firstFunc(function(){
secondFunc();
});
// prints 'yes' 'great' after 3 seconds
> yes
great
When invoking the function, if you pass the callback argument without the parenthesis i.e firstFunc(secondFunc); the callback function will invoke after the first function has finished (just like above) provided inside the first function where the callback gets called is invoking that function. i.e callback(), the () is the important part.
Try omitting the parenthesis inside the first function like this, callback and pass the second function as a callback without the parenthesis firstFunction(secondFunction) notice how you are passing the callback function but it is never being invoked. Your console.log() should look like this.
> yes
() => console.log('great')
So why does this matter...
If you pass the function invocation as firstFunc(secondFunc()) using the setup from the first code snippet. You will notice that the second function prints first then 3 seconds later the first function is invoked.
> great
yes
Given that Javascript is event driven, the invocation of the second function can be found const secondFunc = () => console.log('great'); and it will immediately invoke that function not waiting for the response from the first function. That is what the () did when you invoked secondFunc() inside firstFunc.
By passing an anonymous function that function is never being invoked until it reaches the callback() invocation part. Again using the setup from the first code snippet, try.
firstFunc(function(){
secondFunc();
});
firstFunc(function(){
secondFunc();
}())
See how the second call invokes the secondFunc right away. What is happening is the anonymous function is a wrapper to not invoke your function right away.
Why is this useful?
If secondFunc takes a callback that callback function would not be invoked until the second function has finished executing. You would need to call that callback function inside your second function.
firstFunc(function(){
secondFunc(function(){
thirdFunc();
});
});

What is going on inside the $.each()?

I am stumbling upon a problem that I have seen before, but that I couldn't solve before. I will likely stumble upon it again in the future, so please, someone explain it to me what is going on?
In the partial snippet of javascript below, I have a function that populates a screen, including an order combobox (twitter bootstrap). When I click on one of the order items in that combobox, it should invoke the function clsModCampaigns.blnCompaniesListReload().
For a reason that I don't understand, once inside the '$.each' iterator, the global object reference 'objModCampaigns' is lost? I get a successful alert '1', but not an alert '2'.
Within the $.each, I would like to use 'objModCampaigns.arrOrderBy' instead of 'this.arrOrderBy', but the $.each iterator only seems to work this way. Why is it working this way??
What is going on with 'this', or with variables/objects assigned in the root of the class with 'this'?
Is $.each just special??
function clsModCampaigns(objSetSystem, objSetModuleBase)
{
objModCampaigns = this;
arrOrderBy = {
intID: 'ID',
strName: 'Name'};
[...]
this.blnScreenCampaignInitialize = function (fncSuccess,fncError, intID) {
$.each(this.arrOrderBy, function (strFieldName, strFieldDescription) {
if(strFieldName != 'datDeleted' || objSystem.blnHasPerm("CAMPAIGNS_DELETED")) {
strOrderByID = "ulCampaignsCompaniesListOrderBy" + strFieldName;
$("#ulCampaignsCompaniesListOrderBy").append('<li>'+strFieldDescription+'</li>');
$("#"+strOrderByID).unbind("click").bind("click", function() {
alert("1");
objModCampaigns.arrCurrentShownCompanies.strOrderBy = strFieldName;
objModCampaigns.blnCompaniesListReload();
alert("2");
});
}
});
return true;
};
}
The code you have is
$.each(this.arrOrderBy, ...);
You want
$.each(arrOrderBy, ...);
The reason for it is the this context on that line is different because it is inside a new function this.blnScreenCampaignInitialize.
This is just a part of how JavaScript works
var message = "hello";
function welcome() {
console.log(message);
}
welcome(); // "hello"
P.S. use var
If you don't use var, you'll be attaching all of your vars to the global object.
function hello() {
foo = "bar";
console.log(foo);
};
hello(); // "bar"
console.log(foo); // "bar"
// Holy smokes! `foo` has escaped our `hello` function!
Compare that to
function hello() {
var foo = "bar";
console.log(foo);
}
hello(); // "bar"
console.log(foo); // ReferenceError: foo is not defined
// much better
Now let's see a terrible example
function a() {
b = 5;
return b;
}
function b() {
return "function";
}
console.log(a()); // 5
console.log(b()); // TypeError: number is not a function
This is happening because we didn't use var properly. We first define b as a function but after running a(), b is now set to 5. The second log statement is the equivalent of trying to run 5() because b is no longer a function.
P.P.S. it's pretty unconventional to prefix your vars with str, int, fnc, obj, or cls in JavaScript.
I understand you're a "VB guy" according to your comments, but that's no excuse for bringing your own conventions to the language. I see in your profile that you're fluent in Dutch, English, German, and French. I would recommend you treat learning programming languages much the same as spoken languages: each of them have their own explicit set of rules and conventions.
Here's a heap of free JavaScript books for you. I hope they can help you learn some more basics.
P.P.P.S. Overall, your function is really big as it is, and I can see you already truncated some of the code with your [...]. The whole thing could probably benefit from some better composition.
If you paste all of your code, maybe someone could help you better.
What is going on inside the $.each() ?
Regarding you question title, I'm trying to answer:
// each function in source
function (obj, callback, args) {
//...
}
Check the source of complete $.each function by yourself, you can see any function's source code just by typing the function name in the appropriate text box (the second on top).
Here in each function, the array/object passed in to the each function (the first argument) is being run through a loop and each value is being passed in to the callback (second argument) and that call back is getting executed like:
callback.apply(obj[i], args);
So, the passed callback in the each function is being executed each time the loop occurs ad the current value in the loop is passed as the argument of callback function along with the third argument args.
If your function function clsModCampaigns(){ //... } is a normal function then this inside this function points to global window object. so just use:
$.each(arrOrderBy, ...);
instead of
$.each(this.arrOrderBy, ...);
Because, arrOrderBy is within the direct scope so arrOrderBy is accessible directrly. For example:
function someThing()
{
var x = 'y'; //<-- this scope (everything inside someThing) is
// global for somethingElse inner function
function someThingElse)(x) //<-- possible to use directly
{
}
}
The keyword this behaves differently depending on the context. Check about this on MDN.

Decoding the JavaScript syntax of function(event) {}

I've just come across this little snippet of JavaScript code online:
exampleSocket.onopen = function(event) { // rest of code here;}
And I'm rather confused about the function(event) part, as there are no comments for me to analyze. (Who needs comments when you're designing bi-directional duplex connections? Haha ).
What exactly is function(event)? I always thought you had to define a function name with the function in javaScript. Is this an example of bad code? Additionally, the (argument-parameter-whatever) 'event' isn't even defined anywhere else in the code. Just bam. There it is. Is it necessary to define that, or is (event) a special predefined value? Lastly, if you were to replace (event) with some other value like (e), would the code still work?
Thanks
What you've got there is a function expression, not a function statement.
In a function statement, the name is mandatory. In a function expression it is optional. A function expression with a name is called a named function expression. A function expression without is called an anonymous function
There are a number of subtle differences between all these different methods of declaring a function which are covered in this question; var functionName = function() {} vs function functionName() {}
What you're doing here is setting the onopen property of exampleSocket to a function (expression). Note that you are not running that function at all; you are simply declaring it, and saving a reference to it in exampleSocket.onopen.
This means that someone can execute that function when they want to by calling;
exampleSocket.open();
They can pass a parameter to the function, which you can use inside the function using the event variable (and to answer your question; event is not a special word. You can call it anything).
exampleSocket.onopen = function (event) {
console.log(event); // will log "hello"
};
exampleSocket.open("hello");
The fact the variable event isn't used anywhere will likely mean the developer has named the argument to say "hey, look, you can use this if you want to", but hasn't in his actual implementation.
You don't have to declare the variable yourself. It is declared already by being named in the argument list, and it will be initialized to a value when someone passes an argument when they call the function.
Note that we could define this event handler using a function statement;
function foo(event) {
console.log(event);
}
exampleSocket.open = foo;
... or via a named function expression:
exampleSocket.open = function foo(event) {
console.log(event);
};
To confuse things (don't worry about this; it's a quirk of JavaScript) the name of a named function expression is only available inside the function itself;
exampleSocket.open = function foo(event) {
console.log(event);
console.log(typeof foo); // you'll get "function"
};
console.log(typeof foo); // you'll get "undefined"
... but in a function statement, you'll be able to access the name both inside and out.
I hope this helps... it's a bit of a "brain dump" of information :).
This is an anonymous function. A function is a value, and you can declare and store functions like this. More information on that syntax in this question.
Reading the code (I don't think it needs any more comments than it already has), you are writing a handler function which is called when the socket opens. The socket open event will be passed to the function in the variable event.
Why event? Because the API, whatever it is, expects to pass in an argument that represents the 'open' event.
It's a simple and common JS event-binding function.
It attach an anonymous function to the "open" event of "exampleSocket".
When such event is fired the declared function is called.
Each event may have some parameters, which contain additional info about the event itself.
You can name that parameter the way you want ("event","e" or "anythingElse") and then you can refer to it in the anonymous function body.
You are basically assigning a function value to exampleSocket.onopen, which can then be called elsewhere. Imagine something like this:
var obj = {};
obj.onsomething = function(a, b, c, d) {
alert(a+b+c+d);
};
obj.onsomething(1, 2, 3, 4);
In this case, I gave obj.onsomething a function that takes 4 parameters (should be numbers) and alerts the sum. Then I can just call obj.onsomething with 4 parameters.
So the function that you assign to exampleSocket.onopen will get called when it is appropriate (for example, when the socket is open).
Hope that helps.

callback functions

Man Im trying to understand callback functions. Ive been over many articles and posts here on SO. The explanations seem circular and I think Im actually getting farther from understanding lol. Ive used them apparently in javascript events, but its more a 'memorize these lines' than 'this is whats going on and why' sort of understanding.
So heres my understanding.
Say you have 2 objects, function p() and function k(). You pass function k to p(). p() can then access k's inner variables.
function p(x){
alert(x.n);//5
}
function k(){
this.n = 5;
}
p(k);
Embarrassing how long its taken me to get just this.
Maybe an example will help?
// First, lets declare the function we're going to call
calledFunction = function (callback, arg) {
callback(arg);
};
// Second, lets declare the callback function
callbackFunction = function (arg) {
alert(arg);
};
// Next, lets do a function call!
calledFunction(callbackFunction, "HAI");
So, calledFunction()'s callback argument is callbackFunction but, if you notice, we aren't calling the function yet, we're passing a variable the contains the function, and its arg function is just something to alert(). When calledFunction() is executed it takes whatever was passed as the callback argument and calls it with arg as its first, and only, argument.
Helped?
Edit: This still works if you use function foo() {}-style declarations. (just in case; I don't know how fluent you are with JavaScript)
You are doing it wrong. this.n = 5; in k() does not set its "inner variable", and x.n access the function object's x property, instead of its inner variable.
Try this:
function p(x) { alert(new x().n); }
Variable binding is an important programming concept.
I think this article helps. http://www.hunlock.com/blogs/Functional_Javascript

Categories