Javascript - How are things broken? - javascript

var myName = 4;
function myName() {
console.log("xxxx");
}
console.log(typeof myName); //Number
var myNamex;
function myNamex() {
console.log("xxxx");
}
console.log(typeof myNamex); //function
Please refer the fiddle - http://jsfiddle.net/s8a7m1hk/
console.log(typeof myName);
The above log statement logs different value, the only difference is that the variable is assigned a value in one place, and not in another.
Can you tell me how are both code snippet broken down, considering hoisting, closure or any that can be applied.

Your problem is very simple, once you have the hoisting in the right order. Effectively your code looks like this:
function myName() {
console.log("xxxx");
}
function myNamex() {
console.log("xxxx");
}
var myName;
var myNamex;
myName= 4;
console.log(typeof myName); //Number
console.log(typeof myNamex); //function
All the declarations (var statements and function declarations) are hoisted to the top. The assignment of the value 4 is not hoisted, so takes place after the declarations, so myName is 4 when it's logged. You never assign any other value to myNamex, so it is not changed and is still the function.

The spec will tell you the precise algorithm. Below, context is the [[Scope]] of the enclosing LexicalEnvironment, or the global object.
This is roughly what happens:
context.myName = function myName() { ... }; // From evaluating 1st function statement.
context.myNamex = function myNamex() { ... }; // From evaluating 2nd function statement.
context.myName; // From evaluating var declaration statement myName. Does nothing because property already exists.
context.myNamex; // From evaluating var declaration statement myNamex. Does nothing because property already exists.
context.myName = 4; // Changes the existing property to point to the number instead of the function myName.
console.log(typeof myName); // Number - for reasons that should now be clear.
console.log(typeof myNamex); // function - for reasons that should now be clear.

Related

JavaScript object related question that what will be the output of below code?

