Deleting JS Object Properties a few levels deep - javascript

I have an object like this:
var myObj = {
first: {
sub: {
level: "some text",
level2: "some more text"
},
sub2: {
level3: "Something"
}
},
second: {
stuff: "More stuff...lots of stuff"
}
}
what I want to be able to do is say
delete myObj.first.sub.level
But I won't know what is being passed, or how many levels deep I need to go in order to remove the correct property, meaning it could simply be:
Storage.removeItem('myObj.first'); // This is currently working
Or something more complex:
Storage.removeItem('myObj.first.sub2.level3'); // This doesn't work because I'm more than 1 level into the object.
I'm kind of stuck, because I can get to the point where I have the key "level3" and it's property "Something", but I can't figure out how to back-step correctly in order to delete the full section of that object.
I need to replicate it's place in myObj so I can delete the full passed object.
'myObj.first.sub.level3'
If that makes sense...

It's not pretty, but you could use something like this:
function deepDelete(target, context) {
// Assume global scope if none provided.
context = context || window;
var targets = target.split('.');
if (targets.length > 1)
deepDelete(targets.slice(1).join('.'), context[targets[0]]);
else
delete context[target];
}
deepDelete('first.sub.level3', myObj);
deepDelete('myObj.first.sub2.level3');
It would probably be a good idea to modify it to test for typeof context[targets[0]] !== 'undefined' before descending. How exactly you react to that (return false, throw, or whatever else) would depend on how you're using it.

Related

Getting an object by its name contained in a string

I am trying to get a const object indirectly by its name, which is contained in a string. I have no idea if this is possible but if it is, it would make my life a hell of a lot easier. As an example in pseudocode: var obj = findObject("myConstObject");
I know this is a strange thing to need, but I am dealing with quite a large amount of data, and being able to grab objects in this way would work a lot better with my existing code. Thanks in advance!
You can use Object.getOwnPropertyNames() to get all property names of an object. Here is an example that demonstrates how to search a myObj1 that is in the global window scope, and a myObj2 that is in the myStuff object scope:
// object attached to window object:
myObj1 = { a: 1 };
function getKeyNames(aThis) {
return Object.getOwnPropertyNames(aThis || globalThis).sort();
}
console.log('search myObj1 in global scope:', getKeyNames().filter(name => name === 'myObj1'));
// object attached to my on stuff:
const myStuff = {
myObj2: { b: 2 },
deeperLevel: {
myObj3: { b: 3 },
}
}
console.log('search myObj2 in myStuff scope:', getKeyNames(myStuff).filter(name => name === 'myObj2'));
Output:
search myObj1 in global scope: [
"myObj1"
]
search myObj2 in myStuff scope: [
"myObj2"
]
Notes:
if needed, expand this code to search recursively the object hierarchy, so that myStuff.deeperLevel.myObj3 can be found searching myStuff
if needed, expand this code to search a list of objects of interest

QML Javascript Dictionary of Property Alias not Updating

My question is the following:
Do changes to the javascript dictionary values not modify the actual value that is mapped, but rather its own internal copy? Is there a way to get around this?
I have a javascript dictionary that contains property aliases of an object.
When I assign them values, the objects in the dictionary itself changes but it does not propagate outward to the actual display that I want to change.
I have had this problem before, placing the dot access outside of the dictionary access fixed it. However, I cannot do it this time around due to the fact that you cannot dot access using .text because it produces error of cannot read property of undefined.
QML: Cannot read property 'xxx' of undefined
My code resembles something of the following example, I had it obscured to protect actual info so sorry if it is a cringy example.
onUpdate passes in another dictionary that I want to tie to the local .qml dictionary.
ControllerDisplay.qml
// ...
property alias id1: id_box.text
// ...
SomeBox
{
id: id_box
text: "some text"
}
main.qml
ControllerDisplay{
id: controller
}
// ...
Connections
{
target: myguimodel
onUpdate:
{
var dict = { "ID1" : controller.id1}
for (var key in updates)
{
dict[key] = updates[key] // does NOT change the value in ControllerDisplay
controller.id1 = updates[key] // DOES change the value ControllerDisplay
}
}
}
When you do var dict = { "ID1" : controller.id1}, you store the value of controller.id1, not a reference to it.
If you want to be able to modify it you could do:
var dict = { "ID1": { "object": controller, "property": "id1"}};
for (var key in updates) {
var target = dict[key];
target.object[target.property] = updates[key];
}
This whole code doesn't look really QML idiomatic though. I would try using property binding if I were you.

