Non property assigned variable is delete-able - javascript

I was reading this article on the Javascript delete method, and tried this code:
function f(){
var x = "abcd";
console.log(delete x); //returns false, because x has DontDelete attribute
y = "abcd";
console.log(delete y); //returns true, but I didn't explicitly assign y as a property
}
This is strange, because I am not using property assignment for y (as in: window.y="abcd";), which the article claims is how you make properties deleteable.
Why does y not have the DontDelete attribute?
UPDATE:
In the answers below, it is claimed that y is deleteable merely because it is a property of the window object. That is not true. Consider the following snippet:
function f() {
var functionx = "abcd";
console.log(delete functionx); //returns false, because x has DontDelete attribute
functiony = "abcd";
console.log(delete functiony); //returns true, but I didn't explicitly assign functiony as a property to the window
}
//take 1
var globalx = "abcd";
console.log(this.globalx);//to prove x is a property of the global
console.log(delete globalx);//fails, even though x is a property of the window
//take 2
this.globaly = "abcd";
console.log(this.globaly);//to prove y is a property of the global
console.log(delete globaly);//succeeds, because I used property assignment
f();
In take 1, globalx is a property of the window, but it is still undeleteable. The criteria for whether delete will succeed is not whether the variable is a property of something (which is always true), but whether that property has a DontDelete attribute set.

delete x is invalid because it does not resolve to any object property.
y resolves to a property of the window object.
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/delete:
delete expression
where expression should evaluate to a property reference

Here is the expanded version of the second example:
window.y = "abcd";
console.log(delete window.y);
It's pretty obvious now what's happening.
If you don't use the var keyword, the interpreter assumes the variable is a property of the global object, (which is usually window), as shown in this JSFiddle. Note that in the global scope, this is the same as the window object.
Re: Update:
Outside a function, a variable declared with var is defined as a non-configurable property of the global object. This is detailed in https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/var, where it says:
Using var outside a function is optional; assigning a value to an undeclared variable implicitly declares it as a global variable (also a property of the global object). The difference is that a declared variable is a non-configurable property of the global object while an undeclared is configurable.
Declaring a variable inside a function does not assign it to a global property, but rather a local variable.
That explains the behaviour you're seeing when defining a variable in the global scope.

Variables in JavaScript are declared using var keyword. When you omit var, the interpreter starts looking for the closest scope in which the given variable is defined. If the given variable is not found, it will be created as a new property on a global object.
This is exactly what happens here:
Variable y is referenced and assigned a new value (abcd)
Var y is not defined anywhere → new global property y is created and assigned the value (effectively window.y = "abcd").
As a result, y becomes property of the global object, which can be deleted.

Related

The local var does not override the parameter of the same name?

This just blew my mind:
function f(x) {
var x;
console.log(x); // prints 100!
}
f(100);
I always used to think that whenever you declare the local variable, anything with the same name that was declared before becomes hidden behind it. Why var x does not make x undefined as it used to do in other situations?
Compare with this code, which behaves as I used to:
var x = 100;
function f() {
var x;
console.log(x); // prints undefined as expected
}
f();
Both var and the parameter declare the same variable x in the same function scope. When the variable is created, it is initialised to undefined, and shortly after assigned the value 100 that was passed as the argument.
For function code, parameters are also added as bindings to that Environment Record.
The defined parameter x is scooped to the current function. Since x is already been declared in the function, as a parameter, the var x; declaration will be ignored.
For more details: http://es5.github.io/#x10.5
From MDN#var:
Description
...If you re-declare a JavaScript variable, it will not lose its value.
In the first example, since x is already declared within the function f (as an argument), redeclaring it (using var) inside the same function will keep the same value for x before that redeclaration (which is the parameter given to f when it is called).
In the second example, x is declared within the function f. So when looking up x's value to pass on to log we use that x inside f (not the outside one), and since we didn't explicitly give it a value (initializing it), its value is going to be undefined.

Scope chain first looks to __parent__ or to __proto__?