var x = 3;
var one = {
x:2,
two: {
x:1,
three:function(){
return this.x;
}
}
}
var go = one.two.three;
console.log(one.two.three() + "" + go());
Anyone can explain to me why output coming 13 why not 1-undefined?
this keyword has a different binding that can change during runtime, depending on how the function was invoked.
When a function is on an object, and is accessed through that object, it's this context will be that object (unless explicitly bound otherwise, but I'll add notes on that later). This means this.x is referencing the same variable as one.two.x
When you reference that same function into a global variable, the this context becomes the global space (e.g. the window object on browsers, or globalThis in NodeJS). When this happens, this.x is now referencing global variable x.
There are other situations where this context rules are different, such as function closures or class functions.
Functions also have .bind method that returns a new function with an explicitly bound this variable.
e.g:
var x = 3;
var one = {
x:2,
two: {
x:1,
three:function(){
return this.x;
}
}
}
one.two.three = one.two.three.bind(one);
var go = one.two.three;
console.log(one.two.three() + "" + go()); // prints 22
There are also arrow functions, which implicitly have the this context bound to it's lexical scope... e.g:
var x = 3;
var one = {
x:2,
two: {
x:1,
three: () => {
return this.x;
}
}
}
var go = one.two.three;
console.log(one.two.three() + "" + go()); // prints 33
This above example prints 33, because the lexical scope is the global scope, thus this.x is referencing global variable x.
Hope this answers your question without creating more questions.
Further Reading:
this keyword
Interesting. I think it has something to do with scopes.
console.log(one.two.three() + "" + go());
//equals console.log(1 + "" + 3);
will output 13 (String) because:
one.two.three() returns 1
go() returns 3
those numbers are concatenated into String with "" (empty string) in between (instead of - as you may have asked)
Why go() returns 3
var x = 3;
// var go = one.two.three;
// equals
var go = function() {
return this.x
}
The declaration var go = one.two.three; assigns one.two's three method as a function into the variable go in the global scope. The same scope with go, one, and x (with the value 3), that was declared before declaring one and go (var x= 3;).
Based on your whole codes, this.x's this is in the global scope. and this.x is 3. So running go() returns 3.
one.two.three is a global function
→ notice there's no (), so assigning a function to global scope's variable go will make the function's scope global.
→ go function is run under global's scope
Why one.two.three() returns 1
Well, one.two.three is a method inside the object two, which is inside the object one. While the definition looks the same,
function() {
return this.x;
}
when you run three method of two object, return this.x's this refers to the method's parent object (which is two, three's parent object is two).
So,
this.x refers to
two.x which is 1.
Hence, in this case return this.x; outputs 1.
one.two.three() is 1
→ notice the () which means run the function
→ three method is run under two's scope
Addition
This will output 1-undefined because:
y is not defined in the global/one/go scope
I use - as a delimiter in console.log
var one = {
y:2,
two: {
y: 1,
three:function(){
return this.y;
}
}
}
var go = one.two.three;
console.log(one.two.three() + "-" + go());
To assign an object method to a variable, it needs to be bandaged using the bind() function, and if the global variable window is passed to the context, the answer will be 13
*var go = one.two.three.bind(window);*
if the object is one the answer will be 12
*var go = one.two.three.bind(one);*
if the object is two the answer will be 11
*var go = one.two.three.bind(two);*

why does var behave differently in a with statement depending on whether or not the passed object has a property with the same name?

function foo(obj) {
with(obj) {
var x = 2;
}
console.log(x);
}
let o1 = {};
foo(o1); // 2 (x is visible even outside the with statement because of *var*)
function foo2(obj) {
with(obj) {
var x = 2;
}
console.log(x);
}
let o2 = {
x: 1
};
foo2(o2); // undefined (why?)
I'm reading along Kyle Simpson's Scope & Closures book from the YDKJS series and I was able to understand all of the quirks of with statements and how with(obj) { a = 1 } is functionally different from obj.a = 1 despite having been intended as a shorthand for it in cases of long object names and having to constantly reference it. This is because the object's properties are treated as lexically defined identifiers in that scope (a vs obj.a), and that in sloppy mode, one side effect of this is that if the object you pass into a with statement doesn't have a property that you are trying to assign to, a global variable of that name will be created. Still, armed with all this knowledge and more, I don't quite understand why the code above behaves the way it does. Why does foo(o2) log undefined?
The difference in behaviour can be accounted for by this behaviour, described in (for instance) the following note in ECMAScript 2022 Language Specification sect 14.3.2.1:
NOTE: If a VariableDeclaration is nested within a with statement and the BindingIdentifier in the VariableDeclaration is the same as a property name of the binding object of the with statement's object Environment Record, then step 5 will assign value to the property instead of assigning to the VariableEnvironment binding of the Identifier.
In the first case:
function foo(obj) {
with(obj) {
var x = 2;
}
console.log(x);
}
let o1 = {};
foo(o1);
because obj has no x property, the var statement is hoisted to the top of the function and is therefore visible beyond the scope of the with statement.
In the second case:
function foo2(obj) {
with(obj) {
var x = 2;
}
console.log(x);
}
let o2 = {
x: 1
};
foo2(o2);
x exists on obj, so we satisfy the conditions laid out in the quoted note, and therefore the value is assigned to the property and no hoisted variable is created. Now, there's no x outside the scope of the with statement.

Output is giving "1undefined" for something that should be "1function" for sure. Where is the Mistake? [duplicate]

This question already has answers here:
typeof of a function not returning correct value but undefined
(2 answers)
Closed 4 years ago.
The example below must output for sure function, as the value of x is "1" (integer) and then we are passing a parameter named "f" (of a function). It doesn't matter whether this function does something or is blank, but I am sure -- that variable f --> points to function. so typeof(f) will surely return function.
Now, adding of an integer and "function" (as typeof always returns a string) is going to be a string --> 1function.
Now, amazingly the output is "1undefined". How?
<script>
var x = 1;
if (function f(){}) {
x += typeof f;
}
console.log(x);
</script>
As per answer by Ellepsis that declarations don't take inside if() braces and only boolean is returned. Explain this then, why is it returning 3?
<script>
var x = 1;
if (y = 2) {
x = x + y;
}
console.log(x);
</script>
if (function f(){}) {
A function declaration will create a variable with the same name in the current scope.
A function expression will only create a variable with the same name inside itself.
So the variable f only exists:
if (function f(){ })
^^^^
here
The function expression itself evaluates as a function, which the if statement picks up as a truthy value but there is no f variable in scope.
Explain this then, why is it returning 3?
You are explicitly assigning a value to a variable. That variable remains in scope.
You would get the same effect if you did this:
if (f = function f(){}) {
So:
(function f(){})
Creates a function
Names the function f
Creates a variable inside the function called f containing a reference to a function
Evaluates as a function, which is a true value, which is tested by the if
While:
(f = function f(){})
Creates a function
Names the function f
Creates a variable inside the function called f containing a reference to a function
Creates a variable f outside the function
function f(){} evaluates as a function and is assigned to f by the =
f = function f(){} also evaluates as a function, which is a true value, which is tested by the if
You are getting undefined because function f is not defined in the code anywhere. Writing the function inside an if statement does not define the function. The code just assumes it as a truthy value, a condition for the if statement but in real f does not exists. You can define f outside and it will work fine or you can just perform the assignment in the if and then also it will work
var x = 1;
if (f=function(){}) {
x += typeof f;
}
console.log(x);
var x = 1;
var f;
if ( f = function() {} ) {
x += typeof f;
}
console.log(x);

What is the use of just declaring variables

I have been using python for a while now, and have just started learning javascript. In javascript you can, as I understand it, declare a variable without assigning a value to it (var cheese compared to var cheese = 4) in what situation would you want to declare a variable but not assign a value to it straight away?
Consider this snippet.
if (someCondition) {
var x = 5;
} else if (someOtherCondition) {
var x = 4;
}
if (x) {
doFunc();
}
Since x needs to exist for the doFunc to run, you simply add an undefined declaration above. var x; so that the if (x) doesn't return an error.
You do this when you want the value of the variable to be undefined.
var cheese;
console.log(cheese); // undefined
It's simpler than
var cheese = undefined;
The undefined value doesn't seem much useful, but this will allow to assign some other value later.
var cheese; can be perfectly useful (even if you never assign anything to it). Of course it's a shorter way to type var cheese = undefined;, but that's not the only reason…
Using var declares a local variable, and this has a nice property: it hides variables from parent scopes.
There's another part to your question:
If we're going to assign a value to var cheese anyway: why not assign immediately?.
Answer: it may be fine for your algorithm to return cheese without ever assigning anything to it — i.e. "undefined is valid".
Here's an example which illustrates how var hides variables from parent scopes:
var a = 3;
console.log(a); // prints 3; "a" is defined in this scope
function findEvenNumber(numbers) {
var a; // we declare this local variable, to ensure that we do _not_ refer to the variable that exists in the parent scope
numbers.forEach(function(number) {
if (number % 2 === 0) {
a = number;
}
});
return a; // if no even number was found, it returns undefined (because we never assigned anything to a)
}
findEvenNumber([1, 2]); // returns 2;
console.log(a); // prints 3; the "a" in this scope did not get overwritten by the function
Speculation: maybe the var cheese; syntax exists in ECMA to enable programmers to declare all variables at the beginning of their function. Such a convention was enforced by the C89 compiler, and some people grew fond of it.

Does the variable of the current element in a Javascript for-each loop need defined outside the loop?

The W3Schools example for a JS for-each loop (http://www.w3schools.com/js/js_loop_for.asp) is
var person = {fname:"John", lname:"Doe", age:25};
var text = "";
var x;
for (x in person) {
text += person[x];
}
and I'm wondering if there's any particular reason why x is defined outside of the loop if it's only used inside the loop in that particular example, or if that's necessary condition for defining a for-each loop, and if so, why?
This is(/was) an old convention, meant largely to indicate that x does not exist only inside the loop.
Declaring variables at the top of a function is not necessary and is variously encouraged/discouraged by different style tools. It can be convenient to group variable declarations in one place, but may increase the distance between declaration and use (generally considered a bad thing).
In JS, the var declaration works at function-scope, so variables are hoisted to the top of the nearest function and live for the duration of the function. See:
function foo() {
for (var i = 19; i > 0; --i) {
console.log(typeof i); // number
}
console.log(typeof i); // number
}
foo();
Because the variable is accessible throughout the function, it is declared at the start of the function (C used to require this).
ES6 has changed this with the let statement, which introduces the more common block-level scoping. With let, the variable is only available inside of the loop:
function foo() {
for (let i = 19; i > 0; --i) {
console.log(typeof i); // number
}
console.log(typeof i); // undefined
}

Categories