How to grab the children of an Object.keys(myEl) reference

In the code below, I can get a reference to the text000 object, but I need to capture its child array as my target payload. Once I have a reference to the key, how can I capture its children?
Full object is below:
activeItem = [{"dnd":{"index":0,"active":true,"group":"common","label":"Text (000)","type":"text"},
"json":{"schema":{"properties":{"text000":{"title":"Text (000)","type":"string"}},"required":["text000"]},"layout":[{"key":"text000","description":"","floatLabel":"auto","validationMessages":{"required":"Required"}}]}}]
To grab a reference to the "text000" key I'm using:
const myEl = Object.keys(this.activeItem.json.schema.properties); // points to text000
I need to pull that key's contents/children > {"title":"Text (000)","type":"string"} out to use it as my target payload for this operation.
The text000 element is dynamic so I need its reference, which is why I'm using the Object.keys() method to point to it.
Feel free to school me on the proper names to use to refer to these elements. For example, not sure exactly how to reference > {"title":"Text (000)","type":"string"} with respect to the key text000. Is that the key's "children", "value", "contents" or what?
UPDATE:
console.log('TRY: ', this.activeItem.json.schema.properties[0]);
// Returns undefined
console.log('TRY2: ', this.activeItem.json.schema.properties);
// Returns {"text000":{"title":"Text (000)","type":"string"}}
I need something to return:
{"title":"Text (000)","type":"string"}
SOLUTION thanks #jaredgorski:
const properties = this.activeItem.json.schema.properties;
const propertiesKeys = Object.keys(properties);
const propertiesKeysFirstVal = Object.keys(properties)[0];
const logProperties = properties[propertiesKeysFirstVal];
console.log('PROPERTIES KEYS:', propertiesKeys);
console.log(
'VALUES OF FIRST PROPERTIES KEY:',
propertiesKeysFirstVal
);
console.log('RESULT:', logProperties);
PROPERTIES KEYS: ["text000"]
wrux-wrux-form-builder.js:1782 VALUES OF FIRST PROPERTIES KEY: text000
wrux-wrux-form-builder.js:1783 RESULT: {title: "Text (000)", type: "string"}
You need to remember that activeItem is an array. As long as you include the index (in this case the first index, which is [0]), you can access the json property (or key) and continue down the chain to retrieve the values in text000.
The other trick here is that you're wanting to access the first key in properties, but you don't know the name of that key yet. So what you need to do is actually make an array of the keys and then find out the name of the first key in that properties object. To do this, you can use Object.keys(), a method which turns the keys of an object into an array. Once you have the name of this key, you only need to use bracket notation on the properties object to find the value for this key. I'll show you how this works in the snippet below.
Here are some references so that you can learn more about how this works:
MDN page on the Object.keys() method
Accessing JavaScript
object properties: Bracket notation vs. Dot notation
And here's the working example:
const activeItem = [
{
"dnd": {
"index": 0,
"active": true,
"group":"common",
"label":"Text (000)",
"type":"text",
"icon":"text_fields",
"fontSet":"material-icons",
"class":""
},
"json": {
"schema": {
"properties": {
"text000":{
"title":"Text (000)",
"type":"string"
}
},
"required":["text000"]
},
"layout":[
{
"key":"text000",
"description":"",
"floatLabel":"auto",
"validationMessages": {
"required":"Required"
}
}
]
}
}
]
// This is the dirty looking version:
const logPropertiesDirty = activeItem[0].json.schema.properties[Object.keys(activeItem[0].json.schema.properties)[0]]
console.log("First, the dirty version where we don't save anything to variables. Everything is laid out here.")
console.log('WHAT WE DID:', 'activeItem[0].json.schema.properties[Object.keys(activeItem[0].json.schema.properties)[0]]')
console.log('RESULT:', logPropertiesDirty)
console.log('=================================================')
// This is the cleaner version, using variables to store things as we go:
const properties = activeItem[0].json.schema.properties;
const propertiesKeys = Object.keys(properties);
const propertiesKeysFirstVal = Object.keys(properties)[0];
const logPropertiesClean = properties[propertiesKeysFirstVal];
console.log('Now, the cleaner version. We save some values to variables to make things more readable.')
console.log('PROPERTIES OBJECT:', properties)
console.log('PROPERTIES KEYS:', propertiesKeys)
console.log('NAME OF FIRST PROPERTIES KEY:', propertiesKeysFirstVal)
console.log('RESULT:', logPropertiesClean)
Regarding what to call these things, I've always thought of Objects as generally consisting of "key-value pairs". Keys can also be called properties and values can also be called contents (I guess).
myObject = {
key1: value1,
property2: contentsOfProperty2
}
At the end of the day, clear communication is all that counts! So, whatever names you come up with (as long as they make reasonable sense), I'm sure people won't be jerks about it unless they feel like they have something to prove.
You should be able to use Object.values over this.activeItem.json.schema.properties:
The Object.values() method returns an array of a given object's own enumerable property values, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).
const object1 = {
a: 'somestring',
b: 42,
c: false
};
console.log(Object.values(object1));
// expected output: Array ["somestring", 42, false]
It is not supported across the map yet, but you should be able to load a polyfill if you need it.

