Recently I came across a piece of code which was like this:
var noop = function(){};
options.ondragover = options.ondragover || noop;
options.ondragleave = options.ondragleave || noop;
options.ondrop = options.ondrop || noop;
options.onfilesdone = options.onfilesdone || noop;
This is a No Operation function
Discussed in detail in following link
https://disqus.com/home/discussion/chrislaughlin/noop_no_operation_function/oldest/
What is the JavaScript convention for no operation?
The code you posted declared an empty function with the name noop (No Operation) as an alternative to execute when certain conditions apply.
For example the code:
options.ondragover = options.ondragover || noop;
checks if options.ondragover exists and if not assigns the empty function to the variable.
It is simply a self executed function in which whatever you declare, you can execute the same.
It restrict the scope and make it private and hide the variables from global objects.
// Somewhere it is defined as global..
var x = 7;
// Your piece of code
var x = "roman" // Here, you override the value of x defined earlier.
alert(x); // "roman"
But when you use a closure which you have mentioned:
var x = 7;
// it doesn't affect/change the value of global x
(function (){ var x = "roman";})();
alert(x); // 7
Related
I've been exploring scope within JavaScript. Sources point out that scope is function-delimited, not block-delimited as in most languages.
I put some display code in some code I'm writing, because some of my functions-within-functions are not clear (to me), and I wanted to see just how the scope works for these.
The big surprise is that in the $.each function within the $.getJSON function the if(){} clause is, evidently, treated as a function. I would have assumed it to be a block.
function displayInfo(nKey) {
if(!nKey) var nKey = 0;
var objFilm = {};
var imgRef;
//iterate through all object properties; display their attributes
// Object.keys() returns an array of all property names
// for most entries, the object is ...film; check first for array of multiple films
jqxhr = $.getJSON('dbMovies.json', function(data) {
var xx = "xx";
$.each(data.disc, function(i, xdata) {
if(xdata.key == nKey) {
objFilm = xdata.film;
var yy = "yy";
imgRef = xdata.img;
return false;
}
console.log("in jqxhr, xx: " + typeof xx); //this shows
console.log("in jqxhr, yy: " + typeof yy); //this does NOT
}); // $.each
})
.done(function() {...}
If if(){} is a function, what is a block?
You have a return false inside the if, therefore the only time those two log statements will be reached is if the if condition wasn't true and the block controlled by the if didn't run. And if the block didn't run, then yy wasn't assigned a value. It's in scope, but uninitialized.
The variable the function is assigned to is limited only by its scope, which is guaranteed to include the scope where the function is declared in.
if() { } is not a function... it is a block. the reason it is not showing up in your example is because you have return false which breaks before the log happens, and when the logs do happen then the variable is still undefined.
(function () {
if (true) var x = "if declared variable"; /* block declaration */
document.getElementById('if').innerHTML = x ? x : 'undefined';
(function() {
var y = "function declared variable";
})();
if (typeof y != 'undefined')
document.getElementById('func').innerHTML = y
else
document.getElementById('func').innerHTML = 'undefined';
})();
if: <span id="if"></span>
<br>
func: <span id="func"></span>
I want to know how the function has been initialized, with the expression or declaried as fuction. _ Amazon interview question
expression : var a = function (){ }
declaration: function a (){ }
You could just do a.toString() and parse out the name. Or do the same with regular expressions
a.toString().test(/^\s*function\s*\(/);
function a(){ }; // gives false
var a = function (){ }; // gives true
Of course as Grundy pointed out this fails with named functions. Something like
var a = function b() {};
or
function b() {};
var a = b;
And ES6 has .name (see the Browser table at the bottom for the current state of affairs) - https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Function/name
I don't think it's possible to do so. The only difference between:
var func = function(){ };
and:
function func() { };
Is that the first one gets assigned on runtime. The way I see it, is that both function statements return a reference to their respective function objects. In that sense they are both the same. The only thing you could argue is that one is not named and the other one is, but you could have assigned a named function to a variable too.
However, there seems to be a difference on how they get assigned. The second one seems to get assigned to a variable that its named after, right at the start of the execution context. The first one has to wait for the explicit assignment within the execution context.
So you'd be testing for when they get assigned. You might think that's is possible to do so within the global object like:
//some protected vars that can't work without same-origin
var protected = ['caches', 'localStorage', 'sessionStorage', 'frameElement'];
var definedAtInit = [];
for(prop in window){
if(!isSandboxed(prop) && typeof window[prop] === 'function'){
definedAtInit.push(prop);
}
};
function isSandboxed(prop){
return protected.indexOf(prop) !== -1;
}
function isItDefinedAtInit(funcName){
return definedAtInit.indexOf(funcName) !== -1;
}
var func = function() {
console.log('test');
}
var results = { isItDefinedAtInit : isItDefinedAtInit('isItDefinedAtInit'),
func : isItDefinedAtInit('func')
};
document.getElementById('results').innerHTML = JSON.stringify(results, '/t');
<pre id="results"></pre>
However, you could still do something like:
var isItDefinedAtInit = function() { };
//After this, isItDefinedAtInit('isItDefinedAtInit') would be wrong.
And you still have the problems with other execution contexts, I don't think functions declared within a function execution context get attached to any object.
I think these kind of checks are a bad idea to be honest.
There is only way, we can determine function has defined with function declarations not as expression.
as Grundy mentioned name property of the respective function gives require information, if it has been defined with expression name property holds undefined value, else it holds function name.
Here is the code :
var isDefinedAsFunction = function(fn){
return fn.name !== undefined
}
var inner = function() { console.log(x); }
// test 1
(function(cb) { var x = 123; cb(); })(inner);
// test 2
(function(cb) { var x = 123; cb.apply(this); })(inner);
// test 3
(function(cb) { var x = 123; cb.bind(this)(); })(inner);
// test 4
(function(cb) { cb.bind({x: 123})(); })(inner);
All tests result in:
ReferenceError: x is not defined
Do someone know how it is possible to access 'x' as a local variable inside the callback?
Fact: when you do var inner = function() { console.log(x); } in your first line, x is not defined. Why? Because, inside your inner function, there's no local declaration of x (which would be done with var x = something). The runtime will then look up in the next scope, that is the global scope. There isn't, also, a declaration of x, so x is also not defined there.
The only places where there is a variable called x are inside each one of your 4 IIFEs following. But inside the IIFEs, each x is a different variable, in a different scope. So, if what you want is to console.log() the x defined inside each IIFE, you are taking the wrong approach.
Keep in mind that, when you define inner, you are capturing the environment inside the function's closure. It means that, whatever value could x have there (in the declaration of the function), would be the available value to the x variable later, when the inner function would be used. The fact that your x there is not defined is only an accessory, and is not what is causing the undesired behavior.
So, what happens is that when you call your inner function inside any of your IIFEs, the x referred to inside the inner function declaration is a captured value of what x had as a value when the function was defined, not the value that x has now in the scope where the function is currently being called. This is what is called lexical scope.
To solve this, you would have to pass the value that you want to console.log() inside the inner function as a parameter to the inner function, as so:
var inner = function(x) { console.log(x); }
// test 1
(function(cb) { var x = 123; cb(x); })(inner);
The only way to access the local variable x in the callback, is to pass it as an argument:
var inner = function(some_var) { console.log(some_var); }; //logs 123
(function(cb) { var x = 123; cb(x); })(inner);
OR
var inner = function(some_var) { console.log(some_var); }; //logs 123
(function(cb) { var x = 123; cb.apply(this,[x]); })(inner);
OR
var inner = function(some_var) { console.log(some_var); }; //logs 123
(function(cb) { var x = 123; cb.call(this,x); })(inner);
FURTHER
Because JS is lexically scoped, trying to reference the local variable after the anonymous function has finished executing is impossible by any other means. If you don't pass it as an argument to make it available elsewhere, JS will see it as non-reachable and it will be eligible for garbage collection.
You could redefine the callback function in the current scope:
var inner = function() { console.log(x); }
(function(cb) { var x = 123; eval('cb = ' + cb.toString()); cb(); })(inner);
// or
(function(cb) { var x = 123; eval('(' + cb.toString() + ')')(); })(inner);
This will not work if the function relies on anything in the scope in which it was originally defined or if the Javascript file has been minified. The use of eval may introduce security, performance, and code quality issues.
Have you tried using events? Emit an event inside the anonymous function, then subscribe to it in your own function somewhere else that carries out your logic.
I thought any variable defined in a function would be local but I can easily access variable 'e' outside of its function.
function change() {
var d = 6;
e = 7;
}
change();
alert(e); //> alerts 7
Because new variables will enter the global scope by default. var prevents this from happening by constraining a variable's existence to be within the current scope.
Because it was declared without var it becomes part of the global window object.
You've not explicitly declared it as such, so it has taken global scope.
Thats because e is global by default, using var make a scope varible.
You can read more about this in Javascript Garden Scope and Namespaces
I am guessing that you are going under this assumption that
JSLint expects that a var will be
declared only once, and that it will
be declared before it is used.
Problem with your code is you are using one var, but your second line has no var in front of it. That is pushing that varaible e into the global namespace.
Why is it happening? You used a semicolon instead of a comma in the variable declaration.
function change() {
var d = 6, //Change this to a comma
e = 7;
}
change();
alert(e); //will produce an error now
It is surprisingly easy to create global variables, here are some other gotchas I've seen.
// :-( antipattern: implied global variable
function sum(x, y) {
result = x + y; // result is global
return result;
}
// :-) better
function sum(x, y) {
var result = x + y; // result is local
return result;
}
// :-( antipattern: chain assignments as part of a var declaration
function foo() {
var a = b = 0; // b is global
}
// :-) better
function foo() {
var a, b;
a = b = 0; // both local
}
First question
var obj = function(){
var a = 0;
this.b = 0;
}
Is there any difference in behaviour of a and b?
Second question
var x = 'a';
var f1 = function(x){ alert(x) }
var f2 = new Function('alert('+x+')')
Is there any difference in behaviour of f1 and f2
Question 1
var obj = function() {
var a = 0;
this.b = 0;
}
Within the function, you'll be able to access both variables, but in the case of
var x = new obj();
... you'll be able to access x.b, but not x.a.
Question 2
As your question is written at the moment, it is a syntax error. The following will work:
var x = 'a';
var f1 = function(x){ alert(x) }
var f2 = new Function('alert('+x+')')
... but that would be the same thing as writing:
var x = 'a';
var f1 = function(x){ alert(x) }
var f2 = new Function('alert(a)')
The difference here is obvious. f1 disregards the global variable x and alerts whatever is passed to it, while f2 also disregards the global variable x, and tries to look for a global variable a. This is probably not what you're trying to ask about.
What you probably want is something like this:
var x = 'a';
var f1 = function(){ alert(x) }
var f2 = new Function('alert(x)')
... or this:
var f1 = function(x){ alert(x) }
var f2 = new Function('x', 'alert(x)')
The difference between the two alternatives above is that the first always uses the global variable x, while the second never uses any global variable. The difference between f1 and f2, internally, in both examples, is none at all.
These are two ways of generating the exact same result. The only reason you'd ever want to use the f2 approach would be when generating the code in some dynamic manner that require string input for its definition. In general, try to avoid this practice.
var obj = function() { // function expression, while obj is created before head
// it's only assigned the anonymous function at runtime
var a = 0; // variable local to the scope of this function
this.b = 0; // sets a property on 'this'
}
Now what this is depends on how you're calling the function.
Also note the difference between function statements and expressions.
var x = 'a'; // string a, woah!
var f1 = function(x){ alert(x) } // another anonymous function expression
// Does not work
// 1. it's "Function"
// 2. It gets evaluated in the global scope (since it uses eval)
// 3. It searches for 'a' in the global scope
var f2 = new function('alert('+x+')') // function constructor
In short, never use the Function constructor, it will never inherit local scope and therefore you can't use closures with it etc.
First question:
var obj = function() {
var a = 0;
this.b = 0;
}
instance = new obj();
instance.showA = function() {
alert("this.a = " + this.a);
}
instance.showB = function() {
alert("this.b = " + this.b);
}
instance.showA(); // output undefined - local scope only, not even to methods.
instance.showB(); // output 0 - accessible in method
Paste this in your Firebug console and run to see the output and behavior for yourself.
Second question:
var f2 = new function('alert('+x+')');
This throws a syntax error in Firebug because the f should be capitalized. This is a case where a function is defined inside a string and evaluated. Here is a good example:
var x = 'a=3';
var f2 = new Function('alert('+x+')');
f2(); // outputs 3 because the x passed into the variable is evaluated and becomes nested inside the quotes prior to the alert command being fired.
Here is what the substitution process looks like:
1: x = "a=3";
2: 'alert(' + x + ')');
3: 'alert(' + 'a=3' + ')'); // x replaced with a=3
4: 'alert(a=3)';
5: 'alert(3);'
When function runs, alert(3) is fired. This can be used to execute other JavaScript pulled down from a remote server, although extreme care should be used for security reasons. When evaluating code that is nested in quotes, it helps to start from the inside and work your way up to the top level context. More information on dealing with nested quotes or embedded code can be found here: http://blog.opensourceopportunities.com/2007/10/nested-nested-quotes.html
Question 1: homework on scoping of variables (var b is local to the enclosing {} (local to the function in this case).
Question 2: Instead of using the Function constructor you could use eval? http://www.w3schools.com/jsref/jsref_eval.asp , as in
eval 'alert('+x+')';
Second question is VERY interesting. Only benchmarks can say the truth.
http://jsperf.com/function-vs-function/
http://jsperf.com/function-vs-function/1..8
http://jsperf.com/function-vs-constructor-vs-eval
http://jsperf.com/function-vs-constructor-vs-eval/1..5
It looks they are almost equal? I can see in modern browsers each variant is optimized enough
BUT BE AWARE OF RECREATING THE FUNCTION IN A LOOP!
http://jsperf.com/function-vs-function/2
Any wise comments?