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

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.

Related

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

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"));
});

understanding javascript function call and referance

I found this browsing:
What is the difference between a function call and function reference?
After reading the answers there, I did't understand the definition and usage for function references and function calls. Then I searched a lot, but it is still unclear where to use what.
Could you help me understand this by pointing out the differences in concept and usage? I want to make this as a reference for future programers.
Take this for example:
function foo() {
alert('foo');
return 'bar';
}
First of all, what is a function? It's a routine that can be called (or "invoked", or "executed"), and when you do so it usually does something, and returns some value.
So you have a function named foo. You can call it by adding () after its name:
foo();
You can store the return value in a variable, if you assign the result of the invocation to it:
var something = foo();
something === 'bar'; // true
But that's not all you can do with functions in JavaScript. It's a language where functions are first class citizens, so they can be passed around to other functions, and returned from other functions. They can also be stored as variables. For example:
var refToFoo = foo;
Now refToFoo is the same as foo. It's not a copy, it's a reference pointing to the same (internal) function object as foo. So you can use refToFoo just like you would use foo:
var something = refToFoo();
something === 'bar'; // true
refToFoo === foo; // true; they're the same object
Perhaps the most common use to function references is to use them as event listeners:
someElement.onclick = foo;
Note there is no parentheses above. It we used parentheses, foo would be invoked, immediately, and its return value would be assigned to the element's onclick method. Since that function returns a string, nothing would happen if the element were clicked. That's a very common mistake newbies do. Another common one is invoking a function instead of passing a reference to setTimeout:
setTimeout(foo(), 1000); // WRONG - foo is executed immediately
Compare that to:
setTimeout(foo, 1000); // RIGHT - we're passing a reference to the function,
// that will be invoked by the js engine after 1000ms
I hope this helps clarify your doubt.

Javascript named function definition executed when it shouldn't