Here I found information hot to works scope chain:
...before we go to the parent link, first proto chain is
considered.
Notice, that not in all implementations the global object inherits
from the Object.prototype. The behavior described on the figure (with
referencing “non-defined” variable x from the global context) may be
tested e.g. in SpiderMonkey.
I use Firefox browser for testing, but, when I set global variable x, and set to Object.prototype property x and do a() I've got 4. Why, if first we go to proto?
var x = 1;
Object.prototype.x = 2;
var a = function () {
y = 3;
return this.y + this.x;
};
a.x; // 2
a(); // 4
You should've cited the beginning of that paragraph, not the end:
At code execution, a scope chain may be augmented using with statement and catch clause objects.
So what your sentence refers to are only object environment records - scope objects in which variables live. Those are typically imaginary, described for specification purposes only (and can only be observed in Rhino), but the with statement makes an exception and prepends an actual JS object to the scope chain.
If you check out the example, you will find the with statement right there. The gist:
Object.prototype.x = "inherited object property";
var x = "parent scope variable";
with ({}) {
alert(x); // you bet what it yields
}
When I set global variable x, and set Object.prototype.x property, why doesn't it get the prototype value?
By using this in a function that is called plainly (a()), you are referring to the global object. It is indeed the object for the object environment record of the global scope, which means that all global variables live there as properties.
Now why does accessing x on that object (regardless whether by variable x or property this.x) bring up 1 not 2? Because the global variable with the value 1 is an own property of the object. The prototype chain will only be traversed if the property is not already found!

Can't understand the behavior of deleting vars in JavaScript

Here is the issue:
var x = 5;
window.x === x // true. x, as it seems, is a property of window
delete x; // false
delete window.x; // false;
BUT
window.x = 5;
delete window.x; // true
AND
window.x = 5;
delete x; // true
What is the explanation for such behavior?
Essentially the reason is that declared variables are created with an internal DontDelete attribute, while properties created via assignment are not.
Here is great article explaining the inner details of delete: Understanding delete
When declared variables and functions become properties of a Variable
object — either Activation object (for Function code), or Global
object (for Global code), these properties are created with DontDelete
attribute. However, any explicit (or implicit) property assignment
creates property without DontDelete attribute. And this is essentialy
why we can delete some properties, but not others:
You can use delete only for deleting objects, object properties or array element.
delete expression
delete will be not working if expression can't be represented
as property. So delete can remove global variable, but not variables inited by var.
So, let me explain:
var x = 5;
You create variable in global scope by var, not property of window object. This var is just linked to window.x. And then you compare window.x === x it will return true. But:
delete x; // deleting variable, not property, return false
delete window.x; // resolve link to x and also deleting variable, not property, return false
BUT
window.x = 5;//add property
delete window.x; // can delete property, return true
AND
window.x = 5;//add property
delete x; //resolve x. it's a propery of window, return true
and older
In ECMAScript 262/3 as #Peter explain is available DontDelete flag. But in ECMAScript 262/5.1 in strict mode deleting is regulated by Configurable flag:
When a delete operator occurs within strict mode code, a SyntaxError
exception is thrown if its UnaryExpression is a direct reference to a
variable, function argument, or function name. In addition, if a
delete operator occurs within strict mode code and the property to be
deleted has the attribute { [[Configurable]]: false }, a TypeError
exception is thrown.
This is how I understand that:
var x = 5; declared in the global scope creates the new window property x.
window.x = 5; declared (whereever) creates the new window property x as well. That's why window.x === x gives you true.
The difference is that javascript by default sets different descriptors for x property according to the way (one of two above) it is declared.
var x = 5 is equal to:
Object.defineProperty(window,'x',{
value: 5,
writable: true,
enumerable: true,
configurable: false
});
while window.x = 5 is equal to:
Object.defineProperty(window,'x',{
value: 5,
writable: true,
enumerable: true,
configurable: true
});
The configurable descriptor, if false, forbides to delete the property.
We can assume, that javascript use Object.defineProperty with different descriptor settings under the hood when we declare variables in a simple way with var keyword or without it (automatically assigned to window).
You can simply check that:
var x = 5;
window.y = 5;
console.log(Object.getOwnPropertyDescriptor(window,'x')); //configurable:false
console.log(Object.getOwnPropertyDescriptor(window,'y')); //configurable:true

