Consider the following 2 functions:
cat = function() {
console.log("Meow");
}
and:
var dog = function() {
console.log("woof")
}
cat() -> "Meow"
dog() -> "Woof
They both work, except that cat is not declared using var. Does this mean that it is globally scoped? I would say that both functions are globally scoped. There is also the syntaxfunction cat(){...}, I guess that is similar to the first style, some sort of implicit variable binding...
Could somebody explain the difference between the styles for declaring functions, if there is any.
Variables
If you don't specify var, let or const it will get globally scoped
If you do specify var, let or const then it will get scoped to the nearest enclosing scope depending on that particular specifier
(var - will get scoped to the nearest enclosing function or global scope if not defined inside of a function)
(let & const - will get scoped to the nearest enclosing block)
Functions
Assigning a function as follows:
var dog = function() {
console.log("woof")
}
Means that the function will not be accessible until the line that it is declared on is reached during execution, i.e. you will only be able to execute this function from after the line on which it was declared.
Whereas declaring a function as follows:
function cat(){...}
Means that it will be moved to the top of the enclosing scope, so you will be able to call it from anywhere within the reachable scope even if it's earlier in code than the line on which you declared it on.
Not using var/let/const makes it implicitly global, which is generally regarded as a bad thing. If you use 'use strict', you'll get an error for any implicit globals. The biggest issue that arises with implicit global variables is that you may not know that you've made a global variable. For example:
(function() {
a = 5;
})();
// a doesn't exist right?
console.log(a); // 5... whoops!
No you don't. you can declare a function like so:
function foo(){
}
Then foo is automatically declared at the appropriate scope.
Its all a matter of scopes. where will the interpreter declare the function. Doing it the way you did it, without var will cause the interpreter to create a global variable automatically, and that is the highest scope possible, meaning that it is accessible everywhere in the code. That is considered a bad thing, since you normally wouldn't want to do that unless it is done intentionally, because of deep reasons which I can go into if you wish.
function foo(){
function bar(){
console.log("bar");
}
bar();
console.log(typeof bar);
}
foo();
bar(); // will throw an error since "bar" does not exist at this scope
Read all about function declaration
Related
I am experimenting with closures but rather than enclosing a function within a function, I enclosed a function within a block. Since functions are not blocked-scoped and will be hoisted outside of the block I assumed that it wouldn't have access to the scope within the block. Yet, in this case, the function returns the block-scoped variable. Does this mean that the function is a closure?
{
let a = 'hi'
function test() {
return a
}
}
test() // hi
I'd be happy to call it a closure, at least according to Wikpedia's definition:
Operationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created. Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.
In your function test, the variable a is a free variable, used by the function but not defined inside the function. When you called the function outside the block, it retained the value of a. So, you've met the essential points of the definition of closure (according to Wikipedia).
Of course, you asked the question because it's kind of tricky. Normally with closures, we define a function inside an environment and then "export" it out by binding the function object to a name that has a wider scope. Because of the way JavaScript treats function declarations defined in a block (see Code Maniac's link to the ECMAScript specification on handling block-scoped function declarations) you do get this effect! So it's kind of a closure, even though you never explicitly exported the function.
Of course if you had written
{
let a = 'hi'
let test = () => a
}
test()
you get an error.
But this works:
let b;
{
let a = 'hi'
let test = () => a
b = test
}
b() // "hi"
so yes, the block is acting as the non-local environment from which variables can be captured. I'm thinking yes, it's okay to speak of this as being a closure, because it acts like one (even if this behavior comes from a pre-ECMAScript 2015, "optional", and non-strict treatment of function declarations inside of blocks). If it walks like a duck, and all that.
Consider the following code.I’m not sure I completely understand lexical scoping, but, unless I’m misinterpreting everything I’ve been reading, an inner function can only reference outer variables that have been declared in the same context.
let a = 7;
function test() {
return a;
}
function test2() {
let a = 5;
return test()
}
console.log(test2())
In other words, what matters is where such functions are born and NOT where they are called, which, in the case of my example code above, means that the variable “a” that test returns is not the same as the variable “a” declared and assigned the value of 5 in test2. It’s as if the “a” in test2 were foreign to test.
Am I on the right track or is there something I’m missing?
You seem to be on the right track.
Variables defined with let are local to whatever scope they are defined in, either the global scope or a function or a block inside a function. Code in a function or block can "see" variables declared within the same function or block, or variables in an outer scope such as an enclosing function or the global scope.
Your code has two distinct variables that happen to share the same name, a. Each let statement creates a brand new variable, at whatever scope the let statement appears in.
Because your two a variables are actually different and unrelated variables, we could rename them to have two different names, and the code will work the same. I will use global_a for one of them and test2_a for the other:
let global_a = 7;
function test() {
return global_a;
}
function test2() {
let test2_a = 5;
return test()
}
console.log(test2())
Now when you look at the code, you can see that test() only uses global_a. It doesn't even try to use test2_a. And in the test2() function, you can see that the test2_a variable is only assigned but never used!
Note that variables defined with var follow basically the same rules, except that inner blocks inside a function (like an if statement with curly braces) don't count. var only follows function scope and ignores blocks inside a function.
Consider the following code:
var a = 'a';
function b() {
console.log(a);
if (!a) {
var a = 'b';
}
}
b();
Running b() prints undefined to the console. However, if you remove the if statement, or even simply remove the var keyword from the expression within the if statement so that you're redefining the outer a variable, the string a will be printed to the console as expected.
Can anyone explain this? The only cause I can think of is that this is a race condition, and the if statement is running just a tad faster than the console.log.
This is not a race condition - it's a language feature and is working as the designers of the Javascript language intended.
Because of hoisted variable definitions (where all variable definitions within a function scope are hoisted to the top of the function), your code is equivalent to this:
var a = 'a';
function b() {
var a;
console.log(a);
if (!a) {
a = 'b';
}
}
b();
So, the locally declared a hides the globally declared a and initially has a value of undefined until your if statement gives it a value.
You can find lots of discussion about this characteristic of the Javascript language by searching for "Javascript hoisting".
When you use var statement in a function, it will be creating a new variable which is local to that function.
All the variables declared in the function, will be moved to the top of the function, irrespective of the place where they are actually declared. This is called Hoisting.
The hoisted variables will have the value undefined, by default, till they are explicitly assigned a value.
It prints undefined as it is, because of the 3rd point.
In your case, you declared a variable a within the if block. Since the variables are hoisted, the declaration is moved to the top of the function. It has the same name as the outer variable. When you access a in the function, it first looks in the current scope if there is a variable by that name exists. It checks other scopes only if it is not found in local scope. So, the local a shadows the outer a. When you remove the var statement, there is no a in local scope, so the outer a is used. That is why it prints a.
The var keyword in javascript causes a variable to be stored in the local scope. Without var variables belong to the global scope. What about functions? It's clear what happens when functions are declared like variables
var foo = function() {...}
but what scope does
function foo() {...}
belong to?
EDIT:
I realized I didn't ask quite the right question so as a follow up. In the outer most nesting is there a difference between the above two declarations and the following declaration?
foo = function() {...}
It belongs to the current scope, always. For example:
// global scope
// foo is a global function
function foo() {
// bar is local to foo
function bar() {
}
}
Regarding your second question, this:
foo = function() {...}
is an anonymous function expression assigned to a global variable (unless you're running is strict mode, then foo would be undefined). The difference between that and function foo() {} is that the latter is a function declaration (versus a variable declaration, which is assigned an anonymous function expression).
You might be interested in this excellent article about function declarations and function expressions: Named function expressions demystified.
Function declarations are always local to the current scope, like a variable declared with the var keyword.
However, the difference is that if they are declared (instead of assigned to a variable) their definition is hoisted, so they will be usable everywhere in the scope even if the declaration comes in the end of the code. See also var functionName = function() {} vs function functionName() {}.
Noteworthy distinction taking implicit globals into account:
var foo = function() {
// Variables
var myVar1 = 42; // Local variable
myVar2 = 69; // Implicit global (no 'var')
// Functional Expressions
var myFn1 = function() { ... } // Local
myFn2 = function() { ... } // Implicit global
function sayHi() {
// I am a function declaration. Always local.
}
}
Hopefully that clarifies a little. Implicit globals are defined if you forget a var before your assignment. Its a dangerous hazard that applies to variable declarations and functional expressions.
Your first example (var foo = function() {...}) is called an anonymous function. It is dynamically declared at runtime, and doesn't follow the same rules as a normal function, but follows the rules of variables.
do we have to declare js variable like this:
var x=5;
or just simple like this
x=5;
what is the differences?... will it effect the functionality of the variable?...
variable_name = 5 would always put the variable_name into the global object (which is window in a browser)
If you are in the global context (= not a function context) the two statements are basically the same. But if you are in a function context, var makes sure that this variable is only declared within the current context.
So for instance:
function foobar() {
bar = 55;
}
foobar();
window.bar === 55 // true
Better:
function foobar() {
var bar = 55;
}
window.bar === 55 // false
Conclusion: always use var within the context of a function. This avoids clobbering / overriding the global object with variables.
The var keyword limits the scope of the variable to the current function. Leaving it off makes a global. Globals are bad and should be avoided as they are a key source of race conditions and scripts interfering with each other.
x=5 means this variable (after execution) will become global and can be accessed by all other parts in your code(and also by other javascripts).
while var x=5 will be familiar only to the block which it was declared on, (and it's descendants)
Note that although x=5 will be global, it will become global only when this line is execute!
So if you place this inside a function, it will become global only after that function is called (for the first time).
It makes no difference - with the second one (x=5;) the variable is automatically declared if it does not yet exist.
I always use the first option however.