I am reading an interesting article on understanding delete in JS.
I understand that properties created via variable declaration cannot be deleted, or more precisely, has the DontDelete attribute, while properties created via property assignment can be deleted.
But I'm confused with how property overloading works with this idea:
> var GLOBAL_OBJECT = this;
undefined
> var declared = "I cannot be deleted";
undefined
> delete declared;
false
> assigned = "I can be deleted";
'I can be deleted'
> delete assigned;
true
> // Now, I will override `declared` ...
> declared = "I am overrided - now deletable?";
'I am overrided - now deletable?'
> declared;
'I am overrided - now deletable?'
> delete declared;
false
This seems to me is that property attributes are predetermined when properties are created within the Variable Object. So, when you attempt to override a property, you can expect that it will be overridden but that the property attributes will not.
Is this correct?
What you call "override" a property is actually a regular assignment. You simply change the value of the variable. All the attributes of the variable remain the same, including the DontDelete you mentioned.
In the case of the assigned variable in your example, the variable was defined implicitly, not declared with the var keyword and that is what makes it able to be deleted.
I have read the article too hastily.
Here is a quote from the article that addresses this topic,
Note that it is during property creation that attributes are determined (i.e. none are set). Later assignments don't modify attributes of existing property. It's important to understand this distinction.
Related
I'm reading this js tutorial, in Def. 5: Class section there's a code snippet:
// Generic prototype for all letters.
let letter = {
getNumber() {
return this.number;
}
};
I wonder how can getNumber method refer to number which is not declared?
number isn't a variable, it's a property. You don't have to declare properties (in fact, until the class fields proposal progresses [it's currently at Stage 3], you can't declare properties; there's no property declaration syntax, just a property initialization syntax). Variables are storage outside of an object.¹ A property is storage within an object.
If you're wondering how getNumber can use the property before it's created, it's because that's just how JavaScript is defined: Trying to get the value of a property that doesn't exist results in the value undefined, not an error.
¹ "...outside of an object." At least, as far as your code is concerned. In specification terms, variables are bindings (which are very similar to properties) within a lexical environment object, but that's a specification thing, not something you can directly use in code.
In your code, this.number is letter.number which is not defined. And, it means it is evaluted as undefined.
var obj = {};
obj.number; // undefined
This question is inspired by:
ng-model in numeric input does not affect scope
In that question I was surprised to learn that somehow I have nested controllers even though I have exactly one controller per template and I have no custom directives. This might have something to do with Ionic.
I had a problem that I couldn't access primitive $scope properties without wrapping them in objects. I had this problem regardless what I named the primitive property. I could only access it from my template if I wrapped it in an object or referred to $parent.
How come I can't access the primitives regardless of name? I would understand that there can be a naming conflict, but no name worked. And if no name works, then why do primitives wrapped in objects work? Why do I not need to write $parent.object in my template to access an object attached to my $scope?
Accessing vs Defining values
When accessing a value (such as using {{ value }}, or method()), the application will climb up parent scopes looking for the value until it reaches $rootScope: the first version found, if any, is then used.
When defining a value, however (such as using value = 'foo'), it applies it to the current scope, even if a value exists with the same key under a parent scope.
Defining primitives vs defining object properties
When setting a primitive value such as 'value', you're simply defining what value is:
value = 123;
But when defining the property of an object, the object has to be accessed before the property change can be applied to it:
object.value = 123;
The above code looks for object, and applies the change to its value property. If object doesn't exist in the current scope, the application will search up the parent scopes to find object, so it can access it. Then, the change to value is applied to that instance of object. If object doesn't exist at all, the code will throw an error because it is essentially the below:
null.value = 123;
Example
Similar functionality can be seen in vanilla Javascript through prototypal inheritance.
var parent = { primitive: 123, object: { value: 123 } };
var child = Object.create(parent);
console.log(child.primitive); // 123, from parent
console.log(child.object.value); // 123, from parent
child.primitive = 456; // modifies own primitive key
console.log(child.primitive); // 456, from self
console.log(parent.primitive); // still 123
child.object.value = 456; // modifies parent's object's value
console.log(child.object.value); // 456, from parent
console.log(parent.object.value); // 456, since it was modified above
JavaScript objects are dynamic "bags" of properties (referred to as
own properties). JavaScript objects have a link to a prototype object.
When trying to access a property of an object, the property will not
only be sought on the object but on the prototype of the object, the
prototype of the prototype, and so on until either a property with a
matching name is found or the end of the prototype chain is reached.
Read more here
You need to know the prototype inheritance of javascript first.
Then understand how scope works with this very helpful guide.
Today I wondered after some strange behavior of angularjs. I used console.log to log $scope, there were no key attached to scope named val1, but when I use console.log($scope.val1) its returning value as a object. After digging out the reason, I found that it was accessing parent scope as there is no kay named val1 in $scope. Now my question is that,
Which is good practice? Can you please justify?
Using $scope.$parent.val1
Using $scope.val1
You should generally never use $scope.$parent and instead rely on Javascripts prototypal inheritance. By accessing the parent directly, you run the risk of the code breaking if you move the directive/controller a step up in the scope hierarchy, and the data is now on $scope.$parent.$parent instead.
Instead, never write to properties directly on the scope but to objects on the scope object instead.
Say you do:
$scope.$parent.value = 'x';
Then you do:
console.log($scope.value);
That'll print x to the console. If you then do:
$scope.value = 'y';
You're not modifying the value property on the parent scope, but introducing a new property on the child scope. So $scope.$parent.value will still contain x.
To get around that, you do:
$scope.$parent.data = {value: 'x'};
console.log($scope.data.value); // prints x
$scope.data.value = 'y';
console.log($scope.data.value); // prints y
console.log($scope.$parent.data.value); // also prints y
The reason this works is that instead of creating a new value property on the child scope, it first needs to lookup the data property. And that's not on the child scope, so it goes up the prototype chain ($parent) to find the data object. The data object is found on the parent, and the value property is set on that object instead.
It depends on the type of val1, in case it is a primitive, you will have to access it explicitly via $scope.$parent.
In case it is an object, you can take advantage of the prototypal inheritance that exists between parent and child scope in Angular and just reference it regularly, as I am sure you are aware of, objects are passed by reference, so any change to the object will change it on the parent scope.
More info here
consider a piece of code
function F(){
this.p=10;
}
F.prototype.newProp='some value';
var f1=new F(), f2=new F();
alert(f1.__proto__==f2.__proto__); //returns true. implies f1 and f2 share same instance of prototype object
f1.newProp='new value'; //changing the value of inherited property
alert(f2.newProp); //returns 'some value'
Ok now the question is if f1 and f2 both share the same [[prototype]] object instance
and if
property retrieval in javascript works by walking along the prototype chain
So if I change value of a property (newProp, in this case) of a shared [[prototype]] object,
how come its not reflected in f2 as well ,
since f1.proto==f2.proto (which means its the SAME object)
then why changing the newProp of f1 doesn't change newProp of f2 (both inherit from same prototype object, no ?)
Surprisingly,changing f1.proto.newProp reflects the change when retrieving "f1.newProp"
So , are f1.newProp and f1.proto.newProp different properties ?
I thought the property look up in javascript worked by successively looking higher in the prototype chain.
I am sorry if my question sounds naive, but I couldn't get my head around :
If 1) f1.proto==f2.proto //true! implies both objects f1 and f2 refer same [[prototype]] object from which they inherit
and if
2) property not found in object is searched in its prototype .
then why changing f1.newProp doesn't reflect in f2.newProp too ? as both have common [[prototype]] property as shown in point (1)
Is it that properties from prototype object are being copied individually into f1 and f2. ?
but then thats in violation of point (2) [looking up the properties of prototype chain when not not found in the object]
Please explain the contradiction here. thank u very much :)
==================EDIT================
thank you #jfriend00 for the reply.
but lets say I have this code
function Person(name, age){
this.name=name;
this.age=age;
alert("obj created:"+name);
}
function Employee(name,age,eid){
this.base=Person;
this.base(name,age);
this.eid=eid;
}
Employee.prototype=new Person;
var ob1=new Employee('name1',23,100);
var ob2=new Employee('name2',24,101);
here too, obviously ob1.proto==ob2.proto
but if I am not mistaken there's 2 objects here for each instance of employee
1 is the employee object itself with only 1 property eid (and other one base func)
2nd is the Person object which is referenced by the [[prototype]] property of employee object. This object has name and age property..
So , employee obj actually stores and retrieves name and age from its [[prototype]] Person object.
Am I right ?
If so , and since ob1.proto==ob2.proto, then how are we able to store unique name and age of both objects ?
I mean, here it almost seems there's a prototype object for each employee.
if u could explain this, thank u very much :)
and one more query is :
how come the above code will work even if comment out the
Employee.prototype=new Person;
in the above line and thereby breaking the link between 2 objs. Inheritance still works just because I have declared Person function as a property of Employee and called Person from it .
how is this working
thank you :)
Once you set f1.newProp = 'new value', it no longer is setting newProp on the prototype, but on the f1 object itself. Try this, you will see:
var f1=new F(), f2=new F();
console.log(f1.hasOwnProperty('newProp')); // returns false, because it is from prototype
f1.newProp = 'new value';
console.log(f1.hasOwnProperty('newProp')); // returns true
The prototype object is shared among all objects (as you have shown).
But, when you assign to a property an the object, it doesn't change the prototype, the property goes on the object itself and because of the lookup order for resolving a property reference, the newly assigned property on the object itself is found before the one on the prototype so it becomes the active property.
When you reference a property on an object, there is a search order. First it looks for properties directly on the object. If no match is found, then it searches the prototype chain.
When you write to a property on the object, it never writes to the prototype unless you explicitly reference the prototype object, instead it puts a property directly on the object and that property then becomes the active one (essentially overriding what's on the prototype).
You can tell whether a property is on the object itself or on the prototype by using .hasOwnProperty(). That will return true only when the property is directly on the object.
So, in your code:
f1.newProp='new value'; //changing the value of inherited property
This adds a new property directly to the object (not on the prototype) and it essentially overrides what is on the prototype.
In general, data properties are usually set in the constructor to avoid any confusion about the two possible locations the property can reside and, if you're writing to them, there's really no advantage to having initially specified them on the prototype. Function properties (e.g. methods) are often set in the prototype because they generally aren't written to so it's more efficient to just have one shared prototype object that contains them that can be read from.
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