remove array element with non numeric key - javascript

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'];).

Related

Why does JS allow property access with an array as key?

Suppose I have an object
obj = {
a : 1
}
I'm able to access property a via obj["a"] but I'm also able to access it via obj[["a"]]. How is that possible?
Object keys are always strings (or, rarely, symbols). When you do
obj[<expression>]
the interpreter will try to turn expression into a valid key, if it isn't one already. In this case, turning ["a"] into a string results in "a", so both obj["a"] and obj[["a"]] work.
(When an array is implicitly turned into a primitive, like here, it gets .joined by a comma, and ["a"].join(',') === "a")

Array.length is a property not a method, but how .length is work like a method?

A method can get a value from an Array with the logic of that method. but length is not a method to an array, though returning a value when we write array.length, How?
"How did I get to know that .length is property to an array? is 'We all know that a method should have () when we are invoking a method, but .length don't invoke with (). so it is property to an object'".
var arr = [1,2,3,8,6,4,9,5,8,6];
console.log(arr.length); //10 -
console.log(Math.max(...arr)); //9
max() is returning a value because it is methode
As a property how does .length return a value?
Arrays are officially called "Array exotic objects". This sort of very weird behavior you're seeing, where an object property apparently changes itself automatically, is not visible (or possible to implement) on ordinary Javascript objects:
This specification defines several kinds of built-in exotic objects. These objects generally behave similar to ordinary objects except for a few specific situations. The following exotic objects use the ordinary object internal methods except where it is explicitly specified otherwise below:
and
An Array object is an exotic object that gives special treatment to array index property keys (see 6.1.7). A property whose property name is an array index is also called an element. Every Array object has a length property whose value is always a nonnegative integer less than 232. The value of the length property is numerically greater than the name of every own property whose name is an array index; whenever an own property of an Array object is created or changed, other properties are adjusted as necessary to maintain this invariant. Specifically, whenever an own property is added whose name is an array index, the value of the length property is changed, if necessary, to be one more than the numeric value of that array index; and whenever the value of the length property is changed, every own property whose name is an array index whose value is not smaller than the new length is deleted. This constraint applies only to own properties of an Array object and is unaffected by length or array index properties that may be inherited from its prototypes.
In other words, an array's .length is a specific exception to the general rule that objects' properties do not change by themselves.
Note that getters can have a similar functionality:
const obj = {
get length() {
return Object.keys(this)
.filter(key => /^[0-9]+$/.test(key))
.length;
}
};
obj[0] = 'x';
obj[1] = 'y';
console.log(obj.length);
But an array's .length is not a getter, at least not visibly:
var arr = [1,2,3,8,6,4,9,5,8,6];
console.log(Object.getOwnPropertyDescriptor(arr, 'length'))
If it were a getter, you'd instead see a get property on the descriptor, like:
const obj = {
get length() {
return Object.keys(this)
.filter(key => /^[0-9]+$/.test(key))
.length;
}
};
console.log(Object.getOwnPropertyDescriptor(obj, 'length'))
Array length is all implemented under-the-hood, and not visible to the running Javascript.
You could take a property and assign or get a value from it, but it is iomplementes as setter and getter. This allows to use a function as simple property and uses the assigned value for changing other things, like to remove items.
var object = {
l: 42,
get length() { return this.l; },
set length(l) { this.l = l; },
}
console.log(object.length);
object.length = 2;
console.log(object.length);
Good Question. The only catch here is that you believe Array.length is calculated when you invoke/call this property. No, it does not happen like that.
When an Array is created, it's properties get set. These properties like length, prototypical functions etc. contain a value when an Array is created. When you execute Array.length, you are only getting the value of that property. In case of functions, the code execution happens when you invoke the call.
Think of it like a constructor in the Array definition which sets the property length as soon as an object of Array class is created and modified.
The length property of an object which is an instance of type Array
sets or returns the number of elements in that array. The value is an
unsigned, 32-bit integer that is always numerically greater than the
highest index in the array.
As stated, you can also use it to set the number of elements. This is achievable using a getter and setter by theory.
The following example sets the latest property of an object which will represent the last element of an internal array.
var obj = {
log: ['a', 'b', 'c'],
get latest() {
if (this.log.length == 0) {
return undefined;
}
return this.log[this.log.length - 1];
},
set latest(val) {
this.log[this.log.length - 1] = val;
}
}
obj.latest = 'z';
console.log(obj.latest);

