What is the major difference between JavaScript declared and undeclared variables, since
the delete operator doesn't work on declared variables?
var y = 43; // declares a new variable
x = 42;
delete x; // returns true (x is a property of the global object and can be deleted)
delete y; // returns false (delete doesn't affect variable names)
Why does this happen? Variables declared globally are also the properties of the window object, so why can't it be deleted?
Declared and undeclared global variables
The mechanism for storing and accessing them is the same, but JavaScript treats them differently in some cases based on the value of the configurable attribute (described below). In regular usage, they should behave the same.
Both exist in the global object
Below are some comparisons of declared and undeclared global variables.
var declared = 1; // Explicit global variable (new variable)
undeclared = 1; // Implicit global variable (property of default global object)
window.hasOwnProperty('declared') // true
window.hasOwnProperty('undeclared') // true
window.propertyIsEnumerable('declared') // true
window.propertyIsEnumerable('undeclared') // true
window.declared // 1
window.undeclared // 1
window.declared = 2;
window.undeclared = 2;
declared // 2
undeclared // 2
delete declared // false
delete undeclared // true
delete undeclared // true (same result if delete it again)
delete window.declared // false
delete window.undeclared // true (same result if delete it yet again)
delete window.undeclared // true (still true)
Both declared and undeclared global variables are properties of the window object (the default global object). Neither one is inherited from a different object through the prototype chain. They both exist directly in the window object (since window.hasOwnProperty returns true for both).
The configurable attribute
For declared global variables, the configurable attribute is false. For undeclared global variables, it's true. The value of the configurable attribute can be retrieved using the getOwnPropertyDescriptor method, as shown below.
var declared = 1;
undeclared = 1;
(Object.getOwnPropertyDescriptor(window, 'declared')).configurable // false
(Object.getOwnPropertyDescriptor(window, 'undeclared')).configurable // true
If the configurable attribute of a property is true, the attributes of the property can be changed using the defineProperty method, and the property can be deleted using the delete operator. Otherwise, the attributes cannot be changed, and the property cannot be deleted in this manner.
In non-strict mode, the delete operator returns true if the property is configurable, and returns false if it's non-configurable.
Summary
Declared global variable
Is a property of the default global object (window)
The property attributes cannot be changed.
Cannot be deleted using the delete operator
Undeclared global variable
Is a property of the default global object (window)
The property attributes can be changed.
Can be deleted using the delete operator
See also
delete operator
Object.defineProperty
Object.getOwnPropertyDescriptor
hasOwnProperty
Strict mode
The main difference is when you're declaring variables inside a function. If you use var when you're declaring a variable inside a function, then that variable becomes a local variable. However, if you don't use var, then the variable becomes a global variable no matter where you declare it (inside or outside a function).
When any variable is created via Variable Declaration in JavaScript , these properties are created with "DontDelete" attribute , which basically means that variable you created cannot be Deleted using "delete" expression. All the functions, arguments , function parameters by default are created with this DontDelete attribute. You can think of DontDelete as a flag.
var y = 43;
delete y; //returns false because it is has a DontDelete attribute
Whereas Undeclared assignment doesn't set any attributes like DontDelete . So when we apply delete operator on this undeclared variable , it returns true.
x = 42;
delete x; //returns true because it doesn't have a DontDelete attribute
The difference between property assignment and variable declaration — latter one sets DontDelete, whereas former one doesn’t. That's why undeclared assignment creates a deletable property.
Link on how exactly delete operator works
delete is only effective on an object's properties. It has no effect on variable or function names.
In your case x = 42; declares variable X and makes it the property of the Global object. So it returns true.
And var y = 43; declares a global variable which is not part of any object so it returns false.
Related
Using Chrome I passed in console this name of global variable:
multiConfig
And get result:
multi: {type: "1", containerId: "mp", go: {…}}
__proto__: Object
I try to delete this variable by click:
if (window['multiConfig']) {
delete window['multiConfig'];
}
And I get this error:
ERROR TypeError: Cannot delete property 'multiConfig' of [object Window]
Why?
You cannot delete a window variable, but you can unset it:
window['multiConfig'] = undefined;
Reason:
The window object is not configurable.
You can refer to this - How to unset a JavaScript variable?
Variables declared with var are added as properties on the global window object and cannot be deleted with the delete operator.
From MDN - var:
In the global context, a variable declared using var is added as a
non-configurable property of the global object. This means its
property descriptor cannot be changed and it cannot be deleted using
delete.
Reason for this is also explained:
The property created on the global object for global variables, is set
to be non-configurable because the identifier is to be treated as a
variable, rather than a straightforward property of the global object.
JavaScript has automatic memory management, and it would make no sense
to be able to use the delete operator on a global variable.
Also note that trying to delete a property set on of global window object for variables declared with var fails silently in non-strict mode and throws a TypeError in strict-mode.
Also note that you can delete a property from the window object if is set explicitly.
var a = 1; // can't be deleted
window.b = 2; // can be deleted
delete window.a;
delete window.b;
console.log(window.a);
console.log(window.b);
How come a properly declared global variable can't be deleted?
I don't know if this is across all program languages, but I know that in JavaScript it can't be deleted.
Source: Javascript the Definitive Guide O'Reilly.
When you use global variables and you want to be able to delete them, you should easily define them in a global object, without using var in your statement, like:
let's say you want to define a global varible in your code, and you need to be able to delete them whenever you want, so if you do:
function myfunc(){
var name = "Robert";
console.log(delete name);
}
and call it in your console you would have, false as the result of delete statement, which means it has not got deleted, but if you do it like:
function myfunc(){
var obj = {};
obj.name = "Robert";
console.log(delete obj.name);
}
then your result would be true, which means it gets deleted now.
now for global object if you create it like:
window.myobj = {};
then you can delete it and it actually get deleted:
delete window.myobj;
or
delete window["myobj"];
The thing is when you create your variable using var, in the window context, although it is on object in the window, but it doesn't get deleted, for instance if you do:
var myobj = {};
in the browser dev console, it gets defined in the window, and you can have it like:
window.myobj
but you can not delete it, because you have defined it in a var statement.
But do not forget to set it to null, if you really want it to get deleted from memory:
window["myobj"] = null;
delete window["myobj"];
As was stated in this answer by user Eric Leschinski
Delete a variable in JavaScript:
Summary:
The reason you are having trouble deleting your variable in JavaScript
is because JavaScript won't let you. You can't delete anything created
by the var command unless we pull a rabbit out our bag of tricks.
The delete command is only for object's properties which were not
created with var.
JavaScript will let you delete a variable created with var under the
following conditions:
You are using a javascript interpreter or commandline.
You are using eval and you create and delete your var inside there.
or you can set null to an variable which will behave like a deleted object
When variable is created in global scope then automatically DontDelete property is added to the variable and set to the true. That is the reason global variables (or functions too) can not be deleted.
For other variables that property is false so those can be deleted.
For more clarity you can refer the article : understanding delete
With ECMAscript 5, the properties added to an object now have attributes which allow you more control over the object. These attributes are:
value - The actual value of the property
writable - If the property can/cannot be changed.
configurable - If set to false,any attempts to change its attributes will fail in strict mode (and will return false in non-strict mode)
enumerable - if the property can be iterated over when the user does for (var prop in obj) {}
These attributes can be checked with another API exposed by Ecmascript 5 called:
Object.getOwnPropertyDescriptor(obj, prop)
Now, when you create a global variable WITHOUT the 'var' keyword, like so:
sum = function (a, b) { return a + b; }
then this property 'sum' get created on the window object with configurable attribute set to true.
console.log(Object.getOwnPropertyDescriptor(window, "sum"))
... and therefore this property CAN be deleted from the window object.
delete window.sum //returns true
But when you create a property with the var keyword, then configurable property is set to false like so:
var multiply = function (a, b) { return a * b; }
console.log(Object.getOwnPropertyDescriptor(window, "multiply"))
... and now, this property CANNOT be deleted.
delete window.multiply //returns false in non-strict mode
Courtesy: John Resig
When a function is invoked, a new lexical environment is created for that invocation. That lexical environment contains an environment record, which in turn holds the local named bindings which exist in that environment. So, for instance:
(function () {
var x = 123;
// other code
}());
In the above function invocation, there will exist a binding with the name "x" and the value 123, in the function's lexical environment.
Now, if we wanted to change the value of that binding, we could:
set the identifier x as the left-hand side of one of the assignment operators:
x = 456;
// the value of the "x" binding has changed to 456
set the identifier x as the operand of a prefix/suffix increment/decrement operator:
x++;
// the value of the "x" binding has changed to 124
My question: Are those the only two methods to change the value of the "x" binding?
Well, I don't think we should talk about 'bindings' here. The link #Incognito gave in comments to the question describes binding of variables and functions - but not their values.
As 'x' in your example has a primitive value assigned, I don't think there's a way to alter it - if not in an assignment (direct or syntax-sugar one).
For example, this...
var x = 42;
x.y = 24;
... won't actually result in changing x (it gets converted into an object, assigned a new property, but then this object will be just thrown away).
And this...
function x() { ... }
... will also fail to assign a new value to x.
UPDATE: My point is that 'var x = 42' statement in JS (but not in Erlang) won't result in binding of 42 (number literal) to variable x.
I want to know what the global object in JavaScript is and to which class this object belongs to.
And how are Infinity, NaN and undefined part of the global object?
Variable scope is defined in JavaScript by a function, and functions can be nested inside other functions.
function foo() {
// new variable scope in here
var a = "a";
function bar() {
// another nested variable scope
var b = "b";
}
bar();
}
foo();
EXCEPT there is a default "global" variable scope that is defined when your program runs. It is the base variable scope in which all function created scopes are nested.
So what?
Well, every variable scope has a variable object (or more accurately, a "binding" object). It's an internal object to which all the local variables you create are bound.
This variable object is not directly accessible. You can only add properties to it by declaring a local variable (or function parameter, or function declaration). And you can only access properties via the variable names.
Again, so what?
Well the "global" variable scope is unique. It exposes this internal variable object by automatically defining a property on the object that refers back to the object itself. In a browser, the property is named window.
Because a property is placed on the object that refers back to the object, and because properties on the object become variables, we now have a direct access to the global variable object.
You can test this by observing that the window.window property is an equal reference to the window variable.
alert(window.window === window); // true
As a result, we can add a property to the object window.foo = "bar";, and it show up as a global variable alert(foo); // "bar".
Note that the only variable scope that exposes this internal object is the global scope. None of the function scopes expose it.
Also note that the ECMAScript specification does not require that the global variable object be exposed. It is up to the implementation to decide.
There are no real classes, but if you mean the prototype chain of the global object, the specification doesn't say much:
The values of the [[Prototype]] and [[Class]] internal properties of the global object are implementation-dependent.
([[Class]] is used in e.g. window.toString() so that you may get "[object global]".)
The three values you mention are properties of the global object, e.g.:
Infinity === window.Infinity; // true (in a browser the global object is window)
You cannot overwrite these variables, so you can see them as literals. But in reality they are properties of the global object, and thus you can refer to them as variables ("global variables").
I get a strange behavior when declaring an object with the logical OR.
my_var = my_var || {}; // throws TypeError
If I add the var keyword
var my_var = my_var || {}; // returns empty object
Why is this? I can't seem to find an explanation. my_var is global scope, so why is var changing the behavior?
The first example tries to assign to a property on the global object named my_var by reading the value from an identifier called my_var (OR an empty object). However, the identifier my_var is not defined at that point, so it fails.
In the second example, due to how javascript variable hoisting works, the my_var variable is already declared, when you read from it by assign to it.
Also have a look at this example:
a = a; // fails, undeclared identifier
a = 0;
With var keyword it will work!
b = b; // succeeds allthough identifier undeclared?!
var b = 0;
This is because variable hoisting will turn it into this:
var b; // declaration of b hoisted to the top of scope
b = b;
b = 0;
when defining a variable without var, you're directly accessing the global object. That means, your Javascript engine trys to lookup my_var on the global object (window if you're in a browser). Since that property does not exist yet, your JS engine will throw.
That happens on the right side of your statement, when your engine trys to read a variable with the name my_var. assigning like
my_var = {};
would work tho. But accessing an identifier without var will cause the browser to lookup the scopechain. Since the variable object for the global object is the global object itself, the lookup procedure will end up nowhere ( = exception ).
By putting the var keyword infront, your js engine knows at parsetime that it has to declare a new variable with that identifier name. It actually does declare that variable with an undefined value (that is called "hoisting"). That means, using var will prematurely create a property in the current context with that name. So if that code is not located in any function or eval context, it'll create the property my_var on the window object.
In your second example, the var defines the scope of my_var. This allows the value to be set properly. Here's a quick and dirty look at what's happening in both examples:
With example 1, the JS engine has to do the following:
Check the current scope to see if my_var exists.
Check the scope above (and the scope above that) until it finds my_var.
Create my_var in the global scope when it's not found.*
*Step 3 has not yet happened when you try to assign a value to my_var.
Example 2:
Is there a variable named my_var in the current scope? Yes, you just created it using the var keyword.
Assign its value.
In the 2nd situation, my var is undefined so the variable is assigned an empty object which is {}
Although I cannot quote the specs, I assume that the initialization in a var statement is just syntactic sugar:
var my_var = my_var || {};
is equivalent to:
var my_var;
my_var = my_var || {};
In the first line, my_var is declared and implicitely set to the special value undefined. Then, in the second line, my_var exists, undefined evaluates to false and no error is raised.
In your first example, however, my_var is unknown when the right hand side is evaluated, hence the error.
In the first case you try to assign a variable that was not defined. Its the same as you would write :
my_var = a || {};
in the second case my_var is only undefined as you use the var keyword an create my_var in the actual scope. Undefined is converted to false and it will return the empty object.
Interestingly, this will work:
a = my_var || {}; // 'a' is now an empty object
When you use the 'var' keyword you're literally giving the command "create a new variable and assign to it this value." If you don't use 'var' then you're implying that the variable already exists within the global scope somewhere.
In your example the JavaScript engine attempts to look up the current value of 'my_var', finds that it doesn't exist, cannot create it because you're currently attempting to assign a value to it, and fails.