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.
Related
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
Just a quick and easy question which has been confusing me a lot, are function names like:
function drive() {
which are function names considered as variables, is drive considered as a variable?
Function declarations create a variable in the current scope which has the same name as the function and the value of which is the function.
Named function expressions create such a variable in their own scope (not the current scope).
Anonymous function expressions and arrow functions do not create variables.
yes.
drive will be a variable whose value is a named function with the same name. The compiler declares the variable for you, gives it a named function as the value of it -and with the same name as the variable-, and also hoists the variable.
This is done by the compiler as you declare a function.
So, as with any other variable, you can rewrite it:
function bar(){
return 'bar';
}
bar = function(){
return 'foo';
}
console.log(bar() );//foo
However, due to hoisting, changing the order doesn't changes the result:
bar = function(){
return 'foo';
}
function bar(){
return 'bar';
}
console.log(bar() );//also foo
Which doesn't mean that the function bar()... block isn't creating a bar variable, but just that it is created before the bar = function... statement.
You can prevent the compiler to create the variable just by wrapping the function declaration with ():
( function bar(){
return 'foo';
});
bar(); //error
Which is really common to launch IIFEs:
( function bar(){
alert('foo');
})();
//this will launch the alert in a browser.
This question already has answers here:
What are the precise semantics of block-level functions in ES6?
(2 answers)
Closed 7 years ago.
What is block scope function in ECMAScript 6?
Can anyone help me understand the main difference in the block scope function compared to ECMAScript 5?
The new let and const in ES2015 (aka "ES6") have four major differences compared with the venerable var:
They have block scope
They aren't hoisted (well, they're sort of hoisted, but in a useful way)
Repeated declarations are errors
When used at global scope, they don't create properties of the global object (despite creating global variables; this is a new concept as of ES2015)
(For what it's worth, this is covered in detail in Chapter 2 of my recent book JavaScript: The New Toys, which covers ES2015-ES2020.)
Block scope
var variables exist throughout the function they're declared in (or globally, if declared globally), they aren't confined to the block they're in. So this code is valid:
function foo(flag) {
a = 10;
if (flag) {
var a = 20;
}
return a;
}
console.log(foo(false)); // 10
console.log(foo(true)); // 20
a is defined regardless of whether flag is true and it exists outside the if block; all three as above are the same variable.
That's not true of let (or const):
function foo(flag) {
if (flag) {
let a = 10;
}
return a; // ReferenceError: a is not defined
}
console.log(foo(true));
a only exists inside the block it's declared in. (For for statements, a declaration within the () of the for is handled very specially: a new variable is declared within the block for each loop iteration.) So outside the if, a doesn't exist.
let and const declarations can shadow declarations in an enclosing scope, e.g.:
function foo() {
let a = "outer";
for (let a = 0; a < 3; ++a) {
console.log(a);
}
console.log(a);
}
foo();
That outputs
0
1
2
outer
...because the a outside the for loop isn't the same a as the one inside the for loop.
Hoisting
This is valid code:
function foo() {
a = 5;
var a = a * 2;
return a;
}
Bizarre-looking, but valid (it returns 10), because var is done before anything else is done in the function, so that's really:
function foo() {
var a; // <== Hoisted
a = 5;
a = a * 2; // <== Left where it is
return a;
}
That's not true of let or const:
function foo() {
a = 5; // <== ReferenceError: a is not defined
let a = a * 2;
return a;
}
You can't use the variable until its declaration. The declaration isn't "hoisted" (well, it's partially hoisted, keep reading).
Earlier I said
They aren't hoisted (well, they're sort of hoisted, but in a useful way)
"Sort of"? Yes. A let or const declaration shadows an identifier throughout the block in which it appears, even though it only actually takes effect where it occurs. Examples help:
function foo() {
let a = "outer";
for (let x = 0; x < 3; ++x) {
console.log(a); // ReferenceError: a is not defined
let a = 27;
}
}
Note that instead of getting "outer" in the console, we get an error. Why? Because the let a in the for block shadows the a outside the block even though we haven't gotten to it yet. The space between the beginning of the block and the let is called the "temporal dead zone" by the spec. Words aren't everybody's thing, so here's a diagram:
Repeated declarations
This is valid code:
function foo() {
var a;
// ...many lines later...
var a;
}
The second var is simply ignored.
That's not true of let (or const):
function foo() {
let a;
// ...many lines later...
let a; // <== SyntaxError: Identifier 'a' has already been declared
}
Globals that aren't properties of the global object
JavaScript has the concept of a "global object" which holds various global things as properties. In loose mode, this at global scope refers to the global object, and on browsers there's a global that refers to the global object: window. (Some other environments provide a different global, such as global on NodeJS.)
Until ES2015, all global variables in JavaScript were properties of the global object. As of ES2015, that's still true of ones declared with var, but not ones declared with let or const. So this code using var at global scope, on a browser, displays 42:
"use strict";
var a = 42; // Global variable called "a"
console.log(window.a); // Shows 42, because a is a property of the global object
But this code shows undefined for the properties, because let and const at global scope don't create properties on the global object:
"use strict";
let a = 42; // Global variable called "a"
console.log(a); // 42 (of course)
console.log(window.a); // undefined, there is no "a" property on the global object
const q = "Life, the Universe, and Everything"; // Global constant
console.log(q); // "Life, the Universe, and Everything" (of course)
console.log(window.q); // undefined, there is no "q" property on the global object
Final note: Much of the above also holds true if you compare the new ES2015 class (which provides a new, cleaner syntax for creating constructor functions and the prototype objects associated with them) with function declarations (as opposed to function expressions):
class declarations have block scope. In contrast, using a function declaration within a flow-control block is invalid. (It should be a syntax error; instead, different JavaScript engines handle it differently. Some relocate it outside the flow-control block, others act as though you'd used a function expression instead.)
class declarations aren't hoisted; function declarations are.
Using the same name with two class declarations in the same scope is a syntax error; with a function declaration, the second one wins, overwriting the first.
class declarations at global scope don't create properties of the global object; function declarations do.
Just as a reminder, this is a function declaration:
function Foo() {
}
These are both function expressions (anonymous ones):
var Foo = function() {
};
doSomething(function() { /* ... */ });
These are both function expressions (named ones):
var Foo = function Foo() {
};
doSomething(function Foo() { /* ... */ });
I'm puzzled by something in my js. Normally I define functions like this:
function f(){
// do stuff
}
but I can also define functions like this:
f = function(){
// do stuff
}
I always thought there is no difference between them, but I now found that this is working:
f = function(){
alert('IT WORKS!!');
}
function createCallback(request){
request.done(function(data){
var html = '';
data['result'].forEach(function(bill){
html += "<tr onclick=\"f();\"><td>" + bill.title + "</td></tr>";
});
$("#someId").html(html);
});
}
but when I define f as follows:
function f(){
alert('IT WORKS!!');
}
and I click on the row, it gives a ReferenceError: f is not defined.
So I wonder: what is actually the difference between function f(){} and f = function(){}?
When you define a function without using var statement, by default the function will be defined as a property in the global scope.
Quoting MDN documentation on var,
Assigning a value to an undeclared variable implicitly creates it as a global variable (it becomes a property of the global object) when the assignment is executed. The differences between declared and undeclared variables are:
Declared variables are constrained in the execution context in which they are declared. Undeclared variables are always global.
Declared variables are created before any code is executed. Undeclared variables do not exist until the code assigning to them is executed.
Declared variables are a non-configurable property of their execution context (function or global). Undeclared variables are configurable (e.g. can be deleted).
Because of these three differences, failure to declare variables will very likely lead to unexpected results. Thus it is recommended to always declare variables, regardless of whether they are in a function or global scope. And in ECMAScript 5 strict mode, assigning to an undeclared variable throws an error.
So, when you define with function function_name(...){...} syntax, it will be in the current scope.
Since the second function definition is in the global scope tr's onclick can find f. Try using var statement like this
var f = function(){
alert('IT WORKS!!');
}
you will get the same ReferenceError: f is not defined.
You forgot the var statement. The function is defined globally when using f = function(){ }. This is why it’s accessible from the onclick handler and the other is not.
Please also read var functionName = function() {} vs function functionName() {} as suggested by #Nehal.
I'm trying to learn JS on codeacademy and I can't understand/get past this thing. Can someone please provide an answer and also an explanation of why is it so? Would deeply appreciate.
// This function tries to set foo to be the
// value specified.
function setFoo(val) {
// foo is declared in a function. It is not
// accessible outside of the function.
var foo = val;
}
setFoo(10);
// Now that we are outside the function, foo is
// not defined and the program will crash! Fix this
// by moving the declaration of foo outside of the
// function. Make sure that setFoo will still update
// the value of foo.
alert(foo);
You can see scope as a term meaning what variables you can reach at a specific "level" in the code. In JavaScript, these "levels" are defined by functions. Each function introduces a new level.
For example, take this sample code:
var a;
// you can access a at this level
function function1() {
var b;
// you can access a, b at this level
function function2() {
var c;
// you can access a, b, c at this level
}
}
So in your case, you should declare var foo; outside the function, preferably above it. Then you can set it inside setFoo with foo = val;. foo then refers to the one you declared in the level above setFoo.
foo is accessible both in setFoo and in the alert call that way; compare it with the above sample code (function1 is setFoo, a is foo and the alert call is in the top-most level. function2, b and c are not used in your case.).
// Create globale variable
// (You should not use globale variables!)
var foo;
// set value
function setFoo(val) {
foo = val;
}
setFoo(10);
// show value
alert(foo);
Just declare foo outside any function then it will be global:
var foo = null;
function setFoo(val) {
foo = val;
}
setFoo(10);
alert(foo);
Try it !
When you declare a variable in Javascript it is only visible to code that is in the same function as it is declared, or a function inernal to that function. Because foo is originally declared in the SetFoo function nothing outside of SetFoo is able to see it, so the call to alert fails as foo does not exist in the gloabl scope.
As the comments suggest, moving the declaration of foo out of the function and into the global scope (which you can think of as a catch-all function that contains everything) would allow you to use foo when calling alert.
var foo;
function setFoo(val) {
foo = val;
}
setFoo(10);
alert(foo); // No longer crashes
Every function in Javascript has it's own scope. That means that every variable you define there with the var keyword, will only be available within that function. That means that when you call setFoo(10), you create the variable foo, give it a value of five, after which it is immediately destroyed because it went out of scope.
There are multiple ways to solve this problem. The first would be to remove the var keyword. This would put foo in the global scope, which means that it's available everywhere. However, this is discouraged, you want to keep the global scope as uncluttered as possible, so that if you have javascript code provided by multiple people on the same page, they can't overwrite other people's variables. Another way to do it would be this:
function setFoo(val){
var foo = val;
alertfoo = function(){
alert(foo)
}
}
In this example, the only thing you're putting in the global scope is the alertfoo function, because you want that to be available everywhere. The alertfoo function is defined inside the setFoo function, this means that although foo should have gone out of scope after setfoo has been executed, it is kept in memory, because alertfoo has access to it.
This makes for some nice tricks. For example, let's say you're making a javascript library that will be included on other people's pages, you'll want to create a scope inside of which you can define variables, without polluting the global scope. The most common way to do this, is by declairing a self-executing function. This is a function which is executed immediately after being defined, it looks like this:
(function(){
//set variables you want to be global in your own code
var mainpage = document.getElementById('main');
//define functions you want to make available to other people in a way that puts them in the global scope
setMainElement = function(newmain){mainpage = newmain;}
})();
You can make this even better by making only one object global, and provide your interfae through the methods of that object, this way, you create a namespace with all the functions that your library contains. The next example uses an object literal to do this. In javascript, you can create an object by putting key/value pairs petween curly braces. the key/value pairs are properties of the object. for example:
(function(){
var privatevar = 10,otherprivate=20;
publicInterface = {
'addToPrivate': function(x){privatevar+=x;},
'getPrivate': function(){return private}
};
})();
Original code:
function setFoo(val) {
var foo = val;
}
setFoo(10);
alert(foo); // Crash!
Their advice to fix the crash:
Fix this by moving the declaration of foo outside of the function
I'm guessing you're confused as to what they mean by "outside of the function".
Try this edited code:
var foo = 5; // "var" declares the variable to be in this outer scope
function setFoo(val) {
foo = val; // but we can still access it in this inner scope...
}
setFoo(10);
alert(foo); // Displays a dialog box that says "10"
Variables defined in the function is valid only in the function
function setFoo(val) {
foo = val;
}
In JavaScript, new scopes are only created by functions