"object[value] = true" meaning

i know this is kind of weird question but, i was creating a guard to prevent duplicate values in array i write some part and got a little help from stackoverflow but i can't understand code meaning properly
so i created Object with null prototype and iterated for loop over it to detect duplicate values (i know Set constructor is much easier but i am doing it in my server-side code and since older browsers does not support Set it would be dangerous to use Set). here is my code
var duplicateTagsGuard = Object.create(null);
for(var co = 0; co < tags.length; co++){
let val = tags[co];
if(val in duplicateTagsGuard){
return res.status(409).send({
message: ''
})
}
duplicateTagsGuard[val] = true
}
and the part i cant understand is duplicateTagsGuard[val] = true
so if we split my code step by step and explain it would be like
1.first create null Object
2.iterate for loop on it and declare variable val and make it equal to every element in tags array
3.then check if that val is in duplicateTagsGuard object and if it is use return statement to prevent continuing for loop and if it is not then we are adding val's value to object but i don't know how it is implemented with that part of code (duplicateTagsGuard[val] = true) if anyone can explain i will be glad
first create null Object
It is not creating a null object but it is creating an object with null as the prototype check the Object.create docs:
var duplicateTagsGuard = Object.create(null);
console.log(`duplicateTagsGuard is an empty object:`);
console.log(duplicateTagsGuard);
console.log(`Prototye of duplicateTagsGuard is null: `);
console.log(Object.getPrototypeOf(duplicateTagsGuard));
iterate for loop on it and declare variable val and make it equal to every element in tags array
This part is correct every time the loop runs a new variable is created with for block scope and is assigned the value of the current coth index value of the tags array.
then check if that val is in duplicateTagsGuard object and if it is use return statement to prevent continuing for loop and if it is not then we are adding val's value to object but i don't know how it is implemented with that part of code (duplicateTagsGuard[val] = true)
It is checking whether val is a property of the duplicateTagsGuard object, if it is already present then the return is used to return the response else it is adding that property to the duplicateTagsGuard object with the bracket notation [propertyName] and assigning it's value as true.
var duplicateTagsGuard = Object.create(null); //creating a new empty object with prototype as null
let val = "hello"; //creating a new variable
duplicateTagsGuard[val] = true; //adding the property with the value of the variable val
console.log(val in duplicateTagsGuard); //checking if the added property is present in the object
The code is creating a dictionary of val. Basically, when you iterate through the tags array, it checks whether the item in the array (accessed by tags[co]) is already present in the dictionary duplicateTagsGuard. If it has been encountered before, it will perform a certain action.
At the end of the loop, it simply injects the item into the dictionary. The dictionary therefore keep track of whether an item has been encountered before in the for loop.
The injection is done by using the item as the key in the dictionary, since it is easier to look it up (you simply have to do item in dictionary, which is basically val in duplicateTagsGuard in the actual implementation of the code). It does not matter what value you use, so a true value is used as a placeholder.

Can an Object object be coerced into an Array object?

