I know I could just pass it as a parameter but as an effort to understand JS further, is there anything like this:
function logIt() {
console.log(x)
}
[0,1,2].forEach(x => logIt())
// x is not defined
Actually no. Function tries to find the variables in the scope and the above scopes where it was declared. In your case logIt is declared in the global scope and it tries to find x there, but your x is defined in the function scope which is passed to the forEach. In other words logIt doesn't look for its variable in the x => logIt() scope.
// Global scope, Look here, this is the scope where `logIt` was declared
function logIt() {
// Look here, this is my scope
console.log(x)
}
[0,1,2].forEach(x => {
// Does not look here, it is not the scope where `logIt` was defined and not the global scope
logIt();
})
Scope access has to do with the scope in which the function is defined, not the scope in which it is used. Since x does not exist in the scope in which logIt() is defined, it is unavailable inside the function unless it is passed in via an argument.
Not really, no. A function can't reach out and access variables in the scope that called it.* Which is a Good Thing™. :-)
You could define a variable that both logIt and the anonymous forEach callback have access to, set the value of that variable in the callback, and use it in logIt:
// DON'T DO THIS, KEEP READING
let x;
function logIt() {
console.log(x)
}
[0,1,2].forEach(_x => {
x = _x;
logIt();
})
...but that would be a Bad Thing™ in most cases. We have function arguments for a reason. :-)
* (It can access variables in the execution context for the scope where and when it was created [and the contexts containing that context], but that's different.)
Related
I learnt about the term variable shadowing in Eloquent Javascript (Chapter 3), but I am trying to understand a precise, basic example of the concept.
Is this an example of shadowing?
var currencySymbol = "$";
function showMoney(amount) {
var currencySymbol = "€";
console.log(currencySymbol + amount);
}
showMoney("100");
That is also what is known as variable scope.
A variable only exists within its containing function/method/class, and those will override any variables which belong to a wider scope.
That's why in your example, a euro sign will be shown, and not a dollar. (Because the currencySymbol containing the dollar is at a wider (global) scope than the currencySymbol containing the euro sign).
As for your specific question: Yes, that is a good example of variable shadowing.
In computer programming, variable shadowing occurs when a variable declared within a certain scope (decision block, method, or inner class) has the same name as a variable declared in an outer scope. This outer variable is said to be shadowed...
so I believe your example is good.
you have a globally named variable that shares the same name as inner method. the inner variable will be used only in that function. Other functions without that variable declaration will use the global one.
Yes, your example is an example of shadowing.
The shadowing will persist in other scenarios too due to how closures work in JavaScript. Here's an example:
var x = -1;
function xCounter() {
var x = 0;
return function() {
++x;
return x;
};
}
console.log(x); // -1
counter = xCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(x); // still -1, global was never touched
Note that in this case, even when xCounter returns, the function it returns still has a reference to its own x and invocations of that inner function have no effect on the global, even though the original has long since gone out of scope.
We cannot define a variable more than once. But we can define in different scopes.
let name="tara"
if(true){
let name="ali"
if(true){
console.log(name)
}
}
variable shadowing is when a variable in a local scope uses its value instead of a variable in a parent scope.So the local variables value is shadowing over the parents.
in the above code there are two name variables defined but they are not defined in the same scope. so console.log(name) will check the local scope if it finds the name variable it uses it, if not it checks parent scope once finds it, it uses that one so it does not go the root.
var role = "Engineer";
console.log(role);
function displayRole(){
role = "developer";
console.log(role);
}
displayRole();
console.log(role);
Notice how the last line of code (console.log) prints developer yet it’s not inside the function scope. This is a good example of shadowing where by the role variable in the global scope has been overwritten by the role in the function scope.
To avoid shadowing, the variable in the function scope should be declared using the var keyword so that it becomes accessible to the function only.
Yes, this is a good example of shadowing. A global scope variable is said to be shadowed by a block scope variable when both have the same name. This is happening in your code and the block scope is shadowing the global scope.
I have no idea how to describe my question .
(function(fn){
var able=123;
function tmp(){
fn()
};
tmp();
})(function(){alert(able)});
This snippet throws a Reference Error :able is not defined' .
Would you please explain how javascript get variables to me ?
The scope of the "fn" function is not the same as the "parent" function, you should pass the "able" argument when you call the fn function, and then istantiate it in the fn function itself, like this:
(function(fn){
var able=123;
function tmp(){
fn(able)
};
tmp();
})(function(able){alert(able)});
Functions create lexical closures at the time of their creation. This means that when your alert function is created, the able variable does not exist. Wrapping the execution of fn in a lexical closure that does know about able at a later moment does not affect the already created lexical closure of fn.
If you come up with a question that better explains what you are trying to do, we can propose how to properly use closures to express that idea.
java script support in function local and global scoping.
in this case the "able" is local function scope you can't access outside the function.
If you use var the variable will be declared in the local scope. If u just declare the variable without a var, it will be declared in the global scope
Your code could be rewritten like this using named functions:
var func1 = function(fn) {
var able=123;
function tmp(){
fn()
};
tmp();
}
var func2 = function() {
alert(able)
}
func1(func2);
I believe this way it is clear that the variable 'able' is defined inside 'func1' (more precisely in its local scope) and you are trying to access it inside 'func2' which is outside the scope of 'func1' so it can not "see" into this scope.
More information about scoping in JavaScript can be found here: What is the scope of variables in JavaScript?
I really hope this isn't a duplicate.
function a(){ b(); } // function a calls function b; but there's no function b in the global scope...
(function(){
// the purpose was to declare it later because it may collide with user-defined functions
var b = function(){ console.log('I am function b()'); };
a(); // doesn't work, obviously
a.call(this); // also doesn't work
a.apply(this, []); // doesn't work either
// neither works
var scope = { 'b': function(){ return b.apply(this,arguments); } };
with(scope){
a.call(scope);
}
// ... what works then?
}());
Simply put, function a() declared globally calls function b(). Function b() is not declared before a() and will not be part of the same scope.
So:
We cannot modify function a(), nor its location where is defined
We cannot declare b() in the same scope with a()
We also cannot var a = eval(a().toString()) or any likewise cheats
With pure scope handling, is this possible? And if it it's not, what else can we do?
Just trying to learn some JavaScript here that's all.
You can't do it. Variables local to a scope cannot be accessed outside that scope, that's the whole point of scoping. If you want to make the b() function visible outside the anonymous function, you need to assign it to an outer variable.
When you create a function object, it wraps all the enclosing functions and forms the closure. Later, whenever the object being used is not found in the local scope, the enclosing function objects will be searched.
In your case, a is declared in the global scope and there are no enclosing functions. When you invoke a from the IIFE, b will be searched within a itself and its enclosing functions and finally in the global scope, which is not found anywhere in that list of scopes. That is why it fails with
ReferenceError: b is not defined
Note: The important thing to be noted here is, when you invoke a function, the scope in which the function was defined will be searched, not where it is invoked from.
So, the answer is NO. Its not possible to do what you are trying to do.
function onMouseClickFunction() {
$mapCanvas.click(function (e) {
var x = cursor.getCursorPositionInCanvasX(e.pageX),
y = cursor.getCursorPositionInCanvasY(e.pageY);
what is the variable scope in this example is it function onMouseclickFunction or perhaps the anonymous function of jquery?
What i ment is that javascript uses hoisting creating variables at the top of its parent function, so where is hoisting done in this example?
Every variable properly declared will always have a local scope to the current function.
Since you're using the var statement properly, your x and y variables are local to your anonymous function.
If you want to be able to access those variables from your onMouseClickFunction function, you should declare them outside your click event handler. You'll still have access to them from within the click handler, since that function itself is declared within the onMouseClickFunction function.
This is known as JavaScript's scope chain lookup: if a variable you're using has not been declared within the local scope, JavaScript will look for it in the scope just above the current one (which in the case of your anonymous function is the outer onMouseClickFunction). If it's not declared there either, it'll keep on looking all the way up the scope, till it reaches the global scope.
If the variable is not found anywhere through the scope chain, it'll be declared as a new variables in the global scope. That's why it's imperative to always declare your variables with a var statement, as you've done.
Assuming you mean the variables x and y, then it is the anonymous function passed to click().
var always scopes to the current function.
What i ment is that javascript uses hoisting creating variables at the top of its parent function, so where is hoisting done in this example?
Hoisting means that when you use var, the variable will be scoped for the function, even if you have previously tried to use it.
i.e.
function () {
var x = 1;
function () {
alert(x);
var x = 2;
}
}
If the inner function was called, it would alert undefined because var x = 2 creates a new x in the scope of the inner function (var is hoisted), but the assignment doesn't take place until after the alert (since the assignment is not hoisted).
All the var statements in the question appear at the top of the function they appear in, so hoisting makes no difference.
It would be the latter (the anonymous function), since that's the function in which the variables are being declared.
What you have created here is a closure.
As such, the anonymous function would inherit the scope of onMouseClickFunction, but the variables x and y are only in the scope of the anonymous function.
I have no idea why it didn't work if I specify a variable with 'var':
like this:
var mytool = function(){
return {
method: function(){}
}
}();
And later I use it in the same template: mytool.method. This will output mytool was not defined.
But if I define it like this:
mytool = function(){
return {
method: function(){}
}
}();
Then it works.
Javascript has function scope. A variable is in scope within the function it was declared in, which also includes any functions you may define within that function.
function () {
var x;
function () {
// x is in scope here
x = 42;
y = 'foo';
}
// x is in scope here
}
// x is out of scope here
// y is in scope here
When declaring a variable, you use the var keyword.
If you don't use the var keyword, Javascript will traverse up the scope chain, expecting to find the variable declared somewhere in a higher function. That's why the x = 42 assignment above assigns to the x that was declared with var x one level higher.
If you did not declare the variable at all before, Javascript will traverse all the way to the global object and make that variable there for you. The y variable above got attached to the global object as window.y and is therefore in scope outside the function is was declared in.
This is bad and you need to avoid it. Properly declare variables in the right scope, using var.
The code you have doesn't show enough to demonstrate the problem. var makes the variable being defined 'local' so it will only be available within the same function (javascript has function level scoping). Not using var makes it global, this is almost always not what you want. You might need to rearrange your code to fix the scope issues.
I take it that you're using this inside of some function:
function setup_mytool() {
var mytool = function(){
return {
method: function(){}
}
}();
}
This creates the variable mytool in the function's scope; when the function setup_mytool exits, the variable is destroyed.
Saying window.mytool or window.my_global_collection.mytool will leave the variable mytool intact when the function exits.
Or:
var mytool;
function setup_mytool() {
mytool = function(){
return {
method: function(){}
}
}();
}
will also do what I think it is you're intending.
The reason why you are getting variable undefined errors is because when you use var, the declared variable is scoped to the surrounding context, meaning that the variable's lifetime is limited to the lifetime of the surrounding context (function, block, whathaveyou).
If you don't use var however, you are effectively declaring a variable tied to global scope. (Usually a Very Bad Idea).
So, in your code, the reason why you are able to access the mytool variable somewhere else in your template is because you tied it to global scope, where in the case of using var, the variable went out of scope because it must have been declared within a function.