As I understand the scope of const is curly braces (block). However, when I run the following code in browser (FF) it doesn't give any error. Is the following JS code right? Please, explain.
<script type="text/javascript">
{
const Foo = "foo";
}
</script>
<div></div>
<script type="text/javascript">
{
Foo = null;
}
</script>
You will not get error because,
Below code says you are using const variable of Foo inside this code block, the const Foo will bot be accessible out side of the block
{
const Foo = "foo";
}
Below code says you are assigning the variable Foo with value of null, which will bind to window object,
{
Foo = null;
}
so Foo = null; which binds to window object and const Foo='foo' is a constant variable for the particular code block
So when you are assign Foo=null it assigns the variable to window object and you can access it like ,
window.Foo
i.e. any variable which declare without var it will bind to window object,
You are aware that using const will create a constant in a given scope. Look at your example:
<script type="text/javascript">
{
const Foo = "foo";
}
</script>
<div></div>
<script type="text/javascript">
{
Foo = null;
}
</script>
You can reduce the above to the following code:
{
const Foo = "foo";
}
{
Foo = null;
}
Since you have declared and initialized Foo in a scope (denoted by using { and }), then Foo is only known to that scope. Let's call that scope A. When issuing Foo = null;, you are in a different scope: B. When assigning a value to a variable, the engine always checks if the variable name is not bound in the current execution context. In short, it checks
if Foo exists in the local scope: the answer is no. Your Foo = "foo" is only known to the scope A. Not in the current scope.
if Foo exists in the scope chain: the answer is no. There is no declarations made in the parent scope.
if Foo is known to the global execution context (aka window scope): the answer is no.
End result: the assignment will occur. But since you did not have provided any assignment statements: const, let or var. Therefore, Foo=null will be added to the window scope. If you do window.Foo, you will get a response with null.
However, it has to be noted that there should be an error. But Javascript is a language that "serves" the developer. Instead of spitting you with an error, it will silent that error and hook Foo to the window object. If you use strict mode, then it will throw an error. (please consult the MDN page for further information)
To comprehend it a better, look to the following examples that is executed in a non-strict environment and think first if there would be an error or not.
<script type="text/javascript">
{
const Foo = 'hello';
Foo = 555; // success or fail ?
}
</script>
The answer is no. You are aware of that. It fails the first check: Foo is already bound in the same scope.
<script type="text/javascript">
{
const Foo = 'hello';
{
Foo = 555; // success or fail ?
}
}
</script>
The answer is yes. It will fail because it fails the second check (see the list above). Foo = 555; is called in a scope: B. Scope B has a parent scope: A where Foo is known.
Now, something tricky:
<script type="text/javascript">
{
window.Foo = 'hello';
{
Foo = 555; // success or fail ?
}
}
</script>
What do you think? ๐
...
it works. Do you not believe me: check it here below:
{
window.Foo = 'hello world';
console.log('window.Foo?', window.Foo); // shows hello world
{
Foo = 555;
console.log('window.Foo?', window.Foo); // shows 555
}
}
that is because adding variables to the window scope (although it is not recommendable to do so) does not make it read-only. You can change it afterwards as desired.
Related
We are given a code snippet in run time along with a name of a variable used in code. We want to evaluate the given code and log the value of the variable.
Example:
suppose our code is var foo = "Blah"; and the name of the var is foo.
eval('var foo = "Blah"; let varName = "foo"; console.log(this[varName]);');
yields Blah.
yet
new Function('var foo = "Blah"; let varName = "foo"; console.log(this[varName]);')();
yields undefined.
Is there a way to make get this to work with new Function?
With new Function, you're creating a new function. The code that is executed looks something like:
function someFunction() {
var foo = "Blah"; let varName = "foo"; console.log(this); console.log(this[varName]);
}
someFunction();
There, foo is in local scope of the someFunction. It's not global, so variables declared with var inside the function don't get put onto the global object.
In contrast, eval runs on the top level. Your eval code that is executed looks something like:
var foo = "Blah"; let varName = "foo"; console.log(this[varName]);
which is all on the top level, so the foo variable that was declared gets put onto the global object, the this.
Substitute the variable name into the function definition directly, rather than using this.
let varName = 'foo';
new Function(`var ${varName} = "Blah"; console.log(${varName});`)();
Everything here is about Scope. Global Scope and Block Scope.
Global Scope
Variables declared Globally (outside any function) have Global Scope.
var bikeName = "Honda";
// code here can use bikeName
function myFunction() {
// code here can also use bikeName
}
and
var greeter = "hey hi";
function newFunction() {
var hello = "hello"; //Variables declared Locally (inside a function) have Function Scope.
}
console.log(hello); // error: hello is not defined
Here, greeter is globally scoped because it exists outside a function while hello is function scoped. So we cannot access the variable hello outside of a function.
Block Scope
A block is a chunk of code bounded by {}. A block lives in curly braces.
let times = 4;
if (times > 3) {
let hello = "say Hello instead";
console.log(hello);// "say Hello instead"
}
console.log(hello) // hello is not defined
You should read about them. Things will get clear
Hence in your case:
new Function('var foo = "Blah"; let varName = "foo"; console.log(this[varName]);')();
Everything inside function has function scope and will not be available global!
Is it valid to use variable names again and again? For example:
function clicks() {
var foo = document.getElementById("cat");
foo.click();
var foo = document.getElementById("dog");
foo.click(); // Again! This works, but may be it is not valid?
}
Or I should use unique variable names, like below?
function clicks() {
var foo1 = document.getElementById("cat");
foo1.click();
var foo2 = document.getElementById("dog");
foo2.click();
}
Yes, it is valid. This is because the interpreter "hoists" the variable declaration. That is, it moves the declaration to the top of the current function scope.
To the interpreter, your code "looks" like this:
function clicks () {
var foo;
foo = /* something */
foo = /* something */
}
Now, if you don't want this behavior, you can use let, which stays at the current scope. For example:
function bar () {
if (true) {
let foo = 5
}
console.log(foo) // not defined
// you would need to declare foo again with `let foo = ...`
}
There's nothing wrong with overwriting the value of a variable. Do note that it can make the behavior of your application more confusing, e.g., if someone reading through your code misses where you redeclare the variable. Note that after you've declared it once you can just do foo = document.getElementById("dog"); instead of var foo = document.getElementById("dog");.
Technically, yes, you can use multiple variables with the same name but they all of them will share the same entity. It will be just one variable under that name.
But practically you should avoid that.
You can't re instantiate a variable in js so the var foo twice should not even work:/
the solution is to use something like this
function clicks() {
var foo = document.getElementById("cat");
foo.click();
//remove var in this line...
foo = document.getElementById("dog");
foo.click(); // Again! This works, but may be it is not valid?
}
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.
I have been proved I do not truly understand javascript closure, and I am being confused by the following codes. I thought fxn would access the outside foo, but it actually print out "underfined". Why??
var foo = "hello";
function fxn(){
alert(foo);
var foo = "test"
}
fxn();
This is because in JavaScript, variables get hoisted, which means
Variables are initialised to undefined when created. A variable with
an Initialiser is assigned the value of its AssignmentExpression when
the VariableStatement is executed, not when the variable is created.(ES5 ยง12.2)
Thus, semantically, your code would be equivalent, to the following...
var foo = "hello";
function fxn(){
var foo; //Variables are initialised to undefined when created
alert(foo);
foo = "test"; //A variable with an *Initialiser* is assigned the value of its *AssignmentExpression* when the *VariableStatement* is **executed**
}
fxn();
You define your variable foo outside your function. If you repeat calls for var, you redefine the variable inside the function and it loses its allocation.
Remove var in the function to access foo into the function fnx.
var foo = "hello";
function fxn(){
alert(foo);
foo = "test";
}
fxn();
Jsfiddle
What is the difference between declaring a variable with this or var ?
var foo = 'bar'
or
this.foo = 'bar'
When do you use this and when var?
edit: is there a simple question i can ask my self when deciding if i want to use var or this
If it is global code (the code is not part of any function), then you are creating a property on the global object with the two snippets, since this in global code points to the global object.
The difference in this case is that when the var statement is used, that property cannot be deleted, for example:
var foo = 'bar';
delete foo; // false
typeof foo; // "string"
this.bar = 'baz';
delete bar; // true
typeof bar; "undefined"
(Note: The above snippet will behave differently in the Firebug console, since it runs code with eval, and the code executed in the Eval Code execution context permits the deletion of identifiers created with var, try it here)
If the code is part of a function you should know that the this keyword has nothing to do with the function scope, is a reserved word that is set implicitly, depending how a function is called, for example:
1 - When a function is called as a method (the function is invoked as member of an object):
obj.method(); // 'this' inside method will refer to obj
2 - A normal function call:
myFunction(); // 'this' inside the function will refer to the Global object
// or
(function () {})();
3 - When the new operator is used:
var obj = new Constructor(); // 'this' will refer to a newly created object.
And you can even set the this value explicitly, using the call and apply methods, for example:
function test () {
alert(this);
}
test.call("hello!"); //alerts hello!
You should know also that JavaScript has function scope only, and variables declared with the var statement will be reachable only within the same function or any inner functions defined below.
Edit: Looking the code you posted to the #David's answer, let me comment:
var test1 = 'test'; // two globals, with the difference I talk
this.test2 = 'test'; // about in the beginning of this answer
//...
function test4(){
var test5 = 'test in function with var'; // <-- test5 is locally scoped!!!
this.test6 = 'test in function with this'; // global property, see below
}
test4(); // <--- test4 will be called with `this` pointing to the global object
// see #2 above, a call to an identifier that is not an property of an
// object causes it
alert(typeof test5); // "undefined" since it's a local variable of `test4`
alert(test6); // "test in function with this"
You can't access the test5 variable outside the function because is locally scoped, and it exists only withing the scope of that function.
Edit: In response to your comment
For declaring variables I encourage you to always use var, it's what is made for.
The concept of the this value, will get useful when you start working with constructor functions, objects and methods.
If you use var, the variable is scoped to the current function.
If you use this, then you are assigning a value to a property on whatever this is (which is either the object the method is being called on or (if the new keyword has been used) the object being created.
You use var when you want to define a simple local variable as you would in a typical function:-
function doAdd(a, b)
{
var c = a + b;
return c;
}
var result = doAdd(a, b);
alert(result);
However this has special meaning when call is used on a function.
function doAdd(a, b)
{
this.c = a + b;
}
var o = new Object();
doAdd.call(o, a, b);
alert(o.c);
You note the first parameter when using call on doAdd is the object created before. Inside that execution of doAdd this will refer to that object. Hence it creates a c property on the object.
Typically though a function is assigned to a property of an object like this:-
function doAdd(a, b)
{
this.c = a + b;
}
var o = new Object();
o.doAdd = doAdd;
Now the function can be execute using the . notation:-
o.doAdd(a, b);
alert(o.c);
Effectively o.doAdd(a, b) is o.doAdd.call(o, a, b)
var foo = 'bar'
This will scope the foo variable to the function wrapping it, or the global scope.
this.foo = 'bar'
This will scope the foo variable to the this object, it exactly like doing this:
window.foo = 'bar';
or
someObj.foo = 'bar';
The second part of your question seems to be what is the this object, and that is something that is determined by what context the function is running in. You can change what this is by using the apply method that all functions have. You can also make the default of the this variable an object other than the global object, by:
someObj.foo = function(){
// 'this' is 'someObj'
};
or
function someObj(x){
this.x=x;
}
someObj.prototype.getX = function(){
return this.x;
}
var myX = (new someObj(1)).getX(); // myX == 1
In a constructor, you can use var to simulate private members and this to simulate public members:
function Obj() {
this.pub = 'public';
var priv = 'private';
}
var o = new Obj();
o.pub; // 'public'
o.priv; // error
Example for this and var explained below:
function Car() {
this.speed = 0;
var speedUp = function() {
var speed = 10; // default
this.speed = this.speed + speed; // see how this and var are used
};
speedUp();
}
var foo = 'bar'; // 'var can be only used inside a function
and
this.foo = 'bar' // 'this' can be used globally inside an object