I want a property that would always be undefined:
var foo = {bar:undefined}
If someone later try to change property bar then also it should results in undefined.
foo.bar = 'someValue'//
foo.bar//this time this should result in undefined.
I mean how to set a property that is unchangeable.
OK, based on the hint from #somethinghere (who is breaking his/her own answer again…) here is a working example, that sets up an object member, which defaults to undefined and is not writeable:
var foo = {}
Object.defineProperty(foo, 'bar', {
enumerable: false,
configurable: false,
writable: false
});
foo.bar = 'abcdefg';
console.log( foo.bar ); // returns undefined
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Be aware that you may still remove and re-set this property. (While you can't simply overwrite it.)
You can currently do this:
var foo = {}
Object.defineProperty(foo, 'bar', {
enumerable: false,
configurable: false,
writable: false,
value: undefined
});
As some have pointed out, undefined would not equal "undefined", one obviously being a string. However, I have added it for the sake of clarity as omitting the value property really loses the point of being able to use defineProperty to make them non-configurable. Once configured, its over, so its useful to have the value. Omit value if you want it to return undefined.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Related
I created a object using Object.create in the following way.
var myObject = {
price: 20.99,
get_price: function() {
return this.price;
}
};
var customObject = Object.create(myObject, {
price: {
value: 100
}
}
);
console.log(delete customObject.price);
I tried to delete customObject price using
delete customObject.price returns false
The second parameter to Object.create() is interpreted exactly the same way as the second parameter of Object.defineProperties(). That false is being returned from the delete expression because the property you're deleting is an own non-configurable property and you're not in "strict" mode. In "strict" mode you'd get an exception.
If you created the property with the "configurable" flag set to true, you would get true from the delete:
var customObject = Object.create(myObject, {
price: {
value: 100,
configurable: true
}
}
);
Or you can create the object and just set the property with a simple assignment:
var customObject = Object.create(myObject);
customObject.price = 100;
Such properties are always "born" as configurable.
You can use Object.getOwnPropertyDescriptor(customObject, "price") to check whether the property you're deleting is configurable:
if (Object.getOwnPropertyDescriptor(customObject, "price").configurable)
delete customObject.price;
I am extending the array object with a new method called custommethod as follows and looping through the values inside an array. However, the looping through the indices also prints the name of the property which is extended via Array.prototype.<method>.
Array.prototype.custommethod = function() {
console.log("Hello from Custom Method");
}
Object.defineProperty(Array.prototype, "anothercustommethod", {
value: function() {
console.log("Hello from Another Custom Method");
}
});
Loop through the array
> x = [1,2]
[ 1, 2 ]
> for (i in x) { console.log(i); }
0
1
custommethod
Why doesn't the anothercustommethod get printed in this loop?
Is using the Object.defineProperty() a safer way to create Array.prototype?
I am curious as to how the for loop in javascript actually works. Does it use Object.keys() internally? If so how does it print custommethod which is inside __proto__ property but not anothercustommethod which is also inside __proto__ property?
Why doesn't the anothercustommethod get printed in this loop?
for in iterates over those properties, which data descriptor enumerable is set to true.
In the Documentation
enumerable
true if and only if this property shows up during
enumeration of the properties on the corresponding object. Defaults to
false.
When using defineProperty, you can also pass an extra property - enumerable.
By default it is set to false.
Array.prototype.custommethod = function() {
console.log("Hello from Custom Method");
}
Object.defineProperty(Array.prototype, "anothercustommethod", {
value: function() {
console.log("Hello from Another Custom Method");
},
enumerable: true
});
const x = [1,2]
for (i in x) { console.log(i); }
Is using the Object.defineProperty() a safer way to create Array.prototype?
There is nothing about safe. Try to change the build in prototypes rarely
you can check the property by this API:
Object.getOwnPropertyDescriptor(Array.prototype,'custommethod');//{value: ƒ, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(Array.prototype,'anothercustommethod');//{value: ƒ, writable: false, enumerable: false, configurable: false}
see? the first one got:enumerable: true,the second one got:enumerable: false,
also other values is different too that is because the default settings is different when set by different API
acutally ,want to be more safe,you can use this API:
Object.getOwnPropertyNames
Object.getOwnPropertyNames(Array.prototype).filter(v=>v.endsWith('custommethod'));//["custommethod", "anothercustommethod"]
if there is symbol,you still need to
Object.getOwnPropertySymbols(Array.prototype);//[Symbol(Symbol.iterator), Symbol(Symbol.unscopables)]
Object.keys works like for in,they won't traverse property whose enumerable is false;
when you try to traverse property with other API,should think about these things
This question already has answers here:
delete a.x vs a.x = undefined
(9 answers)
Closed 5 years ago.
I want to set the property of object to something if condition is true, else do nothing.
And I tried to use ? operator by
obj.prop = (...)?sth:null;
and
obj.prop = (...)?sth:undefined;
But it turns out that nether one of them can perform what I want.
Given the condition is false, when I called obj.hasOwnProperty(prop), it always gives me true.
Is there a way to do it?
I know I can do it by using if syntax but I just want to know if I can do the same thing using ? operator.
When you assign a property like this:
var obj = {
a : undefined // or any other value
};
this happens according to the ECMAScript spec:
11.1.5 Object Initialiser
[...]
The production PropertyNameAndValueList : PropertyAssignment is evaluated as follows:
Let obj be the result of creating a new object as if by the expression new Object() where Object is the standard built-in constructor with that name.
Let propId be the result of evaluating PropertyAssignment.
Call the [[DefineOwnProperty]] internal method of obj with arguments propId.name, propId.descriptor, and false.
Return obj.
When you assign a property like this:
obj.a = undefined;
this happens according to the ECMAScript spec:
8.12.5 [[Put]] ( P, V, Throw )
[...]
Else, create a named data property named P on object O as follows
a. Let newDesc be the Property Descriptor
{[[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}.
b. Call the [[DefineOwnProperty]] internal method of O passing P, newDesc, and Throw as arguments.
In either case, since undefined and null are legimite values, this will just define the property with this value.
Finally, hasOwnProperty() will only check if a property descriptor was created, the value does not matter:
15.2.4.5 Object.prototype.hasOwnProperty (V)
[...]
Let desc be the result of calling the [[GetOwnProperty]] internal method of O passing P as the argument.
If desc is undefined, return false.
Return true.
But, according to the ECMAScript spec, both a property set to undefined and a not set property, will return undefined if you access them:
8.12.3 [[Get]] (P)
[...]
If desc is undefined, return undefined.
If IsDataDescriptor(desc) is true, return desc.[[Value]].
Otherwise, IsAccessorDescriptor(desc) must be true so, let getter be desc.[[Get]].
If getter is undefined, return undefined.
Return the result calling the [[Call]] internal method of getter providing O as the this value and providing no arguments.
Proof:
var obj = {
a : undefined
}
console.log(typeof obj.a); // undefined
console.log(typeof obj.b); // undefined
obj.hasOwnProperty('a') // true
obj.hasOwnProperty('b') // false
Only delete will remove the property.
var obj = {
a : null,
b : undefined
}
obj.hasOwnProperty('a') // true
obj.hasOwnProperty('b') // true
delete obj.a;
delete obj.b;
obj.hasOwnProperty('a') // false
obj.hasOwnProperty('b') // false
Reading the ECMAScript spec on delete is left to the reader.
Assuming that the result of your condition is falsy enough, something like this should work.
All falsey values in JavaScript
var obj = {
a: true,
b: false,
}
obj.prop1 = obj.a ? true : false;
obj.prop2 = obj.b ? true : false;
console.log(obj);
function foo(){}
delete foo.length;
alert(typeof foo.length);
// result is number
Why the above code alert number? Is this a bug?
-Nick
Thank you!
A function object has a built-in property named .length that specifies the number of arguments that were defined with the function which is something you can't delete or change its value.
The length property specifies the number of arguments expected by the function. And it has property attributes Writable: false, Enumerable: false, Configurable: true. So you can't delete that. It always returns a number.
2018 Update
Actually, it is even stranger than your example demonstrates.
Using this code it seems that the foo.length cannot be changed:
function foo() {}
alert(foo.length); // alerts 0
delete foo.length;
alert(typeof foo.length); // alerts 'number'
alert(foo.length); // alerts 0
But this is more interesting:
function foo(a, b, c) {}
alert(foo.length); // alerts 3
delete foo.length;
alert(typeof foo.length); // alerts 'number'
alert(foo.length); // alerts 0
So it's not that your delete foo.length doesn't change the value - it does, but it changes it to 0!
It's worth noting that this has no effect in non-strict mode:
foo.length = 0;
foo.length++;
But both of the above lines will raise an exception in strict mode:
TypeError: Cannot assign to read only property 'length' of function 'function foo(a, b, c) {}'
But delete foo.length works also in the strict mode, always changing the foo.length to zero.
delete foo.length does not work because length still exist in function prototype and it is 0.
To change function length or name you can redefine it as writable.
Object.defineProperty(foo, 'length', { writable: true, configurable: true });
Now you can change length.
Remember if you delete length you'll still have 0 from function prototype.
You can change it if you want:
Object.setPrototypeOf(foo, {});
Function still be usable.
I am reading up a little more on ECMAScript 5 (in the browser, using the ES5-shim which I know doesn't support everything). And just to clear up any confusion, considering I have this object (stolen from this post):
var Person = {
firstName: null, // the person’s first name
lastName: null // the person’s last name
};
Is there any difference between this:
var Employee = Object.create(Person, {
id: {
value: null,
enumerable: true,
configurable: true,
writable: true
}
});
And this:
var Employee = Object.create(Person);
Employee.id = null;
// Or using jQuery.extend
$.extend(Employee, {
id : null
});
As far as I understood enumerable, configurable and writable are set to true when defining a property this way (which would also be backwards compatible to legacy JavaScript engines). Am I missing something or can I just omit the verbose property descriptors whenever I want this to be the desired behaviour?
They're the same.
When creating new properties by assignment
obj.prop = val;
all three Boolean attributes of the newly created property are set to true.
Also, notice that when adding properties via Object.defineProperty
Object.defineProperty( obj, 'prop', {
value: val
});
the Boolean attributes are set to false (by default).