While reading a book of JavaScript I read that
all the attributes of Data Properties defaults to true when "defined directly on an object".
then after some description it again says that
"When you are using Object.defineProperty()", the values for configurable, enumerable, and
writable default to false unless otherwise specified.
I guess, in first statement "defined directly on an object" means using dot operator or by object literal notation like this:
var obj = new Object();
obj.name = "Mahesh";
But is there any way to experiment to check what these attributes have been set to, after the property has been added to the object by either method?
You can use getOwnPropertyDescriptor:
> var desc = Object.getOwnPropertyDescriptor(obj, 'name');
{"value":"Mahesh","writable":true,"enumerable":true,"configurable":true}
desc will contain the the flags configurable and enumerable. If the property is a data descriptor (no get or set), desc will also contain value and the flag writable. If the property is an accessor descriptor, desc will also contain the get and set methods.
Related
I am trying to understand how the Object mutation in JS works. I came across the writable property on JS.
var x = {name:'JohnSnow'};
Object.defineProperty(x, 'name', {
writable: false
};
Now changing the name property has no effect on the object x. This is understandable as I have changed its writable property to false.
However, all the docs that I read including (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties#Parameters) says that this property is false by default.
If the writable is set to false by default, shouldn't the object be immutable by default and should become mutable only after setting writable to true.
Am I wrong in understanding the concept of Object properties here, because I think all the objects in JS have this config and every object has writable property.
Object.defineProperty should usually only be used when defining a new property - otherwise, the property descriptor object passed will often be partially ignored, as described in step 2 of 9.1.6.3 ValidateAndApplyPropertyDescriptor
.
In step 2, the new descriptor, desc, will only be put as the new property descriptor if the current descriptor is undefined.
In step 6, an existing data property might be switched to become an accessor property (or the other way around), but
Preserve the existing values of the converted property's [[Configurable]] and [[Enumerable]] attributes and set the rest of the property's attributes to their default values.
Steps 7 and 8 do not change the current descriptor, they simply verify and return a value.
So, no matter the descriptor passed, if the property already exists on the object, the writable property (or its absence) of the "new" descriptor will be completely ignored.
writable does default to false, but only when using Object.defineProperty.
var x = {};
Object.defineProperty(x, 'name', {
value: 'foo'
});
x.name = 'bar';
console.log(x.name);
As you can see above, if you do not provide a writable property when calling Object.defineProperty, it will default to false. That's all it means - it's not specifying that properties are always non-writable by default, it's only specifying that properties are non-writable when defining a property with Object.defineProperty.
Object properties are writable when defining an object with an object literal, described in 12.2.6.7 Runtime Semantics: Evaluation ObjectLiteral : {}:
Perform ? PropertyDefinitionEvaluation of PropertyDefinitionList with arguments obj and true.
Which eventually leads you to:
CreateDataProperty ( O, P, V )
:
Let newDesc be the PropertyDescriptor { [[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true }.
So I'm wondering what the difference is between methods and getters?
Reading the Mozilla documentation:
Sometimes it is desirable to allow access to a property that returns a
dynamically computed value, or you may want to reflect the status of
an internal variable without requiring the use of explicit method
calls
But don't they achieve the same thing? Why is one better than the other?
Why is saying:
var obj = {
log: ['a', 'b', 'c'],
get latest() {
if (this.log.length == 0) {
return undefined;
}
return this.log[this.log.length - 1];
}
}
console.log(obj.latest);
Sometimes preferable to just having a latest() method and calling obj.latest(). If the code is run in both cases, then what's the point? Aren't they both dynamic?
The documentation also reads:
Getters give you a way to define a property of an object, but they do
not calculate the property's value until it is accessed.
What exactly is the difference between 'accessed' and 'called'? A method isn't run until it's called, just as a property isn't accessed until its included? So where does the significance lie?
Note, the following is an opinion.
A getter is for retrieving the value of a specific property, and it allows your object to have dynamic properties based on the value of other properties but otherwise behave just as you would expect properties to behave. The getter allows you to define a method that is called when you access that property, even though you access it with normal object property accessors, myObject.dynamicProp and myObject['dynamicProp'].
Getters are provided for exactly that purpose. If that's the intent of the method you are writing, then use the getter syntax.
Methods exist to do other things that are verbal, action oriented, and not to simply return some property of the object you're writing.
You can always write a method to be a getter, but why?
So it depends on your intent. Getters specify intent, and if your intent is to provide a dynamic property that behaves just like an object property then use a getter over a method.
Hope that helps!
Updated:
While there is technical nuance to be understood here, and though I've leaned toward using the getters above, I'd say, after further reflection, that the approach you wish to take is up to you based on:
(1) Do you want to use normal accessors to access this property? Are you ok with dynamic properties that hide some logic? (They don't really 'hide' the logic per se, but they look just like normal props to the caller). Then use the get().
(2) Do you want to make it obvious and more readable that your property is dynamic? Are you doing things besides just computing a dynamic property based on the current values of existing properties of this object? Are you ok with having to call the method explicitly? Then use a method, e.g. getLatest().
According to the documentation for Object.defineProperty() on MSDN
Property descriptors present in objects come in two main flavors: data
descriptors and accessor descriptors. A data descriptor is a property
that has a value, which may or may not be writable. An accessor
descriptor is a property described by a getter-setter pair of
functions. A descriptor must be one of these two flavors; it cannot be
both.
Both data and accessor descriptors are objects. They share the
following optional keys:
configurable true if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object. Defaults to false.
enumerable true if and only if this property shows up during enumeration of the properties on the corresponding object. Defaults to false.
A data descriptor also has the following optional keys:
value The value associated with the property. Can be any valid JavaScript value (number, object, function, etc). Defaults to undefined.
writable true if and only if the value associated with the property may be changed with an assignment operator. Defaults to false.
An accessor descriptor also has the following optional keys:
get A function which serves as a getter for the property, or undefined if there is no getter. When the property is accessed, this function is called without arguments and with this set to the object through which the property is accessed (this may not be the object on which the property is defined due to inheritance). The return value will be used as the value of the property. Defaults to undefined.
set A function which serves as a setter for the property, or undefined if there is no setter. When the property is assigned to, this function is called with one argument (the value being assigned to the property) and with this set to the object through which the property is assigned. Defaults to undefined.
If a descriptor has neither of value, writable, get and set
keys, it is treated as a data descriptor. If a descriptor has both
value or writable and get or set keys, an exception is thrown.
This indicates that get and set intercept access calls and assignment calls respectively.
A very good example (and description) here points out a clear example of when this is useful.
Take a case where you have the first and last name on a person, with the common need for the full name.
person.setLastName('Smith');
person.setFirstName('Jimmy');
person.getFullName(); // Jimmy Smith
Using the get and set keys, gives you the option of declaring the object like so:
var person = {
firstName: 'Jimmy',
lastName: 'Smith',
get fullName() {
return this.firstName + ' ' + this.lastName;
},
set fullName (name) {
var words = name.toString().split(' ');
this.firstName = words[0] || '';
this.lastName = words[1] || '';
}
}
and assigning it, and accessing it like so:
person.fullName = 'Jack Franklin';
console.log(person.firstName); // Jack
console.log(person.lastName) // Franklin
console.log(person.fullName) // Jack Franklin
This allows the developer to interact with fullname, without accidentally leaving firstname or lastname unassigned or improperly assigned.
Lastly,
The use strict directive will enforce read and write attempts to attributes defined through get or set accordingly. See W3Schools.
"use strict";
var obj = {get x() {return 0} };
obj.x = 3.14; // This will cause an error
JavaScript objects can be sealed, which prevents new properties from being added and existing properties from being removed or reconfigured, but the properties remain writable. They can also be frozen, which is sealed plus all properties become non-writable.
Conspicuously absent is the ability to make the existing properties read-only, non-removable, non-configurable while leaving the object extensible. This would be useful to prevent accidental trampling on an object's properties while allowing other code to augment it's properties.
What's the best or idiomatic way to create such an object using vanilla JavaScript?
For instance you could use a getter to set your properties like:
var object = {get property(){return "value"} };
making them read only, meaning you can't change its value by assignment anymore as in:
object.property = "other";
since it has no setter. So object.property will continue to return "value", but you can still delete the 'property' key using the deleteoperator.
Simply loop through the object's properties and make each one non-writable and non-configurable:
var obj = { "foo": 1, "bar": 3 };
Object.defineProperty(obj, "baz", { set: a=>a });
Object.getOwnPropertyNames(obj).forEach(function(name) {
var desc = Object.getOwnPropertyDescriptor(obj, name);
desc.configurable = false;
// make the property non-writable if it is not an accessor property
if(!desc.set && !desc.get) { desc.writable = false; }
Object.defineProperty(obj, name, desc);
});
Note that this doesn't make accessor properties defined by set and get methods "non-writable" since the notion of writability doesn't apply to an accessor property -- storing into an accessor property runs the setter.
function me(a, b) {
function he(c, d) {
if(!a[c]) {
}
}
}
Please someone explain 'if(!a[c])' for me.
why this square bracket is used here in [c] though it is a parameter. it is not an array obviously.
what does if(!a[c]) make sense? how two parameters are used like this?
There is nothing special about that code.
It is saying, in English, If the property c of a is falsey, then the condition is true.
In JavaScript, bracket notation can be used to access properties of an object or members of an array.
For example, someArray[5] will access the 6th member of the array, while someObject['someProp'] will access someProp of the object someObject.
The argument a is likely an object. The syntax:
if (!a[c])
Checks to see if the property in the variable c on the a object does not have a truthy value. This could be if it was null, false, undefined or any other falsey value.
The bracket notation can be used with property names. So, if you have an object like this:
var x = { name: "John"};
Then, you can access that property like in any of these ways:
x.name
x["name"];
// Or, if the property name is in a variable
var prop = "name";
x[prop]
Your example is using a version of the last of the above three options when the property name is in another Javascript variable.
In javascript, properties can be accessed dynamically using the square-bracket syntax.
Consider the following:
var person = {name:'Sarah'};
console.log(person.name); // logs 'Sarah';
Sometimes, you might want to dynamically access properties of an object, using a variable that holds the name of the property you want to access. The above example could also be written like this:
var person = {name:'Sarah'};
var prop = 'name';
console.log(person[prop]); // logs 'Sarah';
I have an array of objects where the key is an md5 string and the value is an object
[0315778255cca8d2f773642ad1d3678f] = {a:12,b:34}. I need to remove array elements based on their key, i tried splice but failed cause i suppose the keys are non numeric.
I also tried to splice by position, but that failed to, and even delete the element but we all know that it is not ideal.
I could change my implemantation from array to object but that too will have the same problems more or less i suppose.
Any ideas are welcome
splice is indeed about the array indexes (as the numeric properties of arrays are called), not about other properties.
To remove a property from an object (including an array), use delete:
delete theArray['0315778255cca8d2f773642ad1d3678f'];
Despite its similarity to "delete" in other languages, delete in JavaScript has nothing (directly) to do with memory management; all it does is remove a property from an object (entirely; it doesn't just set the property's value to undefined or something).
Side note: If you're only using non-numeric properties, you probably don't want an array at all. The only reason for using JavaScript's Array type is if you need the special handling it gives properties whose names are all digits, the magic length (which only relates to the numeric properties), and the stuff from Array.prototype — none of which does anything with other, non-index properties.
Re your comment below:
delete leaves an undefined in the elements place. i need to get rid of it completely
No, delete removes the property, entirely. It does not leave undefined in its place. You might be thinking it does because any time you try to retrieve a property from an object that doesn't exist, you get back undefined. E.g.:
var obj = {}; // Object with no "foo" property at all
var x = obj.foo;
console.log("x = " + x); // "x = undefined"
You can prove that the property really is removed by using hasOwnProperty or in:
var obj = {};
console.log('foo' in obj); // "false"
console.log(obj.hasOwnProperty('foo')); // "false"
in will check the object and its prototype chain; hasOwnProperty just checks the object itself.
Coming back to delete:
var obj = {};
console.log(obj.hasOwnProperty('foo')); // "false"
obj.foo = "bar";
console.log(obj.hasOwnProperty('foo')); // "true"
delete obj.foo;
console.log(obj.hasOwnProperty('foo')); // "false"
obj.foo = "bar";
console.log(obj.hasOwnProperty('foo')); // "true"
delete obj['foo'];
console.log(obj.hasOwnProperty('foo')); // "false"
Live example | source
Note that both delete obj.foo; and delete obj['foo']; work if foo is a valid identifier. But for properties whose names aren't valid identifiers (like your md5 sums), you have to use the bracketed form with the string as I showed above (delete theArray['0315778255cca8d2f773642ad1d3678f'];).