I am very new to JavaScript and I am trying to figure out how to set a function to remove the last key:value pair to the right, much like array.pop for an array. This is an assignment I am working on. It seems confusing to me because, from my limited understanding of JS their is no specific order in a list of properties in an object. If anyone has any insight I would appreciate it. Here is the object:
var array = {length:0, size:big, smell:strange};
this is where I have started to go, but just having a hard time completing the function:
array.pop = function() {
//...
};
Ultimately I would like it to turn out like this:
array = {length:0, size:big};
Thanks in advance.
Objects do not have any defined order of properties so there is no "last" property. You have to remove a property by name, not position.
You can, of course, iterate over the properties and inspect them as you iterate and decide whether you want to delete any given property by looking at its name. Some javascript implementations will preserve the order that properties were added, but that is specifically not guaranteed by the ECMAScript specification so it cannot be relied upon.
This will work
const car = {
color: 'blue',
brand: 'Ford'
}
let keys = Object.keys(car)
delete car[keys[keys.length-1]]
console.log(car)
This answer is good for those situtations where the key is dynamically generated numbers like 0,1,2,3,4 etc
const myObject = {
0: 'somestring',
1: 42,
2: false
};
delete myObject[`${Object.keys(myObject).length-1}`]
console.log(myObject);
output:
Object { 0: "somestring", 1: 42 }
this one line logic may not good when key is a string. So, carefully use it.
The snippet below demonstrates that "objects have no order", and an [inefficient] workaround: use an array alongside of the object, to store the order that the properties were added to the object.
Click to add random properties, and note the order that they appear below.
In CodePen (or on my webserver) the properties seem to be stored sorted numerically (even though they're stored as strings).
However, in the snippet below they seem to be ordered randomly.
Neither are the order that the properties are added.
It should be noted:
Unlike what common belief suggests (perhaps due to other programming languages like delete in C++), the delete operator has nothing to do with directly freeing memory. Memory management is done indirectly via breaking references.
More info: delete operator and Memory Management.
var obj={}, // object to store properties (keys) and values
props=[]; // array to store property names
add.onclick=function(){
var prop=rnd(), val=rnd(); // get 2 random numbers
obj[ prop ] = val; // add property & value → object
props.push( prop ); // add property name → array
updateInfo(); // display object
}
del.onclick=function(){
var lastProp=props.pop(); // get/remove last property name in array
delete obj[ lastProp ]; // remove property
updateInfo(); //display object
}
function rnd(){return Math.floor(Math.random()*1E5);} // random 0-99999
function updateInfo(){ // show pretty object 😘
info.innerHTML=JSON.stringify(obj).replace(/[\{\}]+/g,"").replaceAll(',','<br>');
}
<button id='add'>add new property</button>
<button id='del'>delete last added</button>
<div id='info'></div>
Related
I want to add attribute to a JS object, but in a custom place, After a given attribute.
var me = {
name: "myname",
age: "myage",
bday: "mybday"
};
me["newAt"] = "kkk"; //this adds at the end of the object
Is there a way to specify the object (me), an attribute(age) in it and add a new attribute(newAt) right after the specified one? A better way than doing string operations?
var newMe = {
name: "myname",
age: "myage",
newAt: "newAttr",
bday: "mybday"
}
UPDATE: (Since people are more focused on why I'm asking this than actually answering it)
I'm working on a drawable component based on user input - which is a JS object. And it has the ability to edit it - so when the user adds a new property based on "add new node" on the clicked node, and I was thinking of adding the new node right after it. And I want to update the data accordingly.
JavaScript object is an unordered list of properties. The order is not defined and may vary when using with an iterator like for in. You shouldn't base your code on the order of properties you see in debugger or console.
JavaScript objects do, as of ES2015, have an order to their properties, although that order is only guaranteed to be used by certain operations (Object.getOwnPropertyNames, Reflect.ownKeys, etc.), notably not for-in or Object.keys for legacy reasons. See this answer for details.
But you should not rely on that order, there's no point to it, it's more complicated than it seems initially, and it's very hard to manipulate (you basically have to create a new object to set the order of its properties). If you want order, use an array.
Re your edit:
I'm working on a drawable component based on user input - which is a JS object. And it has the ability to edit it - so when the user adds a new property based on "add new node" on the clicked node, and I was thinking of adding the new node right after it. And I want to update the data accordingly.
The best way to do that is, if you want a specific order, keep the order of keys in an array and use that to show the object.
While you could use ES2015's property order for it, to do so you'd have to:
Require your users use a truly ES2015-compliant browser, because this cannot be shimmed/polyfilled
Destroy the object and recreate it adding the properties in the specific order you want each time you add a property
Forbid properties that match the specification's definition of an array index
It's just much more work and much more fragile than keeping the order in an array.
The simplest solution I could find was to iterate through the keys of the parent and keep pushing them to form a clone of the parent. But to additionally push the new object if the triggered key is met.
var myObj = {
child1: "data1",
child2: "data2",
child3: "data3",
child4: "data4"
};
var a = (function addAfterChild(data, trigChild, newAttribute, newValue) {
var newObj = {};
Object.keys(data).some(function(k) {
newObj[k] = data[k];
if (k === trigChild) {
newObj[newAttribute] = newValue;
}
});
return newObj;
})(myObj, "child3", "CHILD", "VALUE");
document.getElementById("result").innerHTML = JSON.stringify(a);
<p id="result"></p>
We have object type variable in Jquery:
var obj = *{"1234" : "xx", "4321" : "yy", "5555" : "hh", "2321" : "aa" };*
Lets say that I want to delete every property from property name "5555" to the end of the object(that means that I want to delete obj['5555'] and delete obj['2321'] ).
I am interested in smartest way, trough loop, to do that.
In array I would use splice(2, arr.length) but I am confused.
There's no guarantee as to the order of an object's properties. When pasting your example object in my console, Here's what I saw:
> obj = {"1234" : "xx", "4321" : "yy", "5555" : "hh", "2321" : "aa" }
Object {1234: "xx", 2321: "aa", 4321: "yy", 5555: "hh"}
As you can see, chrome ordered the properties in ascending order, like it would an array. Who knows, but maybe IE doesn't do this... Maybe some obscure browser would order the properties in descending order... There's no way of knowing what the actual object will look like, so perhaps have a rethink.
If all your properties are, essentially numeric, there's nothing wrong with using an array, in JS, the Array prototype is nothing but an augmented Object:
obj = [];
obj[1234] = 'xx';
obj[2321] = 'aa';
obj[5555] = 'hh';
The numeric indexes are coerced to strings internally anyway (because Array's are objects), so JS isn't going to create endless empty indexes for you, it resolves obj[200] just like it would resolve objectLiteral.undefinedProperty: scan instance, then prototypechain. If the requested property wasn't found, return undefined.
They're added as you go along, yet here are 2 ways:
//Assume simpel object (non-nested)
var newObj = JSON.parse(JSON.stringify(obj).replace(/\{|,\s*"5{4}"\s*:.+$/,'}'));
This, I think, is the easiest way, but not very reliable. The most "tried and tested" apprach is:
var unset = false;
for (var prop in obj)
{
if (obj.hasOwnProperty(prop))
{
unset = unset || !!(prop === '5555');
if (unset === true)
{
delete(obj[prop]);
}
}
}
The last approach creates an array, containing all keys, which you can iterate over, and delete the properties that way. It's here for completeness' sake only: I wouldn't use it, though, simply because it requires a browsers that supports the ES5 spec (not all browsers do, sadly), and there's no real advantage over the code above:
var keys = Object.keys(obj).sort(),//call sort to assure ascending order
toDelete = keys.splice(keys.indexOf('5555'), keys.length).sort();
for(var i=0;i<toDelete.length;i++)
{
delete obj[toDelete[i]];
}
Push the obj to be searched and the value to be found into a function that returns a new object with only those properties up to the value you specified.
function returnNewobj(obj, value) {
var newObj = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
if (prop === value) return newObj;
newObj[prop] = obj[prop];
}
}
return newObj;
}
Edit: probably not necessary, but I added the hasOwnProperty line to be on the safe side.
Edit2: It's worth pointing out that new properties are added to objects in alphanumerical order, not to the end of objects like elements are added to arrays. So don't get caught out by that.
I would recommend you to get the index of the element from which you want to start deleting elements and then looping throw the object deleting the elements with a higher index.
You might want to create a function to make it more similar to splice i you prefer.
Find the element you are looking for and set that particular element and any element after that to null.
Its very tricky to delete property name however property value can be made null or undefined but removing property is difficult but you can do one thing can copy the required properties in new object its a workaround though here is a sample fiddle i use this often in this kind of situation
objCopyTo[strToPropertyName] = objCopyFrom[strPropertyName];
here is the fiddle
I was trying to define an array (including other arrays as values) in a single javascript statement, that I can loop through to validate a form on submission.
The function I wrote to (try to) create inline arrays follows:
function arr(){
var inc;
var tempa = new Array(Math.round(arguments.length/2));
for(inc=0; inc<arguments.length; inc=inc+2) {
tempa[arguments[inc]]=arguments[inc+1];
}
return tempa;
}
This is called three times here to assign an array:
window.validArr = arr(
'f-county',arr('maxlen',10, 'minlen',1),
'f-postcode',arr('maxlen',8, 'minlen',6)
);
However in the javascript debugger the variable is empty, and the arr() function is not returning anything. Does anyone know why my expectations on what this code should do are incorrect?
(I have worked out how to create the array without this function, but I'm curious why this code doesn't work (I thought I understood javascript better than this).)
Well from what your code does, you're not really making arrays. In JavaScript, the thing that makes arrays special is the management of the numerically indexed properties. Otherwise they're just objects, so they can have other properties too, but if you're not using arrays as arrays you might as well just use objects:
function arr(){
var inc;
var tempa = {};
for(inc=0; inc<arguments.length; inc=inc+2) {
tempa[arguments[inc]]=arguments[inc+1];
}
return tempa;
}
What you're seeing from the debugger is the result of it attempting to show you your array as a real array should be shown: that is, its numerically indexed properties. If you call your "arr()" function as is and then look at (from your example) the "f-county" property of the result, you'll see something there.
Also, if you do find yourself wanting a real array, there's absolutely no point in initializing them to a particular size. Just create a new array with []:
var tempa = [];
Your code works. Just inspect your variable, and you will see that the array has the custom keys on it. If not expanded, your debugger shows you just the (numerical) indixed values in short syntax - none for you.
But, you may need to understand the difference between Arrays and Objects. An Object is just key-value-pairs (you could call it a "map"), and its prototype. An Array is a special type of object. It has special prototype methods, a length functionality and a different approach: to store index-value-pairs (even though indexes are still keys). So, you shouldn't use an Array as an associative array.
Therefore, their literal syntax differs:
var array = ["indexed with key 0", "indexed with key 1", ...];
var object = {"custom":"keyed as 'custom'", "another":"string", ...};
// but you still can add keys to array objects:
array.custom = "keyed as 'custom'";
I have a js 'associative' array, with
array['serial_number'] = 'value'
serial_number and value are strings.
e.g. array['20910930923'] = '20101102'
I sorted it by value, works fine.
Let's say I get back the object 'sorted';
Now I want to access the first KEY of the 'sorted' array.
How do I do it? I can't think I need an iteration with
for (var i in sorted)
and just stop after ther first one...
thanks
edit: just to clarify, I know that js does not support associative arrays (that's why I put it in high commas in the Title).
2021 Update
Since ES6, properties with string keys are enumerated in insertion order. Here's a nice summary. My original answer from 2010 was correct at the time and is preserved below:
Original answer
JavaScript object properties are specified to have no order, much though many people wish it were different. If you need ordering, abandon any attempt to use an object and use an Array instead, either to store name-value objects:
var nameValues = [
{name: '20910930923', value: '20101102'},
{name: 'foo', value: 'bar'}
];
... or as an ordered list of property names to use with your existing object:
var obj = {
'20910930923': '20101102',
'foo': 'bar'
};
var orderedPropertyNames = ['20910930923', 'foo'];
Try this:
// Some assoc list
var offers = {'x':{..some object...}, 'jjj':{...some other object ...}};
// First element (see attribution below)
return offers[Object.keys(offers)[0]];
// Last element (thanks to discussion on finding last element in associative array :)
return offers[Object.keys(offers)[Object.keys(offers).length - 1]];
Actually JavaScript doesn't support associative arrays, so you can't loop through it in an implied order (e.g. you can't access it via the indexer property array[0] won't access the first element in your object). The syntax is what makes it look like it does, but in reality it doesn't. So you have no "Order" to your objects.
http://www.hunlock.com/blogs/Mastering_Javascript_Arrays
Javascript does not have, and does not
support Associative Arrays. However…
All arrays in Javascript are objects
and Javascript's object syntax gives a
basic emulation of an associative
Array. For this reason the example
code above will actually work. Be
warned that this is not a real array
and it has real pitfals if you try to
use it. The 'person' element in the
example becomes part of the Array
object's properties and methods, just
like .length, .sort(), .splice(), and
all the other built-in properties and
methods.
Just thinking off the top of my head, but could you have another array with the key value pairs swapped?
So the answer would be arrayKeyValueReversed['20101102'] = '20910930923';
When you sort the array, use the first item (array[0]) as the key to get the value in the arrayKeyValueReversed.
I have a situation, where I need to create a new JavaScript object that is inherited from Array. I am using the following code:
// Create constructor function.
var SpecialArray = function () {};
// Create intermediate function to create closure upon Array's prototype.
// This prevents littering of native Array's prototype.
var ISpecialArray = function () {};
ISpecialArray.prototype = Array.prototype;
SpecialArray.prototype = new ISpecialArray();
SpecialArray.prototype.constructor = SpecialArray;
// Use Array's push() method to add two elements to the prototype itself.
SpecialArray.prototype.push('pushed proto 0', 'pushed proto 1');
// Use [] operator to add item to 4th position
SpecialArray.prototype[4] = 'direct [] proto to 4';
// Create new instance of Special Array
var x = new SpecialArray();
// Directly add items to this new instance.
x.push('pushed directly on X');
x[9] = 'direct [] to 9'
console.log(x, 'length: ' + x.length);
Quite interestingly, the [] operation seem to be useless and the console output is:
["pushed proto 0", "pushed proto 1", "pushed directly on X"] length: 3
What am I missing here?
It is not possible to subclass the Array class and use t this way.
The best solution for you is to extend just the array class and use it as it is.
There are two other options that I do not like but they exist
http://ajaxian.com/archives/another-trick-to-allow-array-subclasses
http://dean.edwards.name/weblog/2006/11/hooray/
This is one of those that always trips people up. The length property only applies to the ordered elements. You can't extend an array then insert an arbitrary non-sequitous key and expect it to work. This is because the relationship between the length property and the array contents is broken once you extend the array. Pointy's link above does a very good job of explaining this in more detail.
To prove this add this to the end of your example:
console.log(x[4]);
As you can see your entry is present and correct, it's just not part of the ordered array.
Like everything else in javascript the Array object is just a Associative Array with string keys. Non numerical, non sequitous keys are hidden to fool you into thinking it's a 'proper' numerically indexed array.
This strange mixed design of the Array object does mean you can do some strange and wonderful things like storing ordered and unordered information in the same object. I'm not saying this is a good idea, I'm just saying it's possible.
As you will have noticed by now when iterating structures like this the non sequitous keys don't appear which makes sense for the general use case of arrays for ordered information. It's less useful, or in fact useless when you want to get keyed info. I would venture that if ordering is unimportant you should use an object not an array. If you need both ordered and unordered store an array as a property in an object.
The best way I have found to create a child prototype of an "Array" is to not make a child prototype of "Array" but rather create a child of an "Array-Like" prototype. There are many prototypes floating around that attempt to mimic the properties of an "Array" while still being able to "inherit" from it, the best one I've found is Collection because it preserves the ability to use brackets []. The major downfall is that it doesn't work well with non-numeric keys (i.e. myArray["foo"] = "bar") but if you're only using numeric keys it works great.
You can extend this prototype like this:
http://codepen.io/dustinpoissant/pen/AXbjxm?editors=0011
var MySubArray = function(){
Collection.apply(this, arguments);
this.myCustomMethod = function(){
console.log("The second item is "+this[1]);
};
};
MySubArray.prototype = Object.create(Collection.prototype);
var msa = new MySubArray("Hello", "World");
msa[2] = "Third Item";
console.log(msa);
msa.myCustomMethod();