Some problems in function default parameters? - javascript

See this
let foo = 'outer';
function bar(func = x => foo) {
let foo = 'inner';
console.log(func());
}
bar(); //outer
I want to know why the output is 'outer' rather than 'inner'. I know JavaScript has lexical scope. This output makes me feels like that the function x => foo is defined out of function bar

I know js has lexical scope, This output makes me feels like that the function x => foo is defined out of function bar
Not exactly. It's in-betweeen: in the parameter declaration, which has its own scope with access to the other parameters but not the body. The default initialiser basically desugars to
let foo = 'outer';
function bar() {
var func = arguments[0] === undefined ? x => foo : arguments[0];
{
let foo = 'inner';
console.log(func());
}
}
bar(); // outer

Related

Why the ES6 code and ES5 code has diffent result after compiling by Babel.js?

The ES6 code:
let foo = 'outer';
function bar(func = x => foo){
let foo = 'inner';
console.log(func());
}
bar(); // outer
The Result is "outer".
The ES5 code compiled by Babel.js:
'use strict';
var foo = 'outer';
function bar() {
var func = arguments.length <= 0 || arguments[0] === undefined ? function (x) {
return foo;
} : arguments[0];
var foo = 'inner';
console.log(func());
}
bar(); // inner
The Result is "outer".
I don't know why they have different result.
It's a bug in Babel. Expressions in complex parameter lists should not be able to see declarations in the body of the function, but the code generated by Babel here evaluates the default parameter in the scope of the function, where the inner foo is visible.

Javascript- Variable Hoisting

This is a simple snippet, I just dont understand something.
The below code outputs 12, I understand that, because the var foo = 12; replaces the previous declaration of the variable.
<script>
var foo = 1;
function bar(){
if (!foo) {
var foo = 12;
}
alert(foo);
}
bar();
</script>
In the below code, it alerts 1 , which means the variable declared outside the function is accessible inside the function.
<script>
var foo = 1;
function bar(){
alert(foo);
}
bar();
</script>
But, in the below code, why it alerts undefined ?? I thought, it will alert 1, I am just assigning the previously declared variable to the new one.
<script>
var foo = 1;
function bar(){
if (!foo) {
var foo = foo;
}
alert(foo);
}
bar();
</script>
Variable declarations are pushed to the start of the function.
Therefore in reality the following is happening:
function bar(){
var foo;
if (!foo) {
foo = foo;
}
alert(foo);
}
Therefore you would need to change this to use window.foo so that you're referring to the global property rather than the function's property:
var foo = 1;
function bar(){
var foo;
if (!window.foo) {
foo = window.foo;
}
alert(foo);
}
bar();
Hoisting is slightly tricky. Function declarations are hoisted with the function assignment, but variable declarations are hoisted without the variable assignment. So the execution order of code is actually:
var foo;
var bar = function bar(){
var foo; // undefined
if (!foo) { // true
foo = foo; // foo = undefined
}
alert(foo);
}
foo = 1;
bar();
You could either use window.foo if you want to refer to the global variable foo, or better, just use a different variable name:
var foo = 1;
function bar(){
var baz = foo;
alert(baz);
}
bar();
The below code outputs 12, I understand that, because the var foo =
12; replaces the previous declaration of the variable.
var foo = 1;
function bar(){
if (!foo) {
var foo = 12;
}
alert(foo);
}
bar();
You are right because local variable overriding the global one.
In the below code, it alerts 1 , which means the variable declared
outside the function is accessible inside the function.
var foo = 1;
function bar(){
alert(foo);
}
bar();
You are correct. foo is declare in global scope so is accessible fron anywhere.
But, in the below code, why it alerts undefined ?? I thought, it will
alert 1, I am just assigning the previously declared variable to the
new one.
var foo = 1;
function bar(){
if (!foo) {
var foo = foo;
}
alert(foo);
}
bar();
This is a bit different. You are declaring a global variable and a local one with the same name. When your JavaScript program execution enters a new function, all the variables declared anywhere in the function are moved (or elevated, or hoisted) to the top of the function.
Another example:
var a = 123;
function f() {
var a; // same as: var a = undefined;
alert(a); // undefined
a = 1;
alert(a); // 1
}
f();
In javascript, until the ES5 specification, the scope is implemented only in terms of function body. The concept of block scope doesn't exist (really, will be implemented in the next javascript with the let keyword).
So, if you declare a variable var something; outside from function body, it will be global (in browsers global scope is the scope of the window object).
global variables
var something = 'Hi Man';
/**
* this is equal to:
**/
window.something = 'Hi Man';
If your code doesn't run in strict mode, there is another way to declare a global variable: omitting the var keyword. When the var keyword is omitted the variable belongs (or is moved) to the global scope.
example:
something = 'Hi Man';
/**
* this is equal to:
**/
function someFunction() {
something = 'Hi Man';
}
Local Variables
Because the non-existence of block scopes the only way to declare a local variable is to define it in a function body.
Example
var something = 'Hi Man'; //global
console.log('globalVariable', something);
function someFunction() {
var something = 'Hi Woman';
console.log('localVariable', something);
/**
* defining variable that doesn't exists in global scope
**/
var localSomething = 'Hi People';
console.log('another local variable', localSomething);
}
someFunction();
console.log('globalVariable after function execution', something);
try {
console.log('try to access a local variable from global scope', localSomething);
} catch(e) { console.error(e); }
As you can see in this example, local variables don't exist outside from their scope. This means another thing... If you declare, with the var keyword, the same variable in two different scopes you'll get two different variables not an override of the same variable (name) defined in the parent scope.
If you want to "override" the same variable in a child scope you have to use it without the var keyword. Because of the scope chain if a variable dosn't exist in a local scope it will be searched on their parent scope.
Example
function someFunction() {
something = 'Hi Woman';
}
var something = 'Hi Man';
console.log(1, 'something is', something);
someFunction();
console.log(1, 'something is', something);
Last thing, variable hoistment.
As I wrote below, at the moment, there isn't any way to declare a variable in some point of your code. It is always declared at the start of it scope.
Example
function someFunction() {
// doing something
// doing something else
var something = 'Hi Man';
}
/**
* Probably you expect that the something variable will be defined after the 'doing
* something else' task, but, as javascript works, it will be defined on top of it scope.
* So, the below snippet is equal to:
**/
function someFunction1() {
var something;
// doing something
// doing something else
something = 'Hi Man';
}
/**
* You can try these following examples:
*
* In the someFunction2 we try to access on a non-defined variable and this throws an
* error.
*
* In the someFunction3, instead, we don't get any error because the variable that we expect to define later will be hoisted and defined at the top, so, the log is a simple undefined log.
**/
function someFunction2() {
console.log(something);
};
function someFunction3() {
console.log('before declaration', something);
var something = 'Hi Man';
console.log('after declaration', something);
}
This happens because in javascript there are two different steps of a variable declaration:
Definition
Initialization
And the function3 example becomes as following:
function3Explained() {
var something; // define it as undefined, this is the same as doing var something = undefined;
// doing something;
// doing something else;
something = 'Hi Man';
}
IMHO it doesn't have anything to do with function declaration and hoisting ,
declaring the var with var inside function you are creating a variable in the function's isolated scope, this is why you get undefined.
var foo = 1;
function funcOne() {
var foo = foo;
alert('foo is ' + foo);
};
funcOne();
var bau = 1;
function funcTwo() {
bau = bau;
alert('bau is ' + bau);
};
funcTwo();
fiddle

