if I set an attribute with configurable: false, can I change or delete it any more? Just like below:
var a = {
test: {
// there are some function
}
}
Object.defineProperty(a, 'test', {configurable: false, value: null})
I want to do something like this a.test.b = '1'again, but now test is null and no-configurable.
Maybe this question is boring, but I just don't want to get something cannot be changed or used with js code.
I have try to redefined: Object.defineProperty(a, 'test', {configurable: true, value: {}})
or want to make a new 'test' with delete a.test
nothing worked.
Object.defineProperty(a, 'test', {configurable: false, value: null});
delete a.test; // error
a.test; // null, and I want it be {} with some code.
Object.defineProperty(a, 'test', {configurable: false, value: null});
// there is some code to make sure below code right.
a.test.b = 1
You can't delete the property, but if you use writable: true, you will be able to reassign it:
'use strict';
var a = {
test: {
b: 'x'
}
}
Object.defineProperty(a, 'test', {
configurable: false,
writable: true,
value: null
})
a.test = {
b: 'foo'
};
console.log(a.test.b);
(writable defaults to false, so you have to explicitly pass writable: true for the descriptor)
configurable: false means that the property descriptor can't be changed from a data descriptor to an accessor descriptor (or vice versa), nor can the property be removed from the object, but that doesn't prevent you from changing the actual value of the property, if the descriptor is writable.
Related
trying to figure out how to dynamicly create a new nested object from this one:
object1 = {
DataStore : false,
Header: false,
Footer : false,
Sidebar : false,
Main : false,
}
to nested one like this:
const registerComponentsLocal = {
'DataStore': {
'debug': false
},
'Header': {
'debug': false
},
'Footer': {
'debug': false
},
'Sidebar': {
'debug': false
},
'Main': {
'debug': false
},
}
keys and values have to by dynamic. Only important thing is a structure of the final object.
Any ideas would be greatly appricieated.
To create a new instance (i.e preserve the old one)
let originalObject = {
DataStore : false,
Header: false,
Footer : false,
Sidebar : false,
Main : false,
}
let newObject = Object.assign({}, originalObject) // Copies the original object
Object.entries(newObject).forEach(([key, value]) => newObject[key] = {debug: value})
Here's a method using reduce
Object.entries(object1)
.reduce((b,a) => ({...b, [a[0]] : {debug:a[1]}}), {})
To iterate, we need an array and Object.entries gives us that. Then, using reduce, we iterate through each item in object1, and build a result. Here, this line ({...b, [a[0]] : {debug:a[1]}}) takes our accumulating object b and adds in the next iterable: {key: { debug: value}}`
let object1 = {
DataStore : false,
Header: false,
Footer : false,
Sidebar : false,
Main : false,
}
const registerComponentsLocal = Object.entries(object1).reduce((b,a) => ( {...b, [a[0]] : { debug:a[1]} }),{})
console.log(registerComponentsLocal)
So let's say that I have an object literal, which is the following:
let test = {
settings: {
title: '',
has_content: true,
can_edit: false,
}
}
Now I have another object literal as shown below:
let test2 = {
...test,
settings: {
can_edit: true,
}
}
How can I bring over all the parameters from the test object literal but have the ability to change values in test2?
So ultimately, I'd like for this:
let test2 = {
settings: {
title: '', (This is default)
can_edit: true, (This value is changed)
has_content: true, (This is default)
}
}
Now, when I console.log test2, all that I see in the settings is the can_edit: true, but not the title or has_content.
You need to spread the test.settings in test2.settings to merge the properties and override with the latest one that are defined in test2.settings.
let test = {
settings: {
title: "",
has_content: true,
can_edit: false,
},
};
let test2 = {
settings: {
...test.settings,
can_edit: true,
},
};
console.log(test2);
Because you test.settings key will be replaced by test2.settings. so you should spread the test.setting into test2.settings like below
let test = {
settings: {
title: '',
has_content: true,
can_edit: false,
}
}
let test2 = {
settings: {
...test.settings,
can_edit: true,
}
}
console.log(test2)
It should be like this
let test2 = {
...test,
settings: {
...test.settings,
can_edit: true,
}
}
Explanation: You need to spread object by object. Be aware, if you use the spread before changing the values (like I did) your changes survive.
I am trying to discover the getters and setters on an object in typescript. I've tried Object.entries() and Object.keys() and neither of these return getters and setters. How can I enumerate these?
Edit: Here is some code that shows the problem:
class ThingWithGetter{
myProperty = 22;
get myGetter() {return 1;}
}
const thing = new ThingWithGetter()
// Does not show getter
console.log(Object.keys(thing));
// Does not show getter
const descriptors = Object.getOwnPropertyDescriptors(thing);
console.log(Object.keys(descriptors));
// Does not show getter
console.log(Object.entries(thing))
The reason this doesn't work is that the getter is on the class's prototype, which is on the instance's prototype chain, rather than on the instance itself.
To illustrate:
class A {
get x() { return 1 }
}
aInstance = new A()
// A {}
Object.getOwnPropertyDescriptors(aInstance)
// {}
Object.getOwnPropertyDescriptors(A.prototype)
// { constructor:
// { value: [Function: A],
// writable: true,
// enumerable: false,
// configurable: true },
// x:
// { get: [Function: get x],
// set: undefined,
// enumerable: false,
// configurable: true } }
Object.getOwnPropertyDescriptors(Object.getPrototypeOf(aInstance))
// { constructor:
// { value: [Function: A],
// writable: true,
// enumerable: false,
// configurable: true },
// x:
// { get: [Function: get x],
// set: undefined,
// enumerable: false,
// configurable: true } }
There a few good blog posts by Axel Rauschmayer on this topic:
https://2ality.com/2011/06/prototypes-as-classes.html
https://2ality.com/2012/11/property-assignment-prototype-chain.html
Note that if you are trying to enumerate all the properties, accessors, and methods on an object you will need to recursively walk the prototype chain until an object has a null prototype.
You can enumerate the getter name with this function:
function listGetters (instance) {
return Object.entries(
Object.getOwnPropertyDescriptors(
Reflect.getPrototypeOf(instance)
)
)
.filter(e => typeof e[1].get === 'function' && e[0] !== '__proto__')
.map(e => e[0]);
}
It will returns an array containing the getters names.
The function Object.getOwnPropertyDescriptors is in the ECMAScript latest draft specification, but is implemented in popular browsers. It returns the property descriptors belonging to an object.
Your use-case is a bit more difficult because the getter is defined on the class, not the object itself. So, you need to walk the prototype chain and build it that way. It's not enough to look at just the object's prototype, because the getter could be inherited from any superclass of the object's class.
Here's a recursive function which does it:
function getAllPropertyDescriptors(obj) {
if (!obj) {
return Object.create(null);
} else {
const proto = Object.getPrototypeOf(obj);
return {
...getAllPropertyDescriptors(proto),
...Object.getOwnPropertyDescriptors(obj)
};
}
}
The output for JSON.stringify(getAllPropertyDescriptors(thing)) is below. myGetter is the third property descriptor; the actual output if you don't JSON.stringify it also includes references to the actual functions, so you can see if they have get/set properties.
{
"myProperty": {"value": 22, "writable": true, "enumerable": true, "configurable": true},
"constructor": {"writable": true, "enumerable": false, "configurable": true},
"myGetter": {"enumerable": false, "configurable": true},
"__defineGetter__": {"writable": true, "enumerable": false, "configurable": true},
"__defineSetter__": {"writable": true, "enumerable": false, "configurable": true},
"hasOwnProperty": {"writable": true, "enumerable": false, "configurable": true},
"__lookupGetter__": {"writable": true, "enumerable": false, "configurable": true},
"__lookupSetter__": {"writable": true, "enumerable": false, "configurable": true},
"isPrototypeOf": {"writable": true, "enumerable": false, "configurable": true},
"propertyIsEnumerable": {"writable": true, "enumerable": false, "configurable": true},
"toString": {"writable": true, "enumerable": false, "configurable": true},
"valueOf": {"writable": true, "enumerable": false, "configurable": true},
"__proto__": {"enumerable": false, "configurable": true},
"toLocaleString": {"writable": true, "enumerable": false, "configurable": true}
}
You could convert this into an iterative version, but that's probably unnecessary since most prototype chains are short, and the iterative version would need some wrangling to get overrides in the right order.
You can try something like:
var obj = {
get foo() {
return Math.random() > 0.5 ? 'foo' : 'bar';
}
};
Object.keys(obj).forEach(key => {
console.log("Getter:", Object.getOwnPropertyDescriptor(obj, key).get);
console.log("Setter: ", Object.getOwnPropertyDescriptor(obj, key).set);
})
Hope this works for you.
Using this code I have this issue:
$.fn.dxwShow = function (options)
{
console.log(typeof(options));
dxwShowSetOptions(options);
setInterval(function(){
dxwShowChange();
}, dxwShowOptions.time);
};
var dxwShowOptions = {
"transition" : "SlideToggle",
"time": 1000
};
var dxwShowStatus = {
current : 0
};
function dxwShowSetOptions(options)
{
console.dir(typeof(options));
dxwShowOptions = Object.create(dxwShowOptions, options);
}
function dxwShowChange()
{
console.log(dxwShowOptions);
};
$(function()
{
options = {
"time": 700,
"debug" : true
};
$("#dxwShow").dxwShow(options);
});
I want to update dxwShowOptions and so I use Object.create passing first the object I wanna copy and so the object containing the new parameters. Where is the mistake?
PS :Chrome say that the object is at the Object.create line.
Object.create takes a map of property descriptors. options is not such a list.
See https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create
If you wanted to still use Object.create, you'd need to modify options to be something more like
var options = {
time: {
enumerable: true,
configurable: true,
writable: true,
value: 700
},
debug: {
enumerable: true,
configurable: true,
writable: true,
value: true
}
};
But probably you want to use something more like _.extend.
From the node repl:
foo = { bar: 'baz'};
console.log (Object.getOwnPropertyDescriptor(foo, 'bar'))
Returned value:
{ value: 'baz',
writable: true,
enumerable: true,
configurable: true }
How do you change the writable enumerable, and configurable to false? What are these values called? Are they part of ES5.1? Are there more that the repl didn't output?
"How do you change the writable enumerable, and configurable to false?"
Object.defineProperty(foo, 'baz', {
enumerable:false,
writable:false,
configurable:false
});
There's also Object.defineProperties, which is the same, except you can set multiple properties, and Object.create, which let's you create a new object, and set its prototype object, and its descriptors.
"What are these values called?"
They're property descriptors.
"Are they part of ES5.1?"
Yes, ES5.
"Are there more that the repl didn't output?"
More what, property descriptors? No.
squint:I think there is like a little typing error in your answer.
Your code:
Object.defineProperty(foo, 'baz', {
enumerable:false,
writable:false,
configurable:false
});
but the second argument must be the name of the property and not the value, so the correct code is:
Object.defineProperty(foo, 'bar', {
enumerable:false,
writable:false,
configurable:false
});
Just wanted to add this in
You can change the attributes when first creating an object like so:
var newObj = Object.defineProperty({}, 'aPropertyName', {
enumerable:false,
writable:false,
configurable:false
});
You can also, you can alter multiple properties at once:
var newObj = Object.defineProperties({}, {
aPropertyName: {enumerable: false, writable: false, configurable: false},
anotherPropertyName: {enumerable: true, writable: true, configurable: false},
finalPropertyName: {enumerable: true, writable: false, configurable: true},
});
And of course passing in the object name with the previous method:
Object.defineProperties(objectName, {
aPropertyName: {enumerable: false, writable: false, configurable: false},
anotherPropertyName: {enumerable: true, writable: true, configurable: false},
finalPropertyName: {enumerable: true, writable: false, configurable: true},
});