find if path exists in json nodejs

I would like to add to the an existing json a new value in the following path:
 
VAL:"BS", PATH:["info", "bosses", "lives"]
if my json had the passes it will add the value, otherwise I will create the fields
example:
var myJson = {
    "root": {
        "name": "jim",
        "age": "4",
        "info": {"bosses": {"name": "sam"}}
    }
}
so my new json will look like this:
var myNewJson = {
    "root": {
        "name": "jim",
        "age": "4",
        "info": {"bosses": {"name": "sam", "lives": "BS"}}
    }
}
an example when I didn't have the fields:
var myJson = {
    "root": {
        "name": "jim",
        "age": "4",
    }
}
the output:
var myNewJson = {
    "root": {
        "name": "jim",
        "age": "4",
        "info": {"bosses": {"lives": "BS"}}
    }
}
an example where part of the path exists I didn't have the fields:
var myJson = {
    "root": {
        "name": "jim",
        "age": "4",
 "info": {"salary": 500}
    }
}
the output:
var myNewJson = {
    "root": {
        "name": "jim",
        "age": "4",
        "info": {"salary": 500, "bosses": {"lives": "BS"}}
    }
}
how can I check if path exists (note: part of the path might exist- how can I know from where to start it?)
This is old, but...
testing existence of fields on paths is nicer now, with optional chaining, like:
var infoExists = !!myJson?.root?.info - the ?. means that if root were missing, the line wouldn't break.
In this case though, I wouldn't worry about testing for the existence of fields, I'd use spread operators to just rebuild the info object:
var newInfo = {"bosses": {"lives": "BS"}};
var info = {...myJson.root.info, ...newInfo};
if myJson.root.info doesn't exist, no problem (as long as myJson.root does, cue an optional chaining check?), we just get the newInfo.
if myJson.root.info currently holds {"salary": 500}, the spread operators will combine that to "info":{"salary": 500, "lives": "BS"}.
if myJson.root.info currently holds the same as newInfo, well, no sweat, we end up with no change.
Now you have the info object exactly as you want it, you can simply replace it in the original object with
myJson.root.info = ...info;
The first thing you could think it works could be some code like:
if (myObject.attributeName){
//property exists!
}
It will work for you in many tests but I sure you know that javascript manage some values as truthy or falsy. It use lot's of different type value as boolean false in many comparison (just === not convert type).
When you check something as
if(somethingtotest){
// it's true
}
It is the same you'd write
if(somethingtotest == true){
// it's true
}
'==' operator tryes to convert different types to be "similar" together.
In the first example code many of object attribute values can be '==' true.
That attribute value is truthy, meaning it’s an object, a non-empty string, a non-zero number that’s not NaN, true, and not null or undefined.
That means if the attribute is an empty string (“”), this check will fail. The same if value is 0 (zero), null, false. Failing, in this case, doesn’t mean that the property doesn’t exist. In fact, the property does exist and contains a value, but the value is falsy and so doesn’t pass this test.
Since ECMAScript 5 the base Object has the function hasOwnProperty(propertyName)
So you could try
if(myObject.hasOwnPorperty('attributeName')){
// do something
}
This function remembers us that the Objects has also prototype attributes that our object could inherit. For example if I write
myObject.anyAttribute='AnyValue';
var my1stObject = Object.create(myObject);
var my2ndObject = Object.create(myObject);
myObject.anyAttribute='AnotherValue';
console.log(my1stObject.anyAttribute);
console.log(my2ndObject.anyAttribute);
last two rows will print 'AnotherAttribute'.
In this case 1st and 2nd objects have not own property anyAttribute but they will use the prototipe one.
Different if you write
myObject.anyAttribute='AnyValue';
var my1stObject = Object.create(myObject);
var my2ndObject = Object.create(myObject);
my1stObject.anyAttribute='AnotherValue';
console.log(my1stObject.anyAttribute); //AnotherValue
console.log(my2ndObject.anyAttribute); //AnyValue
First object hasOwnProperty 'anyAttribute' because we set it.
At last, to be shure to check if property, proptotipe or own, really exists, you would like to use
if('anyProperty' in myObject){
//do something
}
I suggest you to read it better at this link:
https://www.nczonline.net/blog/2010/07/27/determining-if-an-object-property-exists/