Javascript hoisting - David Shariff quiz

The question is, what will the following alert:
function bar() {
return foo;
foo = 10;
function foo() {}
var foo = '11';
}
alert(typeof bar());
and the answer is, function.
My questions:
Isn't bar() being replaced by its return value? If no, why?
Isn't foo = 10; being hoisted to the top? (hoisting)
You can look at it this way:
function bar() {
var foo = function() {};
return foo; // function ends here
foo = 10;
foo = '11';
}
The other two assignment statements aren't happening.
Only declarations are hoisted in JavaScript.
For function declarations, that includes their entire statement body (which is empty in the case of foo). However, with vars, the assignments aren't considered part of the declaration and will remain where the statement was placed. (2)
To the engine, bar() appears to be:
function bar() {
// hoisted
function foo() {}
var foo; // no-op, `foo` was already declared by `function foo() {}`
// remaining statements
return foo;
// unreachable code following a `return`
foo = 10;
foo = '11'; // separated from `var foo;`
}
The resulting typeof being function is referring to the type of function foo() {}, a reference to which is what bar() returns. (1)
alert(bar().toString()); // "function foo() {}"

Scope of variables (Hoisting) in Javascript

One of my friends was taking an online quiz and he asked me this question which I could not answer.
var global = false;
function test() {
global = true;
return false;
function global() {}
}
console.log(global); // says false (As expected)
test();
console.log(global); // says false (Unexpected: should be true)
If we assume that functions are hoisted at the top along with var variables, let's try this one.
var foo = 1;
function bar() {
return foo;
foo = 10;
function foo() {}
var foo = 11;
}
bar();
console.log(foo); //says 1 (But should be 11) Why 1 this time ??
Here is a JSBin Demo and JSBIN Demo2 to play with.
PS: If we remove function global() {} from test(), then it runs fine. Can somebody help me understand why is this happening ?
var statements and function declaration statements are "hoisted" to the top of their enclosing scope.
Therefore, the function global(){} in your function creates a local global name.
Assigning to global inside your functions binds to this local name. Here's how you can "rewrite" it using hoisting to understand how the compiler sees it:
function test() {
var global = function() {}; // hoisted; 'global' now local
global = true;
return false;
}
I'll answer the second part of your question,
If we assume that functions are hoisted at the top along with var variables
bar();
console.log(foo); //says 1 (But should be 11) Why 1 this time ??
You should try console.log(bar()); console.log(foo); instead. However, what hoisting does to your function is this:
function bar() {
var foo;
function foo() {}
return foo;
foo = 10;
foo = 11;
}
So you should expect to get the function returned, since your variable assignments are after the return statement. And both the var and the function declaration make foo a local variable, so the global foo = 1 is never changed.

javascript If functions are objects then why doesn't this work

var foo = function () { this.bar = 1; }
>> foo.bar
undefined
How do I access the property of a function?
You syntax is wrong:
function foo() { this.bar = 1; }
var a = new foo();
a.bar; // 1
That is a definition. You need to instantiate it.
var foo = function () { this.bar = 1; }
>> new foo().bar
Another option:
var foo = function () { this.bar = 10; return this; } ();
console.log(foo.bar);
Read about self executing functions here:
What is the purpose of a self executing function in javascript?
The problem here is that you've only defined foo and not actually executed it. Hence the line this.bar = 1 hasn't even run yet and there is no way for bar to be defined.
The next problem is that when you run foo it will need a context which this will be defined in. For example
var x = {}
foo.apply(x);
x.bar === 1 // true
Or alternatively you could run foo as a constructor and access bar on the result
var x = new foo();
x.bar === 1 // true

Categories

Resources