I have no idea what is happening here. The code is:
if( true ) {
console.log('In first function definition');
function test(){
console.log('Hello world');
}
} else {
console.log('In the second function definition');
function test(){
console.log('Goodbye world');
}
}
test();
I would expect this to log in the console:
'In the first function definition'
'Hello world'
But instead it logs:
'In the first function definition'
'Goodbye world'
How is the second named function being created when the code doesn't enter that branch?
Remember, everything in JavaScript is function-scoped; there is no block scope.
To that effect, you have two function declarations defined in the same scope (whatever the scope that if-else sits in), with the same name, in different blocks. This produces inconsistent results between browsers.
You need to either give those functions different names, or use function expressions, with something like this:
var f;
if(true) {
console.log('In first function definition');
f = function(){
console.log('Hello world');
};
} else {
console.log('In the second function definition');
f = function(){
console.log('Goodbye world');
};
}
f();
To your excellent question of
But how is the function defined, if we don't enter that branch of the code? If that block is not executed, why is scope a consideration?
The simple answer is that function declarations are "hoisted", and immediately available anywhere in the scope, even before the declaration itself.
ie:
function foo(){
f(); //perfectly valid
function f(){
}
}
The longer answer is that, prior to entering the scope, all variable declarations, and function declarations are stripped out, and placed onto the "activation object." The activation object is then placed at the head of the "scope chain." When you execute the function, any references to these variables and functions are simply resolved from there.
Function definitions in javascript are independent of control structures, meaning that when you redefine the function the second time even though it's in a branch of a control structure that will never bit hit it still redefines the function. What are you trying to do anyway?
Some JavaScript engines treat the definition as always occurring regardless of the condition, and the second definition overwrites the first.
Note: Some JavaScript engines, not including SpiderMonkey, incorrectly treat any function expression with a name as a function definition.
To add to Adam's answer, you can get a way around it if you assign your function.
if( true ) {
console.log('In first function definition');
test = function() { console.log('Hello world'); }
} else {
console.log('In the second function definition');
test = function(){ console.log('Goodbye world'); }
}
test();
This will print
In the first function definition
Hello world
According to ECMA-262, function declarations are processed before any code is executed. So declaring functions anywhere effectively moves ("hoists") them to the top of the execution context.
However, not everything that looks like a declaration is a declaration. In the following:
if (false) {
function fred() {return true;}
}
Some browsers see a function declaration so:
alert(fred());
shows "true". Other browsers use an extension to ECMA-262 that allows it to be treated as a named function expression function statement (I'll try to find a reference to an excellent posting by Richard Cornford on comp.lang.javascript about that see below), so that:
alert(fred());
throws as an error that fred is undefined. Try it in Firefox and IE.
So the bottom line is if you want to conditionally create a function, use an unambiguous function expression. They're often used in conjunction with feature testing, e.g. to create a function to get the textContent or innerText of an element:
var getText = (function() {
var el = document.createElement('div');
if (typeof div.textContent == 'string') {
div = null;
return function(el) {return el.textContent;};
} else if (typeof div.innerText == 'string') {
div = null;
return function(el) {return el.innerText;};
}
}());
Edit
Here's Richard Cornford's post in FunctionExpression's and memory consumptions. The important part:
In fact it is a function statement; a syntax extension that is
capable of allowing the conditional creation of a function because
being a Statement it can be evaluative inside a block.
But the whole post is worth reading.
Also note that function statements are warned against in ES5 strict mode and may be introduced in some future version of ECMAScript.

Accessing variable in callback function... what?

I've been through a ton of posts and I finally got what I needed thanks to this:
$("a.foo").click(function(){
var that = this;
jPrompt("Type something:","","", function(r) {
$(that).text(r);
}
}
From the following:
Accessing $(this) within a callback function
I was wondering if someone could expand on what exactly is happening here (why is this not available without re-assigning?) and what core information I should read up on? From what I gather this might have something to do with closures... that's most of what I bumped into while searching around. Is that accurate?
In my case, I was looking to execute some code, then redirect once an ajax request completed. In the callback function I was running $(this).attr("href") which was returning undefined.
this is assigned by javascript according to how a function is called. So, it is the jPrompt() function that determines what value this will have in your callback when jPrompt() calls the callback.
So, unless jPrompt goes out of its way to keep the same value for this via some argument you passed in, it will likely have a different value. As such, you can save it away for access within the callback as you've done. This is a very common design pattern in javacscript callbacks.
FYI, some of the ways that this is assigned:
obj.method() - this in method() will be set to obj
func.call(obj) - this in func() will be set to obj
func() - this will be set to window in func() or undefined in strict mode
The meaning of this changes depending on where you're at. The this within a handler for your click event means something other than the this within the callback passed to your jPrompt function.
For what it's worth, you don't need to re-assign this, since the event object passed into your handler will have a reference to the currentTarget:
$("a.foo").on("click", function (event) {
// 'this' here refers to the anchor we clicked
jPrompt("Type something:", "", "", function (r) {
// 'this' here refers to whatever jPrompt instructs
$(event.currentTarget).text(r);
}
}
The code in the question with some added comments:
$("a.foo").click(function(){
var that = this; //`this` holds the a object clicked. now so does `that`!
jPrompt("Type something:","","", function(r) {
//even if `this` has a different value here, `that` still holds the a object clicked
$(that).text(r);
}
}
This is something you will often find yourself doing in similar situations. this is context-dependent and you often need to keep the value this had in one context and use it in another.
A quote from the ECMAScript specification:
10.1.7 This
There is a this value associated with
every active execution context. The
this value depends on the caller and
the type of code being executed and is
determined when control enters the
execution context.
Hope that answers your question. You also asked for a resource for further reading. Please visit:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this
These guys provide excellent documentation both detailed and typically quite accurate (unlike other popular sources of reference that often comes first in Google searches -- w3cshools.com I am thinking of you!).
A Short Overview of this
this in JavaScript is dynamically scoped. Its behavior differs from all other variables which are lexically scoped. Other variables don't have a different binding depending on how the function is called; their scope comes from where they appear in the script. this however behaves differently, and can have a different binding depending not on where it appears in the script but on how it's called. Consequently, it can be a source of confusion for people learning the language, but mastering it is necessary in order to become a proficient JavaScript developer.
Since this is dynamically bound there are several ways to change its values based on how you call the function.
Examples
When you execute a function in JavaScript, the default this is window.
function foo() {
console.log(this);
}
foo(); // => window
The this value can be changed in a number of ways. One way is to call the function as a method of an object:
var x = {
foo: function() {
console.log(this);
}
};
x.foo(); // => This time it's the x object.
Another way is to use call or apply to tell the function to execute in the context of a certain object.
function foo() {
console.log(this);
}
foo.call(x); // => x object again
foo.apply(x); // => x object as well
If you call or apply on null or undefined, the default behavior will occur again: the function will be executed in the context of window:
function foo() {
console.log(this);
}
foo.call(null); // => window
foo.apply(undefined); // => window
However, note that in ECMAScript 5 strict mode, this does not default to window:
(function() {
'use strict';
function foo() {
console.log(this);
}
foo(); // => undefined
foo.call(null); // => null
foo.apply(undefined); // => undefined
})();
You can also set the this by using bind to bind the function to an object before it is called:
function foo() {
console.log(this);
}
var bar = {
baz: 'some property'
};
var foobar = foo.bind(bar);
foobar(); // => calls foo with bar as this
Going Father: Lazy Bind / Uncurrying this
Going further, you may sometimes want to take functions which act on a this and allow the this value to be passed in as the first argument to the function. This can be really helpful for Array methods, such as forEach. For instance, let's say you are dealing with an object which is array-like but not actually an array.
var arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
'length': 3
};
If you want to iterate over this object with forEach, you could use call:
Array.prototype.forEach.call(arrayLike, function(item) {
console.log(item);
});
// Logs: a, b, c
However, another option is to create a forEach function which can be called directly on your object:
var forEach = Function.prototype.call.bind(Array.prototype.forEach);
Now you can use this function anytime you want to iterate over an array-like object:
forEach(arrayLike, function(item) {
console.log(item);
});
// Logs: a, b, c
Sometimes this method is referred to as "uncurrying this". However, I prefer to create a function which can generate these "uncurried" functions and call it "lazy binding".
var lazyBind = Function.prototype.bind.bind(Function.prototype.call);
var forEach = lazyBind(Array.prototype.forEach);
var slice = lazyBind(Array.prototype.slice);
var map = lazyBind(Array.prototype.map);
forEach(arrayLike, function(u) {
console.log(u);
});
// Logs: a, b, c
var realArray = slice(arrayLike);
// Converts arrayLike into a real array
forEach(
map(arrayLike, function(u) {
return u + 'Q';
}),
function(u) {
console.log(u);
}
);
// Logs: aQ, bQ, cQ
One really awesome thing about this technique is it can be useful for creating securable JavaScript, which can be helpful if you don't want other scripts on the page snooping around your internal variables. This is a pretty advanced meta-programming technique, though, and you don't see it in day-to-day JavaScript.

Advanced JavaScript: Why is this function wrapped in parentheses? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the (function() { } )() construct in JavaScript?
I came across this bit of JavaScript code, but I have no idea what to make out of it. Why do I get "1" when I run this code? What is this strange little appendix of (1) and why is the function wrapped in parentheses?
(function(x){
delete x;
return x;
})(1);
There are a few things going on here. First is the immediately invoked function expression (IIFE) pattern:
(function() {
// Some code
})();
This provides a way to execute some JavaScript code in its own scope. It's usually used so that any variables created within the function won't affect the global scope. You could use this instead:
function foo() {
// Some code
}
foo();
But this requires giving a name to the function, which is not always necessary. Using a named function also means at some future point the function could be called again which might not be desirable. By using an anonymous function in this manner you ensure it's only executed once.
This syntax is invalid:
function() {
// Some code
}();
Because you have to wrap the function in parentheses in order to make it parse as an expression. More information is here: http://benalman.com/news/2010/11/immediately-invoked-function-expression/
So to recap quickly on the IIFE pattern:
(function() {
// Some code
})();
Allows 'some code' to be executed immediately, as if it was just written inline, but also within its own scope so as not to affect the global namespace (and thus potentially interfere with or be interfered with by, other scripts).
You can pass arguments to your function just as you would a normal function, for example,
(function(x) {
// Some code
})(1);
So we're passing the value '1' as the first argument to the function, which receives it as a locally scoped variable, named x.
Secondly, you have the guts of the function code itself:
delete x;
return x;
The delete operator will remove properties from objects. It doesn't delete variables. So;
var foo = {'bar':4, 'baz':5};
delete foo.bar;
console.log(foo);
Results in this being logged:
{'baz':5}
Whereas,
var foo = 4;
delete foo;
console.log(foo);
will log the value 4, because foo is a variable not a property and so it can't be deleted.
Many people assume that delete can delete variables, because of the way autoglobals work. If you assign to a variable without declaring it first, it will not actually become a variable, but a property on the global object:
bar = 4; // Note the lack of 'var'. Bad practice! Don't ever do this!
delete bar;
console.log(bar); // Error - bar is not defined.
This time the delete works, because you're not deleting a variable, but a property on the global object. In effect, the previous snippet is equivalent to this:
window.bar = 4;
delete window.bar;
console.log(window.bar);
And now you can see how it's analogous to the foo object example and not the foo variable example.
It means you created an anonymous function, and call it with parameter 1.
It is just the same as:
function foo(x) {
delete x;
return x;
}
foo(1);
The reason that you still get 1 returned is that the delete keyword is for removing properties of objects. The rest is as others have commented, anything wrapped in brackets executes as a function, and the second set of brackets are the arguments passed to that block.
Here's the MDN reference for delete, and the MDN reference for closures, which discusses also anonymous functions.
People normally call these "Immediately Invoked Function Expressions" or "Self Executing Functions".
The point of doing this is that variables declared inside that function do not leak to the outside.

Categories