Crockford writes in http://javascript.crockford.com/survey.html:
"There are two ways to make a new array:
var myArray = [];
var myArray = new Array();"
So I'm confused by these two lines in some AJAX code I am reading:
var obj={}; // obj is an Object object (i.e. a hash table)
obj[4] = 'x'; // now obj is suddenly an Array object via an integer key?
In JavaScript are an object and an array really just the same thing, but with a variant on the key type?
In other words, is this the same as in php where we can use either a name (string) or an integer for a hash key?
I've Googled for an answer on this but can't seem to nail down an article which discusses this issue.
One possibility that comes to mind is that perhaps the first line is syntactic lint because the 2nd line overwrites the previous definition of obj as it creates a new Array object.
it does not become an array, it is simply an Object with a '4' property, like this:
var obj = {
'4': 'x'
};
it is just converted to a string when used as a property like obj['4'] = 'x';
Everything but primitive datatypes is an object in JavaScript. Objects can have a properties and there are two ways to access object properties:
Dot notation, foo.bar, which you can use as long as the property name is a valid identifier.
Bracket notation, foo['bar'] which you have to use if the key is not a valid identifier [spec]. For example, if it is a number, or contains a space or you have a variable with the name.
Hence, bracket notation is not a characteristic of arrays and if you see it, it does not mean the value is an array. It is simple one of two ways of accessing properties.
The elements of an array are just properties with numeric keys. Arrays are built on top of objects and implement some additional methods which treat these numeric properties in a special way. For example the .length property is automatically updated when you add new elements. But ultimately they are just normal properties.
In your example you have a simple object. You have to access the property with obj[4] or obj['4'] because obj.4 is invalid since 4 is not a valid identifier (basically everything that you can use as variable name is a valid identifier. var 4 = 'foo'; is invalid).
And since arrays are just objects, if you could use numbers as identifiers, you were also able to access an element with arr.4.
As far as I know, no, an object can't be coerced into an array. But, it can look and act like an array, and that's what's happening here. Numbers, and anything else that can be coerced to a string, are perfectly valid property names for Javascript objects, so
obj[4] = 1;
obj['spam'] = 2;
are both valid ways of setting a property on the object. That doesn't make the object an array. An Array is a special class of object with specific methods (.slice(), .concat(), etc) and a length property that's kept up to date with the number of items in the array.
Yes
Javascript Array is very different from tradition array, you can think of it as object.
var array = [1,2,3] is equivalent to var object = {'0' : 1, '1' : 2, '2' : 3}
except array inherited from Array.prototype and object inherited from Object.prototype, where Array.prototype will contain method such as length.
Javascript is a loosely-typed, prototype-based language. Even primitive types like a boolean can be treated like an object (though you aren't going to get far). Almost everything in javascript is, at root, an object.
Understanding this, an array IS an object. You can arbitrarily add properties to any object:
var xml = new XMLHttpRequest();
xml[4] = 'x';
console.log(xml);
That object is still an instance of XMLHttpRequest. It now has a property labeled 4 with a value of x. You can treat anything like this -- even a function:
var test_func = function () {
alert('woah!');
}
test_func[4] = 'x';
console.log(test_func[4]);
The take-away here is that the obj[key] = value notation is NOT indicative of an "array" type, like it is in languages such as PHP. Rather, it is an alternate way to access properties of any object, and is equivalent to obj.key = value (you can't use obj.4 = 'x', though, that's invalid syntax). The other take-away is that any object in javascript can be modified or used in pretty much any way. You shouldn't misuse objects, but you can
Check it out here: http://jsfiddle.net/w2AqJ/
Documentation
Array on MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array
Javascript "associative arrays" considered harmful by Andrew Dupont - http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/

Why does delete keep Array elements?

Today I stumbled upon a question here on Stack Overflow - How do I remove objects from a javascript associative array?. What struck me was that the accepted answer was both misleading and heavily upvoted, so I highlighted the possible pitfall.
However, while cobbling together a corrective answer, I realized I have no idea as to why it makes sense for delete to keep elements assign undefined instead of removal.
var elements = new Array()
elements.push(NaN)
elements.push(NaN)
elements.push(NaN)
delete elements[1]
console.log("number of elements: ", elements.length) // returns 3
Is there a rationale behind it?
I realized I have no idea as to why it makes sense for delete to assign undefined instead of removal.
It doesn't. delete removes properties from objects, it does not set them to undefined. Here's an easy way to tell:
var a = ['a', 'b', 'c'];
console.log(1 in a); // logs "true"
delete a[1];
console.log(1 in a); // logs "false"
Note that after the delete, a doesn't have a property called 1 anymore. At all.
Contrast with:
var a = ['a', 'b', 'c'];
console.log(1 in a); // logs "true"
a[1] = undefined;
console.log(1 in a); // logs "true"
There, a still has a property called 1, it's just that the property's value is undefined.
It's useful to understand that in JavaScript, arrays aren't really arrays at all. They're just objects, array "indexes" are just property names (which are strings — yes, really, we just tend to write them as numbers), arrays have special handling of property names that are all numeric (indexes), a special length property, and some functions they get from Array.prototype. This is very clearly laid out in Section 15.4 of the spec. Once you have it set firmly in your head that JavaScript arrays aren't really arrays, they make a lot more sense. :-)
Deleting an array "index" property from an array does not change its length (not even if you delete the highest-numbered one); it just creates a hole in the array (JavaScript "arrays" are sparse arrays by their nature; e.g., they can have gaps in them). So in my first example above, I get exactly the same array that I'd've gotten if I'd done this:
var a = [];
a[0] = 'a';
a[2] = 'c';
Note the gap, the array has no 1 element/property.
If you say:
var foo = a[3];
...foo can get the value undefined for two completely different reasons:
a has a property called 3 that has the value undefined, or:
a has no property called 3 at all; the result of a property accessor operation on an object that doesn't have a property by that name is undefined. This if-no-property-return-undefined is covered by the spec in a fairly convoluted way, but mostly in Section 8.12.3.
These are very distinct things.
It doesn't assign undefined. It deletes the property. (If you try to access a property that doesn't exist, you will get undefined, and length is based on the highest numbered item in the array).
It makes sense, because it works that way on any kind of object. For it to act otherwise, it would have to special case objects if they were an instanceof Array but only if it was a property with a numeric name.
Use splice if you want to remove an item from an array.
> var elements = [NaN, NaN, NaN];
> elements.splice(1,1);
> console.log(elements);
[ NaN, NaN ]
JavaScript arrays can be "sparse". That is, some slots can be empty in the sense of never having had a value assigned, or having a value deleted. If you test the value associated with that index you'll get back undefined because it doesn't exist, not because it was assigned the value undefined.
When delete removes an item from an array it doesn't automatically slide the rest of the elements up to fill the space: the other elements retain their existing indexes, which in turn means the .length property doesn't change since .length is defined as being equal to the highest assigned index plus one.
If you want to remove an array element and have the other elements renumbered use the .splice() method.
This is because delete operator removes property, and removed property has value undefined. To remove element from array you can use splice method of array.
All of this is because of how the delete operator in javascript work.
When you do not set property of object and try to check its value it will be undefined:
var obj = {};
alert(obj.foo); // undefined
which is the same as:
alert(obj['foo']); // undefined
And look at this:
// create empty object
var obj = {};
// check its property named 1
alert(obj[1]); // undefined
// set property named 1 to value 'fooo'
obj[1] = 'fooo';
// and check it
alert(obj[1]); // 'fooo'
// now delete it
delete obj[1];
// and check again
alert(obj[1]); // undefined
delete has removed property and its value is undefined - and all above code was about object.
Now look at the arrays:
var arr = []; // it's better to use [] than new Array();
alert(arr[1]); // undefined - same as above
// assign value
arr[1] = 'fooo'
// check it
alert(arr[1]); // 'fooo' - same as above
// remove it
delete arr[0];
// and check
alert(arr[1]); // undefined - same as above
So behavior is the same, but what about length property of array. Specification http://es5.github.com/#x15.4.5.2 says:
"The length property of this Array object is a data property whose value is always numerically greater than the name of every deletable property whose name is an array index."
So when you look at this:
var arr = ['foo', 'bar', 'foobar'];
alert(arr.length); // 3
// delete first
delete arr[1];
// and check length
alert(arr.length); // 3
Last check gives 3 because the last deletable property in this array has index 2 - first property (with index 0) has value undefined (delete operator set this value), second item (with index 1) has value 'bar' and third (with index 2) has value 'foobar'. So according to specification length = 2 + 1 ('allways numerically greater than last deletable');
This is visible also in this code:
var arr = [];
arr[10] = 'foo';
// element with index 10 is set to 'foo' but elements from 0 to 9 don't have value - they are undefined
// now check length
alert(arr.lenght); // 11
Last deletable property index is 10, so 10 + 1 gives 11, despite of previous elements that are undefined.
So delete operator does his work, but it is not designed to remove items from array.

Categories