Different behaviour of delete keyword on global variables

Please consider the following snippet (fiddle here):
​var a;
​a = 1;
console.log(delete a​); // prints 'false'
​b = 1;
console.log(delete b);​ // prints 'true'​​​​
Why does the delete keywords behave differently on the global variables a and b?
From the MDN docs:
The delete operator removes a property from an object.
A global variable (without var) is a property on the global object (typically window), so can be deleted.
A var is not a global variable, but a local variable in the outer scope - not a property of the global object - so delete does not delete it. From those docs:
x = 42; // creates the property x on the global object
var y = 43; // declares a new variable, y
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)
MDN says delete returns false only if the property exists and cannot be deleted. It returns true in all other cases. After deleting, try testing the actual values. You'll see that a was not deleted. This is because, as the MDN page says, delete will not affect variable names.
It has no effect on variable or function names.
(i.e., defined with var and not off the global object)
Take a look at the examples on the following page.
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/delete
From mozilla docs about var :
The difference is that a declared variable is a non-configurable property of the global object while an undeclared is configurable.
var a; --> This is a declared variable, because you are using var, so it's not configurable.
a = 6; --> This is an undeclared variable, because you are not using var, so it's configurable.
both syntaxes above will end up with a var named a attached as a property of the global object (window typically) and properties has these attributes:
Writable. If false, the value of the property can not be changed.
Configurable. If false, any attempts to delete the property or change its attributes (Writable, Configurable, or Enumerable) will fail.
Enumerable. If true, the property will be iterated over when a user does for (var prop in obj){} (or similar).
that is extracted from ecmascript5 objects and properties , and as you can read, the configurable attribute of the variable in question affects whether the variable can or cannot be deleted.
"var a" means it cannot be accessed from anywhere outside of the current block, thus deleting it WOULD mean UNDECLARE (not same as undefined), thus allowing to write "var a" again in the same block (error).
Allowed usages (MDN):
delete object.property
delete object['property']
delete object[index]
delete property
It's like GOTO and unstructured programming, where you might need to manually clean up resources, it's kind of ~Destructor in C (though not the same). You can delete an object like ~a(); but you cannot "'UNDECLARE' a variable" like "int i".

Why is this variable still alive?

I have the following source code.
testObj = {}
function testFun()
{
this.name = "hi";
}
function test () {
var instanceOfTestFun = new testFun();
testObj.pointerToFun = instanceOfTestFun;
instanceOfTestFun = null;
console.log(testObj);
}
$(document).ready(test);
I expected to see 'null' for the console output of testObj, but I see testFun function. I thought javascript uses 'pass by ref' for objects.
Please...advise me...
testObj.pointerToFun and instanceOfTestFun are two references to the same object.
When you write instanceOfTestFun = null, you're changing instanceOfTestFun to point to nothing.
This does not affect testObj.pointerToFun, which still refers to the original object.
If you change the original object (eg, instanceOfTestFun.name = "bye"), you will see the change through both accessors, since they both point to the (now-changed) object.
You don't destroy the object itself if you set a property that holds a reference to it (instanceOfTestFun) to null. You can only indirectly destroy an object by removing the last reference to it (which is, at that point, the value held by testObj.pointerToFun), so it will be garbage-collected.
Under no circumstance can you delete a property of testObj without referencing it.
Don't confuse properties (instanceOfTestFun, testObj, testObj.pointerToFun) with the values they can hold (references to properties, as after testObj.pointerToFun = instanceOfTestFun, or plain values, as 9 or null).
var x = {};
The above line creates an object and stores a reference to it inside the variable x.
var y = x;
The above line copies the reference from variable x to variable y. Now, both x and y hold references to the object.
x = null;
The above line deletes the reference that was stored inside x. The object that was referenced by this reference is not garbage-collected, since variable y still holds a reference to it.
Any given object lives as long as it's referenced by at least one reference.

Categories

Resources