Deleting Objects in JavaScript

I'm a bit confused with JavaScript's delete operator. Take the following piece of code:
var obj = {
helloText: "Hello World!"
};
var foo = obj;
delete obj;
After this piece of code has been executed, obj is null, but foo still refers to an object exactly like obj. I'm guessing this object is the same object that foo pointed to.
This confuses me, because I expected that writing delete obj deleted the object that obj was pointing to in memory—not just the variable obj.
Is this because JavaScript's Garbage Collector is working on a retain/release basis, so that if I didn't have any other variables pointing to the object, it would be removed from memory?
(By the way, my testing was done in Safari 4.)
The delete operator deletes only a reference, never an object itself. If it did delete the object itself, other remaining references would be dangling, like a C++ delete. (And accessing one of them would cause a crash. To make them all turn null would mean having extra work when deleting or extra memory for each object.)
Since Javascript is garbage collected, you don't need to delete objects themselves - they will be removed when there is no way to refer to them anymore.
It can be useful to delete references to an object if you are finished with them, because this gives the garbage collector more information about what is able to be reclaimed. If references remain to a large object, this can cause it to be unreclaimed - even if the rest of your program doesn't actually use that object.
The delete command has no effect on regular variables, only properties. After the delete command the property doesn't have the value null, it doesn't exist at all.
If the property is an object reference, the delete command deletes the property but not the object. The garbage collector will take care of the object if it has no other references to it.
Example:
var x = new Object();
x.y = 42;
alert(x.y); // shows '42'
delete x; // no effect
alert(x.y); // still shows '42'
delete x.y; // deletes the property
alert(x.y); // shows 'undefined'
(Tested in Firefox.)
"variables declared implicitly" are properties of the global object, so delete works on them like it works on any property. Variables declared with var are indestructible.
Coming from the Mozilla Documentation, "You can use the delete operator to delete variables declared implicitly but not those declared with the var statement. "
Here is the link: https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference:Operators:Special_Operators:delete_Operator
delete is not used for deleting an object in java Script.
delete used for removing an object key in your case
var obj = { helloText: "Hello World!" };
var foo = obj;
delete obj;
object is not deleted check obj still take same values delete usage:
delete obj.helloText
and then check obj, foo, both are empty object.
Setting a variable to null makes sure to break any references to objects in all browsers including circular references being made between the DOM elements and Javascript scopes. By using delete command we are marking objects to be cleared on the next run of the Garbage collection, but if there are multiple variables referencing the same object, deleting a single variable WILL NOT free the object, it will just remove the linkage between that variable and the object. And on the next run of the Garbage collection, only the variable will be cleaned.
Just found a jsperf you may consider interesting in light of this matter. (it could be handy to keep it around to complete the picture)
It compares delete, setting null and setting undefined.
But keep in mind that it tests the case when you delete/set property many times.
Aside from the GC questions, for performance one should consider the optimizations that the browser may be doing in the background ->
http://coding.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/
It appears it may be better to null the reference than to delete it as that may change the behind-the-scenes 'class' Chrome uses.
IE 5 through 8 has a bug where using delete on properties of a host object (Window, Global, DOM etc) throws TypeError "object does not support this action".
var el=document.getElementById("anElementId");
el.foo = {bar:"baz"};
try{
delete el.foo;
}catch(){
//alert("Curses, drats and double double damn!");
el.foo=undefined; // a work around
}
Later if you need to check where the property has a meaning full value use el.foo !== undefined because "foo" in el
will always return true in IE.
If you really need the property to really disappear...
function hostProxy(host){
if(host===null || host===undefined) return host;
if(!"_hostProxy" in host){
host._hostproxy={_host:host,prototype:host};
}
return host._hostproxy;
}
var el=hostProxy(document.getElementById("anElementId"));
el.foo = {bar:"baz"};
delete el.foo; // removing property if a non-host object
if your need to use the host object with host api...
el.parent.removeChild(el._host);
I stumbled across this article in my search for this same answer. What I ended up doing is just popping out obj.pop() all the stored values/objects in my object so I could reuse the object. Not sure if this is bad practice or not. This technique came in handy for me testing my code in Chrome Dev tools or FireFox Web Console.
This work for me, although its not a good practice. It simply delete all the
the associated element with which the object belong.
for (element in homeService) {
delete homeService[element];
}
The delete operator deletes an object, an object's property, or an element from an array. The operator can also delete variables which are not declared with the var statement.
In the example below, 'fruits' is an array declared as a var and is deleted (really??)
delete objectName
delete objectName.property
delete objectName[index]
delete property // The command acts only within a with statement.
var fruits = new Array("Orange", "Apple", "Banana", "Chery");
var newParagraph = document.createElement("p");
var newText = document.createTextNode("Fruits List : " + fruits);
newParagraph.appendChild(newText);
document.body.appendChild(newParagraph);
//Delete the array object.
delete fruits;
var newParagraph1 = document.createElement("p");
var newText1 = document.createTextNode("Display the Fruits after delete the array object - Fruits List : "+ fruits;);
newParagraph1.appendChild(newText1);
document.body.appendChild(newParagraph1);
https://www.w3resource.com/javascript/operators/delete.php
We have multiple ways to Delete the Object property.
Arrow Function: We can also use the arrow function to remove the property from an object which is a one-liner solution.
const obj = {
'first': 'one',
'second': 'two',
'third': 'three'
}
const fn = (key, { [key]: deletedKey, ...others }) => others;
console.log(fn('first', obj)) // { 'second': 'two', 'third': 'three' }
Reduce Method: We can use the reduce method to delete the specific property from the original object in javascript.
const obj = {
'first': 'one',
'second': 'two',
'third': 'three'
}
const exceptSecond = Object.keys(obj).reduce((acc, key) => {
if (key !== 'second') {
acc[key] = obj[key]
}
return acc
}, {})
console.log(exceptSecond) // { 'first': 'one', 'third': 'three' }
Delete: This is easy simple way to delete.
delete obj.first;
// Or
delete obj['first'];
Using unset, Omit, Pic Method from "loadash" lib:
import { unset } from 'lodash'
const obj = {
'first': 'one',
'second': 'two',
'third': 'three'
}
unset(obj, 'third') // true
console.log(obj) // { 'first': 'one', 'second': 'two' }
// Using omit
import { omit } from 'lodash'
const obj1 = {
'first': 'one',
'second': 'two',
'third': 'three'
}
omit(obj1, [ 'first', 'second' ])
console.log(obj1)
Reflect Delete Property: This is the new built-in Object introduced in ES6. Now it is possible to delete object property by calling the deleted property() function from this Refect Object.
This function is equivalent to what we have discussed with the delete operator in the first method.
const someObject = {
'first': 'one',
'second': 'two',
'third': 'three'
}
Reflect.deleteProperty(someObject, 'second')
console.log(someObject) // { 'first': 'one', 'third': 'three' }
If you want the object to be deleted based on its value do this:
Object.keys(obj).forEach((key) => {
if (obj[key] === "Hello World!") {
delete obj[key];
}
});
But deleting an object is not a good idea. So, set it to undefined, so that when you pass it to a parameter. It won't be showing. No need to delete.
Object.keys(obj).forEach((key) => {
if (obj[key] === "Hello World!") {
obj[key] = undefined;
}
});

Categories

Resources