How to list the properties of a JavaScript object? - javascript

Say I create an object thus:
var myObject =
{"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
What is the best way to retrieve a list of the property names? i.e. I would like to end up with some variable 'keys' such that:
keys == ["ircEvent", "method", "regex"]

In modern browsers (IE9+, FF4+, Chrome5+, Opera12+, Safari5+) you can use the built in Object.keys method:
var keys = Object.keys(myObject);
The above has a full polyfill but a simplified version is:
var getKeys = function(obj){
var keys = [];
for(var key in obj){
keys.push(key);
}
return keys;
}
Alternatively replace var getKeys with Object.prototype.keys to allow you to call .keys() on any object. Extending the prototype has some side effects and I wouldn't recommend doing it.

As slashnick pointed out, you can use the "for in" construct to iterate over an object for its attribute names. However you'll be iterating over all attribute names in the object's prototype chain. If you want to iterate only over the object's own attributes, you can make use of the Object#hasOwnProperty() method. Thus having the following.
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
/* useful code here */
}
}

As Sam Dutton answered, a new method for this very purpose has been introduced in ECMAScript 5th Edition. Object.keys() will do what you want and is supported in Firefox 4, Chrome 6, Safari 5 and IE 9.
You can also very easily implement the method in browsers that don't support it. However, some of the implementations out there aren't fully compatible with Internet Explorer. Here's a more compatible solution:
Object.keys = Object.keys || (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !{toString:null}.propertyIsEnumerable("toString"),
DontEnums = [
'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty',
'isPrototypeOf', 'propertyIsEnumerable', 'constructor'
],
DontEnumsLength = DontEnums.length;
return function (o) {
if (typeof o != "object" && typeof o != "function" || o === null)
throw new TypeError("Object.keys called on a non-object");
var result = [];
for (var name in o) {
if (hasOwnProperty.call(o, name))
result.push(name);
}
if (hasDontEnumBug) {
for (var i = 0; i < DontEnumsLength; i++) {
if (hasOwnProperty.call(o, DontEnums[i]))
result.push(DontEnums[i]);
}
}
return result;
};
})();
Note that the currently accepted answer doesn't include a check for hasOwnProperty() and will return properties that are inherited through the prototype chain. It also doesn't account for the famous DontEnum bug in Internet Explorer where non-enumerable properties on the prototype chain cause locally declared properties with the same name to inherit their DontEnum attribute.
Implementing Object.keys() will give you a more robust solution.
EDIT: following a recent discussion with kangax, a well-known contributor to Prototype, I implemented the workaround for the DontEnum bug based on code for his Object.forIn() function found here.

Note that Object.keys and other ECMAScript 5 methods are supported by Firefox 4, Chrome 6, Safari 5, IE 9 and above.
For example:
var o = {"foo": 1, "bar": 2};
alert(Object.keys(o));
ECMAScript 5 compatibility table
Description of new methods

Object.getOwnPropertyNames(obj)
This function also shows non-enumerable properties in addition to those shown by Object.keys(obj).
In JS, every property has a few properties, including a boolean enumerable.
In general, non-enumerable properties are more "internalish" and less often used, but it is insightful to look into them sometimes to see what is really going on.
Example:
var o = Object.create({base:0})
Object.defineProperty(o, 'yes', {enumerable: true})
Object.defineProperty(o, 'not', {enumerable: false})
console.log(Object.getOwnPropertyNames(o))
// [ 'yes', 'not' ]
console.log(Object.keys(o))
// [ 'yes' ]
for (var x in o)
console.log(x)
// yes, base
Also note how:
Object.getOwnPropertyNames and Object.keys don't go up the prototype chain to find base
for in does
More about the prototype chain here: https://stackoverflow.com/a/23877420/895245

I'm a huge fan of the dump function.
Ajaxian » JavaScript Variable Dump in Coldfusion
Download the dump function

Could do it with jQuery as follows:
var objectKeys = $.map(object, function(value, key) {
return key;
});

if you are trying to get the elements only but not the functions then this code can help you
this.getKeys = function() {
var keys = new Array();
for(var key in this) {
if( typeof this[key] !== 'function') {
keys.push(key);
}
}
return keys;
}
this is part of my implementation of the HashMap and I only want the keys, "this" is the hashmap object that contains the keys

This will work in most browsers, even in IE8 , and no libraries of any sort are required. var i is your key.
var myJSONObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
var keys=[];
for (var i in myJSONObject ) { keys.push(i); }
alert(keys);

Use Reflect.ownKeys()
var obj = {a: 1, b: 2, c: 3};
Reflect.ownKeys(obj) // ["a", "b", "c"]
Object.keys and Object.getOwnPropertyNames cannot get non-enumerable properties. It's working even for non-enumerable properties.
var obj = {a: 1, b: 2, c: 3};
obj[Symbol()] = 4;
Reflect.ownKeys(obj) // ["a", "b", "c", Symbol()]

Under browsers supporting js 1.8:
[i for(i in obj)]

Mozilla has full implementation details on how to do it in a browser where it isn't supported, if that helps:
if (!Object.keys) {
Object.keys = (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function (obj) {
if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
var result = [];
for (var prop in obj) {
if (hasOwnProperty.call(obj, prop)) result.push(prop);
}
if (hasDontEnumBug) {
for (var i=0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
}
}
return result;
};
})();
}
You could include it however you'd like, but possibly in some kind of extensions.js file at the top of your script stack.

With ES6 and later (ECMAScript 2015), you can get all properties like this:
let keys = Object.keys(myObject);
And if you wanna list out all values:
let values = Object.keys(myObject).map(key => myObject[key]);

Building on the accepted answer.
If the Object has properties you want to call say .properties() try!
var keys = Object.keys(myJSONObject);
for (var j=0; j < keys.length; j++) {
Object[keys[j]].properties();
}

Since I use underscore.js in almost every project, I would use the keys function:
var obj = {name: 'gach', hello: 'world'};
console.log(_.keys(obj));
The output of that will be:
['name', 'hello']

IE does not support for(i in obj) for native properties. Here is a list of all the props I could find.
It seems stackoverflow does some stupid filtering.
The list is available at the bottom of this google group post:-
https://groups.google.com/group/hackvertor/browse_thread/thread/a9ba81ca642a63e0

A lot of answers here... This is my 2 cents.
I needed something to print out all the JSON attributes, even the ones with sub-objects or arrays (parent name included).
So - For this JSON:
mylittleJson = {
"one": "blah",
"two": {
"twoone": "",
"twotwo": "",
"twothree": ['blah', 'blah']
},
"three": ""
}
It'd print this:
.one
.two.twoone
.two.twotwo
.two.twothree
.three
Here is function
function listatts(parent, currentJson){
var attList = []
if (typeof currentJson !== 'object' || currentJson == undefined || currentJson.length > 0) {
return
}
for(var attributename in currentJson){
if (Object.prototype.hasOwnProperty.call(currentJson, attributename)) {
childAtts = listatts(parent + "." + attributename, currentJson[attributename])
if (childAtts != undefined && childAtts.length > 0)
attList = [...attList, ...childAtts]
else
attList.push(parent + "." + attributename)
}
}
return attList
}
mylittleJson = {
"one": "blah",
"two": {
"twoone": "",
"twotwo": "",
"twothree": ['blah', 'blah']
},
"three": ""
}
console.log(listatts("", mylittleJson));
Hope it helps too.

The solution work on my cases and cross-browser:
var getKeys = function(obj) {
var type = typeof obj;
var isObjectType = type === 'function' || type === 'object' || !!obj;
// 1
if(isObjectType) {
return Object.keys(obj);
}
// 2
var keys = [];
for(var i in obj) {
if(obj.hasOwnProperty(i)) {
keys.push(i)
}
}
if(keys.length) {
return keys;
}
// 3 - bug for ie9 <
var hasEnumbug = !{toString: null}.propertyIsEnumerable('toString');
if(hasEnumbug) {
var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
var nonEnumIdx = nonEnumerableProps.length;
while (nonEnumIdx--) {
var prop = nonEnumerableProps[nonEnumIdx];
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
keys.push(prop);
}
}
}
return keys;
};

Related

How to slice() return values from JSON API [duplicate]

var obj = {
name: "Simon",
age: "20",
clothing: {
style: "simple",
hipster: false
}
}
for(var propt in obj){
console.log(propt + ': ' + obj[propt]);
}
How does the variable propt represent the properties of the object? It's not a built-in method or property. Why does it come up with every property in the object?
Iterating over properties requires this additional hasOwnProperty check:
for (var prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
// do stuff
}
}
It's necessary because an object's prototype contains additional properties for the object which are technically part of the object. These additional properties are inherited from the base object class, but are still properties of obj.
hasOwnProperty simply checks to see if this is a property specific to this class, and not one inherited from the base class.
It's also possible to call hasOwnProperty through the object itself:
if (obj.hasOwnProperty(prop)) {
// do stuff
}
But this will fail if the object has an unrelated field with the same name:
var obj = { foo: 42, hasOwnProperty: 'lol' };
obj.hasOwnProperty('foo'); // TypeError: hasOwnProperty is not a function
That's why it's safer to call it through Object.prototype instead:
var obj = { foo: 42, hasOwnProperty: 'lol' };
Object.prototype.hasOwnProperty.call(obj, 'foo'); // true
As of JavaScript 1.8.5 you can use Object.keys(obj) to get an Array of properties defined on the object itself (the ones that return true for obj.hasOwnProperty(key)).
Object.keys(obj).forEach(function(key,index) {
// key: the name of the object key
// index: the ordinal position of the key within the object
});
This is better (and more readable) than using a for-in loop.
Its supported on these browsers:
Firefox (Gecko): 4 (2.0)
Chrome: 5
Internet Explorer: 9
See the Mozilla Developer Network Object.keys()'s reference for futher information.
Girls and guys we are in 2019 and we do not have that much time for typing... So lets do this cool new fancy ECMAScript 2016:
Object.keys(obj).forEach(e => console.log(`key=${e} value=${obj[e]}`));
In up-to-date implementations of ES, you can use Object.entries:
for (const [key, value] of Object.entries(obj)) { }
or
Object.entries(obj).forEach(([key, value]) => ...)
If you just want to iterate over the values, then use Object.values:
for (const value of Object.values(obj)) { }
or
Object.values(obj).forEach(value => ...)
It's the for...in statement (MDN, ECMAScript spec).
You can read it as "FOR every property IN the obj object, assign each property to the PROPT variable in turn".
It's just a for...in loop. Check out the documentation at Mozilla.
if (typeof obj === 'object' && obj !== null) {
Object.keys(obj).forEach(key => {
console.log("\n" + key + ": " + obj[key]);
});
}
// *** Explanation line by line ***
// Explaining the bellow line
// It checks if obj is neither null nor undefined, which means it's safe to get its keys.
// Otherwise it will give you a "TypeError: Cannot convert undefined or null to object" if obj is null or undefined.
// NOTE 1: You can use Object.hasOwnProperty() instead of Object.keys(obj).length
// NOTE 2: No need to check if obj is an array because it will work just fine.
// NOTE 3: No need to check if obj is a string because it will not pass the 'if typeof obj is Object' statement.
// NOTE 4: No need to check if Obj is undefined because it will not pass the 'if type obj is Object' statement either.
if (typeof obj === 'object' && obj !== null) {
// Explaining the bellow line
// Just like in the previous line, this returns an array with
// all keys in obj (because if code execution got here, it means
// obj has keys.)
// Then just invoke built-in javascript forEach() to loop
// over each key in returned array and calls a call back function
// on each array element (key), using ES6 arrow function (=>)
// Or you can just use a normal function ((key) { blah blah }).
Object.keys(obj).forEach(key => {
// The bellow line prints out all keys with their
// respective value in obj.
// key comes from the returned array in Object.keys(obj)
// obj[key] returns the value of key in obj
console.log("\n" + key + ": " + obj[key]);
});
}
If your environment supports ES2017 then I would recommend Object.entries:
Object.entries(obj).forEach(([key, value]) => {
console.log(`${key} ${value}`);
});
As shown in Mozillas Object.entries() documentation:
The Object.entries() method returns an array of a given object's own
enumerable property [key, value] pairs, 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).
Basically with Object.entries we can forgo the following extra step that is required with the older for...in loop:
// This step is not necessary with Object.entries
if (object.hasOwnProperty(property)) {
// do stuff
}
Dominik's answer is perfect, I just prefer to do it that way, as it's cleaner to read:
for (var property in obj) {
if (!obj.hasOwnProperty(property)) continue;
// Do stuff...
}
jquery allows you to do this now:
$.each( obj, function( key, value ) {
alert( key + ": " + value );
});
The for...in loop represents each property in an object because it is just like a for loop. You defined propt in the for...in loop by doing:
for(var propt in obj){
alert(propt + ': ' + obj[propt]);
}
A for...in loop iterates through the enumerable properties of an object. Whichever variable you define, or put in the for...in loop, changes each time it goes to the next property it iterates. The variable in the for...in loop iterates through the keys, but the value of it is the key's value. For example:
for(var propt in obj) {
console.log(propt);//logs name
console.log(obj[propt]);//logs "Simon"
}
You can see how the variable differs from the variable's value. In contrast, a for...of loop does the opposite.
I hope this helps.
To add ES2015's usage of Reflect.ownKeys(obj) and also iterating over the properties via an iterator.
For example:
let obj = { a: 'Carrot', b: 'Potato', Car: { doors: 4 } };
can be iterated over by
// logs each key
Reflect.ownKeys(obj).forEach(key => console.log(key));
If you would like to iterate directly over the values of the keys of an object, you can define an iterator, just like JavaScipts's default iterators for strings, arrays, typed arrays, Map and Set.
JS will attempt to iterate via the default iterator property, which must be defined as Symbol.iterator.
If you want to be able to iterate over all objects you can add it as a prototype of Object:
Object.prototype[Symbol.iterator] = function*() {
for(p of Reflect.ownKeys(this)){ yield this[p]; }
}
This would enable you to iterate over the values of an object with a for...of loop, for example:
for(val of obj) { console.log('Value is:' + val ) }
Caution: As of writing this answer (June 2018) all other browsers, but IE, support generators and for...of iteration via Symbol.iterator
The above answers are a bit annoying because they don't explain what you do inside the for loop after you ensure it's an object: YOU DON'T ACCESS IT DIRECTLY! You are actually only delivered the KEY that you need to apply to the OBJ:
var obj = {
a: "foo",
b: "bar",
c: "foobar"
};
// We need to iterate the string keys (not the objects)
for(var someKey in obj)
{
// We check if this key exists in the obj
if (obj.hasOwnProperty(someKey))
{
// someKey is only the KEY (string)! Use it to get the obj:
var myActualPropFromObj = obj[someKey]; // Since dynamic, use [] since the key isn't literally named "someKey"
// NOW you can treat it like an obj
var shouldBeBar = myActualPropFromObj.b;
}
}
This is all ECMA5 safe. Even works in the lame JS versions like Rhino ;)
let obj = {"a": 3, "b": 2, "6": "a"}
Object.keys(obj).forEach((item) => {console.log("item", obj[item])})
// a
// 3
// 2
You can access the nested properties of the object using the for...in and forEach loop.
for...in:
for (const key in info) {
console.log(info[key]);
}
forEach:
Object.keys(info).forEach(function(prop) {
console.log(info[prop]);
// cities: Array[3], continent: "North America", images: Array[3], name: "Canada"
// "prop" is the property name
// "data[prop]" is the property value
});
You can use Lodash. The documentation
var obj = {a: 1, b: 2, c: 3};
_.keys(obj).forEach(function (key) {
...
});
Object.keys(obj).forEach(key =>
console.log(`key=${key} value=${obj[key]}`)
);
Nowadays you can convert a standard JS object into an iterable object just by adding a Symbol.iterator method. Then you can use a for of loop and acceess its values directly or even can use a spread operator on the object too. Cool. Let's see how we can make it:
var o = {a:1,b:2,c:3},
a = [];
o[Symbol.iterator] = function*(){
var ok = Object.keys(this);
i = 0;
while (i < ok.length) yield this[ok[i++]];
};
for (var value of o) console.log(value);
// or you can even do like
a = [...o];
console.log(a);
Your for loop is iterating over all of the properties of the object obj. propt is defined in the first line of your for loop. It is a string that is a name of a property of the obj object. In the first iteration of the loop, propt would be "name".
Objects in JavaScript are collections of properties and can therefore be looped in a for each statement.
You should think of obj as an key value collection.
If running Node I'd recommend:
Object.keys(obj).forEach((key, index) => {
console.log(key);
});
While the top-rated answer is correct, here is an alternate use case i.e if you are iterating over an object and want to create an array in the end. Use .map instead of forEach
const newObj = Object.keys(obj).map(el => {
//ell will hold keys
// Getting the value of the keys should be as simple as obj[el]
})
I want to add to the answers above, because you might have different intentions from Javascript. A JSON object and a Javascript object are different things, and you might want to iterate through the properties of a JSON object using the solutions proposed above, and then be surprised.
Suppose that you have a JSON object like:
var example = {
"prop1": "value1",
"prop2": [ "value2_0", "value2_1"],
"prop3": {
"prop3_1": "value3_1"
}
}
The wrong way to iterate through its 'properties':
function recursivelyIterateProperties(jsonObject) {
for (var prop in Object.keys(example)) {
console.log(prop);
recursivelyIterateProperties(jsonObject[prop]);
}
}
You might be surprised of seeing the console logging 0, 1, etc. when iterating through the properties of prop1 and prop2 and of prop3_1. Those objects are sequences, and the indexes of a sequence are properties of that object in Javascript.
A better way to recursively iterate through a JSON object properties would be to first check if that object is a sequence or not:
function recursivelyIterateProperties(jsonObject) {
for (var prop in Object.keys(example)) {
console.log(prop);
if (!(typeof(jsonObject[prop]) === 'string')
&& !(jsonObject[prop] instanceof Array)) {
recursivelyIterateProperties(jsonObject[prop]);
}
}
}
What for..in loop does is that it creates a new variable (var someVariable) and then stores each property of the given object in this new variable(someVariable) one by one. Therefore if you use block {}, you can iterate. Consider the following example.
var obj = {
name:'raman',
hobby:'coding',
planet:'earth'
};
for(var someVariable in obj) {
//do nothing..
}
console.log(someVariable); // outputs planet
Here I am iterating each node and creating meaningful node names. If you notice, instanceOf Array and instanceOf Object pretty much does the same thing (in my application, i am giving different logic though)
function iterate(obj,parent_node) {
parent_node = parent_node || '';
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
var node = parent_node + "/" + property;
if(obj[property] instanceof Array) {
//console.log('array: ' + node + ":" + obj[property]);
iterate(obj[property],node)
} else if(obj[property] instanceof Object){
//console.log('Object: ' + node + ":" + obj[property]);
iterate(obj[property],node)
}
else {
console.log(node + ":" + obj[property]);
}
}
}
}
note - I am inspired by Ondrej Svejdar's answer. But this solution has better performance and less ambiguous
Also adding the recursive way:
function iterate(obj) {
// watch for objects we've already iterated so we won't end in endless cycle
// for cases like var foo = {}; foo.bar = foo; iterate(foo);
var walked = [];
var stack = [{obj: obj, stack: ''}];
while(stack.length > 0)
{
var item = stack.pop();
var obj = item.obj;
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
// check if we haven't iterated through the reference yet
var alreadyFound = false;
for(var i = 0; i < walked.length; i++)
{
if (walked[i] === obj[property])
{
alreadyFound = true;
break;
}
}
// new object reference
if (!alreadyFound)
{
walked.push(obj[property]);
stack.push({obj: obj[property], stack: item.stack + '.' + property});
}
}
else
{
console.log(item.stack + '.' + property + "=" + obj[property]);
}
}
}
}
}
Usage:
iterate({ foo: "foo", bar: { foo: "foo"} });
You basically want to loop through each property in the object.
JSFiddle
var Dictionary = {
If: {
you: {
can: '',
make: ''
},
sense: ''
},
of: {
the: {
sentence: {
it: '',
worked: ''
}
}
}
};
function Iterate(obj) {
for (prop in obj) {
if (obj.hasOwnProperty(prop) && isNaN(prop)) {
console.log(prop + ': ' + obj[prop]);
Iterate(obj[prop]);
}
}
}
Iterate(Dictionary);
To further refine the accepted answer it's worth noting that if you instantiate the object with a var object = Object.create(null) then object.hasOwnProperty(property) will trigger a TypeError. So to be on the safe side, you'd need to call it from the prototype like this:
for (var property in object) {
if (Object.prototype.hasOwnProperty.call(object, property)) {
// do stuff
}
}
Check type
You can check how propt represent object propertis by
typeof propt
to discover that it's just a string (name of property). It come up with every property in the object due the way of how for-in js "build-in" loop works.
var obj = {
name: "Simon",
age: "20",
clothing: {
style: "simple",
hipster: false
}
}
for(var propt in obj){
console.log(typeof propt, propt + ': ' + obj[propt]);
}
If you just want to iterate to map property values then lodash has _.mapValues
const obj = {
a: 2,
b: 3
}
const res = _.mapValues(obj, v => v * 2)
console.log(res)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.21/lodash.min.js"></script>

How to get length of array in JavaScript [duplicate]

I have a JavaScript object. Is there a built-in or accepted best practice way to get the length of this object?
const myObject = new Object();
myObject["firstname"] = "Gareth";
myObject["lastname"] = "Simpson";
myObject["age"] = 21;
Updated answer
Here's an update as of 2016 and widespread deployment of ES5 and beyond. For IE9+ and all other modern ES5+ capable browsers, you can use Object.keys() so the above code just becomes:
var size = Object.keys(myObj).length;
This doesn't have to modify any existing prototype since Object.keys() is now built-in.
Edit: Objects can have symbolic properties that can not be returned via Object.key method. So the answer would be incomplete without mentioning them.
Symbol type was added to the language to create unique identifiers for object properties. The main benefit of the Symbol type is the prevention of overwrites.
Object.keys or Object.getOwnPropertyNames does not work for symbolic properties. To return them you need to use Object.getOwnPropertySymbols.
var person = {
[Symbol('name')]: 'John Doe',
[Symbol('age')]: 33,
"occupation": "Programmer"
};
const propOwn = Object.getOwnPropertyNames(person);
console.log(propOwn.length); // 1
let propSymb = Object.getOwnPropertySymbols(person);
console.log(propSymb.length); // 2
Older answer
The most robust answer (i.e. that captures the intent of what you're trying to do while causing the fewest bugs) would be:
Object.size = function(obj) {
var size = 0,
key;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
};
// Get the size of an object
const myObj = {}
var size = Object.size(myObj);
There's a sort of convention in JavaScript that you don't add things to Object.prototype, because it can break enumerations in various libraries. Adding methods to Object is usually safe, though.
If you know you don't have to worry about hasOwnProperty checks, you can use the Object.keys() method in this way:
Object.keys(myArray).length
Updated: If you're using Underscore.js (recommended, it's lightweight!), then you can just do
_.size({one : 1, two : 2, three : 3});
=> 3
If not, and you don't want to mess around with Object properties for whatever reason, and are already using jQuery, a plugin is equally accessible:
$.assocArraySize = function(obj) {
// http://stackoverflow.com/a/6700/11236
var size = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
};
Here's the most cross-browser solution.
This is better than the accepted answer because it uses native Object.keys if exists.
Thus, it is the fastest for all modern browsers.
if (!Object.keys) {
Object.keys = function (obj) {
var arr = [],
key;
for (key in obj) {
if (obj.hasOwnProperty(key)) {
arr.push(key);
}
}
return arr;
};
}
Object.keys(obj).length;
Simply use this to get the length:
Object.keys(myObject).length
I'm not a JavaScript expert, but it looks like you would have to loop through the elements and count them since Object doesn't have a length method:
var element_count = 0;
for (e in myArray) { if (myArray.hasOwnProperty(e)) element_count++; }
#palmsey: In fairness to the OP, the JavaScript documentation actually explicitly refer to using variables of type Object in this manner as "associative arrays".
This method gets all your object's property names in an array, so you can get the length of that array which is equal to your object's keys' length.
Object.getOwnPropertyNames({"hi":"Hi","msg":"Message"}).length; // => 2
To not mess with the prototype or other code, you could build and extend your own object:
function Hash(){
var length=0;
this.add = function(key, val){
if(this[key] == undefined)
{
length++;
}
this[key]=val;
};
this.length = function(){
return length;
};
}
myArray = new Hash();
myArray.add("lastname", "Simpson");
myArray.add("age", 21);
alert(myArray.length()); // will alert 2
If you always use the add method, the length property will be correct. If you're worried that you or others forget about using it, you could add the property counter which the others have posted to the length method, too.
Of course, you could always overwrite the methods. But even if you do, your code would probably fail noticeably, making it easy to debug. ;)
We can find the length of Object by using:
const myObject = {};
console.log(Object.values(myObject).length);
Here's how and don't forget to check that the property is not on the prototype chain:
var element_count = 0;
for(var e in myArray)
if(myArray.hasOwnProperty(e))
element_count++;
Here is a completely different solution that will only work in more modern browsers (Internet Explorer 9+, Chrome, Firefox 4+, Opera 11.60+, and Safari 5.1+)
See this jsFiddle.
Setup your associative array class
/**
* #constructor
*/
AssociativeArray = function () {};
// Make the length property work
Object.defineProperty(AssociativeArray.prototype, "length", {
get: function () {
var count = 0;
for (var key in this) {
if (this.hasOwnProperty(key))
count++;
}
return count;
}
});
Now you can use this code as follows...
var a1 = new AssociativeArray();
a1["prop1"] = "test";
a1["prop2"] = 1234;
a1["prop3"] = "something else";
alert("Length of array is " + a1.length);
If you need an associative data structure that exposes its size, better use a map instead of an object.
const myMap = new Map();
myMap.set("firstname", "Gareth");
myMap.set("lastname", "Simpson");
myMap.set("age", 21);
console.log(myMap.size); // 3
Use Object.keys(myObject).length to get the length of object/array
var myObject = new Object();
myObject["firstname"] = "Gareth";
myObject["lastname"] = "Simpson";
myObject["age"] = 21;
console.log(Object.keys(myObject).length); //3
Use:
var myArray = new Object();
myArray["firstname"] = "Gareth";
myArray["lastname"] = "Simpson";
myArray["age"] = 21;
obj = Object.keys(myArray).length;
console.log(obj)
<script>
myObj = {"key1" : "Hello", "key2" : "Goodbye"};
var size = Object.keys(myObj).length;
console.log(size);
</script>
<p id="myObj">The number of <b>keys</b> in <b>myObj</b> are: <script>document.write(size)</script></p>
This works for me:
var size = Object.keys(myObj).length;
For some cases it is better to just store the size in a separate variable. Especially, if you're adding to the array by one element in one place and can easily increment the size. It would obviously work much faster if you need to check the size often.
The simplest way is like this:
Object.keys(myobject).length
Where myobject is the object of what you want the length of.
#palmsey: In fairness to the OP, the JavaScript documentation actually explicitly refer to using variables of type Object in this manner as "associative arrays".
And in fairness to #palmsey he was quite correct. They aren't associative arrays; they're definitely objects :) - doing the job of an associative array. But as regards to the wider point, you definitely seem to have the right of it according to this rather fine article I found:
JavaScript “Associative Arrays” Considered Harmful
But according to all this, the accepted answer itself is bad practice?
Specify a prototype size() function for Object
If anything else has been added to Object .prototype, then the suggested code will fail:
<script type="text/javascript">
Object.prototype.size = function () {
var len = this.length ? --this.length : -1;
for (var k in this)
len++;
return len;
}
Object.prototype.size2 = function () {
var len = this.length ? --this.length : -1;
for (var k in this)
len++;
return len;
}
var myArray = new Object();
myArray["firstname"] = "Gareth";
myArray["lastname"] = "Simpson";
myArray["age"] = 21;
alert("age is " + myArray["age"]);
alert("length is " + myArray.size());
</script>
I don't think that answer should be the accepted one as it can't be trusted to work if you have any other code running in the same execution context. To do it in a robust fashion, surely you would need to define the size method within myArray and check for the type of the members as you iterate through them.
If we have the hash
hash = {"a" : "b", "c": "d"};
we can get the length using the length of the keys which is the length of the hash:
keys(hash).length
Using the Object.entries method to get length is one way of achieving it
const objectLength = obj => Object.entries(obj).length;
const person = {
id: 1,
name: 'John',
age: 30
}
const car = {
type: 2,
color: 'red',
}
console.log(objectLength(person)); // 3
console.log(objectLength(car)); // 2
var myObject = new Object();
myObject["firstname"] = "Gareth";
myObject["lastname"] = "Simpson";
myObject["age"] = 21;
Object.values(myObject).length
Object.entries(myObject).length
Object.keys(myObject).length
What about something like this --
function keyValuePairs() {
this.length = 0;
function add(key, value) { this[key] = value; this.length++; }
function remove(key) { if (this.hasOwnProperty(key)) { delete this[key]; this.length--; }}
}
If you are using AngularJS 1.x you can do things the AngularJS way by creating a filter and using the code from any of the other examples such as the following:
// Count the elements in an object
app.filter('lengthOfObject', function() {
return function( obj ) {
var size = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
}
})
Usage
In your controller:
$scope.filterResult = $filter('lengthOfObject')($scope.object)
Or in your view:
<any ng-expression="object | lengthOfObject"></any>
const myObject = new Object();
myObject["firstname"] = "Gareth";
myObject["lastname"] = "Simpson";
myObject["age"] = 21;
console.log(Object.keys(myObject).length)
// o/p 3
A variation on some of the above is:
var objLength = function(obj){
var key,len=0;
for(key in obj){
len += Number( obj.hasOwnProperty(key) );
}
return len;
};
It is a bit more elegant way to integrate hasOwnProp.
If you don't care about supporting Internet Explorer 8 or lower, you can easily get the number of properties in an object by applying the following two steps:
Run either Object.keys() to get an array that contains the names of only those properties that are enumerable or Object.getOwnPropertyNames() if you want to also include the names of properties that are not enumerable.
Get the .length property of that array.
If you need to do this more than once, you could wrap this logic in a function:
function size(obj, enumerablesOnly) {
return enumerablesOnly === false ?
Object.getOwnPropertyNames(obj).length :
Object.keys(obj).length;
}
How to use this particular function:
var myObj = Object.create({}, {
getFoo: {},
setFoo: {}
});
myObj.Foo = 12;
var myArr = [1,2,5,4,8,15];
console.log(size(myObj)); // Output : 1
console.log(size(myObj, true)); // Output : 1
console.log(size(myObj, false)); // Output : 3
console.log(size(myArr)); // Output : 6
console.log(size(myArr, true)); // Output : 6
console.log(size(myArr, false)); // Output : 7
See also this Fiddle for a demo.
Here's a different version of James Cogan's answer. Instead of passing an argument, just prototype out the Object class and make the code cleaner.
Object.prototype.size = function () {
var size = 0,
key;
for (key in this) {
if (this.hasOwnProperty(key)) size++;
}
return size;
};
var x = {
one: 1,
two: 2,
three: 3
};
x.size() === 3;
jsfiddle example: http://jsfiddle.net/qar4j/1/
You can always do Object.getOwnPropertyNames(myObject).length to get the same result as [].length would give for normal array.
You can simply use Object.keys(obj).length on any object to get its length. Object.keys returns an array containing all of the object keys (properties) which can come in handy for finding the length of that object using the length of the corresponding array. You can even write a function for this. Let's get creative and write a method for it as well (along with a more convienient getter property):
function objLength(obj)
{
return Object.keys(obj).length;
}
console.log(objLength({a:1, b:"summit", c:"nonsense"}));
// Works perfectly fine
var obj = new Object();
obj['fish'] = 30;
obj['nullified content'] = null;
console.log(objLength(obj));
// It also works your way, which is creating it using the Object constructor
Object.prototype.getLength = function() {
return Object.keys(this).length;
}
console.log(obj.getLength());
// You can also write it as a method, which is more efficient as done so above
Object.defineProperty(Object.prototype, "length", {get:function(){
return Object.keys(this).length;
}});
console.log(obj.length);
// probably the most effictive approach is done so and demonstrated above which sets a getter property called "length" for objects which returns the equivalent value of getLength(this) or this.getLength()
A nice way to achieve this (Internet Explorer 9+ only) is to define a magic getter on the length property:
Object.defineProperty(Object.prototype, "length", {
get: function () {
return Object.keys(this).length;
}
});
And you can just use it like so:
var myObj = { 'key': 'value' };
myObj.length;
It would give 1.

How can I get the key of my object?

I have the following object:
var text = { 'one' : 1, 'two' : 2, 'three' : 3};
I want to write the key 'one' with console.log(). How can I do it?
try:
var text = { 'one' : 1, 'two' : 2, 'three' : 3};
for (var i in text){
console.log(i);
}
You need to use the keys() function, as epoch pointed out in the comment section.
For example :
console.log(Object.keys(text));
Can print one two three; If you want to be certain about your order, you'll have to use an array instead of an object, as properties in objects are not ordered.
Be careful, in older browers you'll have to define your own fucntion of keys, as explained in the doc i linked above, like so :
if (!Object.keys) {
Object.keys = (function() {
'use strict';
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function(obj) {
if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
throw new TypeError('Object.keys called on non-object');
}
var result = [], prop, i;
for (prop in obj) {
if (hasOwnProperty.call(obj, prop)) {
result.push(prop);
}
}
if (hasDontEnumBug) {
for (i = 0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) {
result.push(dontEnums[i]);
}
}
}
return result;
};
}());
}
Your question is kind of vague.
What exactly is it that you are trying to achieve?
Do you just want to log the first prop in your obj?
If so, that would not be a good idea because the order of properties in an object is not guaranteed. The order might even change over time, depending on what happens to the object.
You could in fact use the Object.keys() method, which would do a for in on all enumerable properties of the object, but this would give you all properties and since you asked for a specific property to be logged to the console, this leads me to the conclusion that you probably are more interested in how to check for the existence of a property.
To make a long story short, if you really want to log a specific property you could just do
(text.hasOwnProperty('one')) ? console.log('one') : console.log('"one" does not exists');

How to Deep clone in javascript

How do you deep clone a JavaScript object?
I know there are various functions based on frameworks like JSON.parse(JSON.stringify(o)) and $.extend(true, {}, o) but I don't want to use a framework like that.
What is the most elegant or efficient way to create a deep clone.
We do care about edge cases like cloning array's. Not breaking prototype chains, dealing with self reference.
We don't care about supporting copying of DOM objects and like because .cloneNode exists for that reason.
As I mainly want to use deep clones in node.js using ES5 features of the V8 engine is acceptable.
[Edit]
Before anyone suggests let me mention there is a distinct difference between creating a copy by prototypically inheriting from the object and cloning it. The former makes a mess of the prototype chain.
[Further Edit]
After reading your answer I came to the annoying discovery that cloning entire objects is a very dangerous and difficult game. Take for example the following closure based object
var o = (function() {
var magic = 42;
var magicContainer = function() {
this.get = function() { return magic; };
this.set = function(i) { magic = i; };
}
return new magicContainer;
}());
var n = clone(o); // how to implement clone to support closures
Is there any way to write a clone function that clones the object, has the same state at time of cloning but cannot alter the state of o without writing a JS parser in JS.
There should be no real world need for such a function anymore. This is mere academic interest.
Very simple way, maybe too simple:
var cloned = JSON.parse(JSON.stringify(objectToClone));
It really depends what you would like to clone. Is this a truly JSON object or just any object in JavaScript? If you would like to do any clone, it might get you into some trouble. Which trouble? I will explain it below, but first, a code example which clones object literals, any primitives, arrays and DOM nodes.
function clone(item) {
if (!item) { return item; } // null, undefined values check
var types = [ Number, String, Boolean ],
result;
// normalizing primitives if someone did new String('aaa'), or new Number('444');
types.forEach(function(type) {
if (item instanceof type) {
result = type( item );
}
});
if (typeof result == "undefined") {
if (Object.prototype.toString.call( item ) === "[object Array]") {
result = [];
item.forEach(function(child, index, array) {
result[index] = clone( child );
});
} else if (typeof item == "object") {
// testing that this is DOM
if (item.nodeType && typeof item.cloneNode == "function") {
result = item.cloneNode( true );
} else if (!item.prototype) { // check that this is a literal
if (item instanceof Date) {
result = new Date(item);
} else {
// it is an object literal
result = {};
for (var i in item) {
result[i] = clone( item[i] );
}
}
} else {
// depending what you would like here,
// just keep the reference, or create new object
if (false && item.constructor) {
// would not advice to do that, reason? Read below
result = new item.constructor();
} else {
result = item;
}
}
} else {
result = item;
}
}
return result;
}
var copy = clone({
one : {
'one-one' : new String("hello"),
'one-two' : [
"one", "two", true, "four"
]
},
two : document.createElement("div"),
three : [
{
name : "three-one",
number : new Number("100"),
obj : new function() {
this.name = "Object test";
}
}
]
})
And now, let's talk about problems you might get when start cloning REAL objects. I'm talking now, about objects which you create by doing something like
var User = function(){}
var newuser = new User();
Of course you can clone them, it's not a problem, every object expose constructor property, and you can use it to clone objects, but it will not always work. You also can do simple for in on this objects, but it goes to the same direction - trouble. I have also included clone functionality inside the code, but it's excluded by if( false ) statement.
So, why cloning can be a pain? Well, first of all, every object/instance might have some state. You never can be sure that your objects doesn't have for example an private variables, and if this is the case, by cloning object, you just break the state.
Imagine there is no state, that's fine. Then we still have another problem. Cloning via "constructor" method will give us another obstacle. It's an arguments dependency. You never can be sure, that someone who created this object, did not did, some kind of
new User({
bike : someBikeInstance
});
If this is the case, you are out of luck, someBikeInstance was probably created in some context and that context is unkown for clone method.
So what to do? You still can do for in solution, and treat such objects like normal object literals, but maybe it's an idea not to clone such objects at all, and just pass the reference of this object?
Another solution is - you could set a convention that all objects which must be cloned should implement this part by themselves and provide appropriate API method ( like cloneObject ). Something what cloneNode is doing for DOM.
You decide.
The JSON.parse(JSON.stringify()) combination to deep copy Javascript objects is an ineffective hack, as it was meant for JSON data. It does not support values of undefined or function () {}, and will simply ignore them (or null them) when "stringifying" (marshalling) the Javascript object into JSON.
A better solution is to use a deep copy function. The function below deep copies objects, and does not require a 3rd party library (jQuery, LoDash, etc).
function copy(aObject) {
// Prevent undefined objects
// if (!aObject) return aObject;
let bObject = Array.isArray(aObject) ? [] : {};
let value;
for (const key in aObject) {
// Prevent self-references to parent object
// if (Object.is(aObject[key], aObject)) continue;
value = aObject[key];
bObject[key] = (typeof value === "object") ? copy(value) : value;
}
return bObject;
}
Note: This code can check for simple self-references (uncomment the section // Prevent self-references to parent object), but you should also avoid creating objects with self-references when possible. Please see: https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references
There is now structuredClone in the Web API which also works with circular references.
Previous answer
Here is an ES6 function that will also work for objects with cyclic references:
function deepClone(obj, hash = new WeakMap()) {
if (Object(obj) !== obj) return obj; // primitives
if (hash.has(obj)) return hash.get(obj); // cyclic reference
const result = obj instanceof Set ? new Set(obj) // See note about this!
: obj instanceof Map ? new Map(Array.from(obj, ([key, val]) =>
[key, deepClone(val, hash)]))
: obj instanceof Date ? new Date(obj)
: obj instanceof RegExp ? new RegExp(obj.source, obj.flags)
// ... add here any specific treatment for other classes ...
// and finally a catch-all:
: obj.constructor ? new obj.constructor()
: Object.create(null);
hash.set(obj, result);
return Object.assign(result, ...Object.keys(obj).map(
key => ({ [key]: deepClone(obj[key], hash) }) ));
}
// Sample data
var p = {
data: 1,
children: [{
data: 2,
parent: null
}]
};
p.children[0].parent = p;
var q = deepClone(p);
console.log(q.children[0].parent.data); // 1
A note about Sets and Maps
How to deal with the keys of Sets and Maps is debatable: those keys are often primitives (in which case there is no debate), but they can also be objects. In that case the question becomes: should those keys be cloned?
One could argue that this should be done, so that if those objects are mutated in the copy, the objects in the original are not affected, and vice versa.
On the other hand one would want that if a Set/Map has a key, this should be true in both the original and the copy -- at least before any change is made to either of them. It would be strange if the copy would be a Set/Map that has keys that never occurred before (as they were created during the cloning process): surely that is not very useful for any code that needs to know whether a given object is a key in that Set/Map or not.
As you notice, I am more of the second opinion: the keys of Sets and Maps are values (maybe references) that should remain the same.
Such choices will often also surface with other (maybe custom) objects. There is no general solution, as much depends on how the cloned object is expected to behave in your specific case.
we can achieve deep clone by using structuredClone()
const original = { name: "stack overflow" };
// Clone it
const clone = structuredClone(original);
The Underscore.js contrib library library has a function called snapshot that deep clones an object
snippet from the source:
snapshot: function(obj) {
if(obj == null || typeof(obj) != 'object') {
return obj;
}
var temp = new obj.constructor();
for(var key in obj) {
if (obj.hasOwnProperty(key)) {
temp[key] = _.snapshot(obj[key]);
}
}
return temp;
}
once the library is linked to your project, invoke the function simply using
_.snapshot(object);
Lo-Dash, now a superset of Underscore.js, has a couple of deep clone functions:
_.cloneDeep(object)
_.cloneDeepWith(object, (val) => {if(_.isElement(val)) return val.cloneNode(true)})
the second parameter is a function that is invoked to produce the cloned value.
From an answer of the author himself:
lodash underscore build is provided to ensure compatibility with the latest stable version of Underscore.
As others have noted on this and similar questions, cloning an "object", in the general sense, is dubious in JavaScript.
However, there is a class of objects, which I call "data" objects, that is, those constructed simply from { ... } literals and/or simple property assignments or deserialized from JSON for which it is reasonable to want to clone. Just today I wanted to artificially inflate data received from a server by 5x to test what happens for a large data set, but the object (an array) and its children had to be distinct objects for things to function correctly. Cloning allowed me to do this to multiply my data set:
return dta.concat(clone(dta),clone(dta),clone(dta),clone(dta));
The other place I often end up cloning data objects is for submitting data back to the host where I want to strip state fields from the object in the data model before sending it. For example, I might want to strip all fields starting with "_" from the object as it is cloned.
This is the code I ended up writing to do this generically, including supporting arrays and a selector to choose which members to clone (which uses a "path" string to determine context):
function clone(obj,sel) {
return (obj ? _clone("",obj,sel) : obj);
}
function _clone(pth,src,sel) {
var ret=(src instanceof Array ? [] : {});
for(var key in src) {
if(!src.hasOwnProperty(key)) { continue; }
var val=src[key], sub;
if(sel) {
sub+=pth+"/"+key;
if(!sel(sub,key,val)) { continue; }
}
if(val && typeof(val)=='object') {
if (val instanceof Boolean) { val=Boolean(val); }
else if(val instanceof Number ) { val=Number (val); }
else if(val instanceof String ) { val=String (val); }
else { val=_clone(sub,val,sel); }
}
ret[key]=val;
}
return ret;
}
The simplest reasonable deep-clone solution, assuming a non-null root object and with no member selection is:
function clone(src) {
var ret=(src instanceof Array ? [] : {});
for(var key in src) {
if(!src.hasOwnProperty(key)) { continue; }
var val=src[key];
if(val && typeof(val)=='object') { val=clone(val); }
ret[key]=val;
}
return ret;
}
This is the deep cloning method I use, I think it
Great, hope you make suggestions
function deepClone (obj) {
var _out = new obj.constructor;
var getType = function (n) {
return Object.prototype.toString.call(n).slice(8, -1);
}
for (var _key in obj) {
if (obj.hasOwnProperty(_key)) {
_out[_key] = getType(obj[_key]) === 'Object' || getType(obj[_key]) === 'Array' ? deepClone(obj[_key]) : obj[_key];
}
}
return _out;
}
The below function is most efficient way to deep clone javascript objects.
function deepCopy(obj){
if (!obj || typeof obj !== "object") return obj;
var retObj = {};
for (var attr in obj){
var type = obj[attr];
switch(true){
case (type instanceof Date):
var _d = new Date();
_d.setDate(type.getDate())
retObj[attr]= _d;
break;
case (type instanceof Function):
retObj[attr]= obj[attr];
break;
case (type instanceof Array):
var _a =[];
for (var e of type){
//_a.push(e);
_a.push(deepCopy(e));
}
retObj[attr]= _a;
break;
case (type instanceof Object):
var _o ={};
for (var e in type){
//_o[e] = type[e];
_o[e] = deepCopy(type[e]);
}
retObj[attr]= _o;
break;
default:
retObj[attr]= obj[attr];
}
}
return retObj;
}
var obj = {
string: 'test',
array: ['1'],
date: new Date(),
object:{c: 2, d:{e: 3}},
function: function(){
return this.date;
}
};
var copyObj = deepCopy(obj);
console.log('object comparison', copyObj === obj); //false
console.log('string check', copyObj.string === obj.string); //true
console.log('array check', copyObj.array === obj.array); //false
console.log('date check', copyObj2.date === obj.date); //false
console.log('object check', copyObj.object === obj.object); //false
console.log('function check', copyObj.function() === obj.function()); //true
Avoid use this method
let cloned = JSON.parse(JSON.stringify(objectToClone));
Why? this method will convert 'function,undefined' to null
const myObj = [undefined, null, function () {}, {}, '', true, false, 0, Symbol];
const IsDeepClone = JSON.parse(JSON.stringify(myObj));
console.log(IsDeepClone); //[null, null, null, {…}, "", true, false, 0, null]
try to use deepClone function.There are several above
There should be no real world need for such a function anymore. This is mere academic interest.
As purely an exercise, this is a more functional way of doing it. It's an extension of #tfmontague's answer as I'd suggested adding a guard block there. But seeing as I feel compelled to ES6 and functionalise all the things, here's my pimped version. It complicates the logic as you have to map over the array and reduce over the object, but it avoids any mutations.
const cloner = (x) => {
const recurseObj = x => (typeof x === 'object') ? cloner(x) : x
const cloneObj = (y, k) => {
y[k] = recurseObj(x[k])
return y
}
// Guard blocks
// Add extra for Date / RegExp if you want
if (!x) {
return x
}
if (Array.isArray(x)) {
return x.map(recurseObj)
}
return Object.keys(x).reduce(cloneObj, {})
}
const tests = [
null,
[],
{},
[1,2,3],
[1,2,3, null],
[1,2,3, null, {}],
[new Date('2001-01-01')], // FAIL doesn't work with Date
{x:'', y: {yx: 'zz', yy: null}, z: [1,2,3,null]},
{
obj : new function() {
this.name = "Object test";
}
} // FAIL doesn't handle functions
]
tests.map((x,i) => console.log(i, cloner(x)))
my addition to all the answers
function deepCopy(arr) {
if (typeof arr !== 'object') return arr
if (Array.isArray(arr)) return [...arr].map(deepCopy)
for (const prop in arr)
copy[prop] = deepCopy(arr[prop])
return copy
}
My solution, deep clones objects, arrays and functions.
let superClone = (object) => {
let cloning = {};
Object.keys(object).map(prop => {
if(Array.isArray(object[prop])) {
cloning[prop] = [].concat(object[prop])
} else if(typeof object[prop] === 'object') {
cloning[prop] = superClone(object[prop])
} else cloning[prop] = object[prop]
})
return cloning
}
example
let obj = {
a: 'a',
b: 'b',
c: {
deep: 'try and copy me',
d: {
deeper: 'try me again',
callDeeper() {
return this.deeper
}
},
arr: [1, 2, 3]
},
hi() {
return this.a
}
};
const cloned = superClone(obj)
obj.a = 'A'
obj.c.deep = 'i changed'
obj.c.arr = [45,454]
obj.c.d.deeper = 'i changed'
console.log(cloned) // unchanged object
If your objects contain methods don't use JSON to deep clone, JSON deep cloning doesn't clone methods.
If you take a look at this, object person2 only clones the name, not person1's greet method.
const person1 = {
name: 'John',
greet() {
return `HI, ${this.name}`
}
}
const person2 = JSON.parse(JSON.stringify(person1))
console.log(person2) // { name: 'John' }
Deep cloning of the object can be done in several ways but each having their own limitations as mentioned below. Hence, I will suggest you to use structuredClone algorithm.
JSON.parse(JSON.stringify(object)) - won't copy functions, Dates, undefineds & many more.
const obj = {
name: 'alpha',
printName: function() {
console.log(this.name);
}
};
console.log(JSON.parse(JSON.stringify(obj))); // function not copied
_.cloneDeep(object) - It is a good option but requires lodash.
const obj = {
name: 'alpha',
printName: function() {
console.log(this.name);
}
};
filteredArray = _.cloneDeep(obj);
console.log(filteredArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.2.1/lodash.min.js"></script>
structuredClone(object) - Browser Native API (It is good to use as JSON.parse() and JSON.stringify() do not serialize the circular object or things like Map, Set, Date, RegEx etc.)
const a = { x: 20, date: new Date() };
a.c = a;
console.log(structuredClone(a)); // { x: 20, date: <date object>, c: <circular ref> }
console.log(JSON.parse(JSON.stringify(a))); // throwing a TypeError
I noticed that Map should require special treatment, thus with all suggestions in this thread, code will be:
function deepClone( obj ) {
if( !obj || true == obj ) //this also handles boolean as true and false
return obj;
var objType = typeof( obj );
if( "number" == objType || "string" == objType ) // add your immutables here
return obj;
var result = Array.isArray( obj ) ? [] : !obj.constructor ? {} : new obj.constructor();
if( obj instanceof Map )
for( var key of obj.keys() )
result.set( key, deepClone( obj.get( key ) ) );
for( var key in obj )
if( obj.hasOwnProperty( key ) )
result[key] = deepClone( obj[ key ] );
return result;
}
This works for arrays, objects and primitives. Doubly recursive algorithm that switches between two traversal methods:
const deepClone = (objOrArray) => {
const copyArray = (arr) => {
let arrayResult = [];
arr.forEach(el => {
arrayResult.push(cloneObjOrArray(el));
});
return arrayResult;
}
const copyObj = (obj) => {
let objResult = {};
for (key in obj) {
if (obj.hasOwnProperty(key)) {
objResult[key] = cloneObjOrArray(obj[key]);
}
}
return objResult;
}
const cloneObjOrArray = (el) => {
if (Array.isArray(el)) {
return copyArray(el);
} else if (typeof el === 'object') {
return copyObj(el);
} else {
return el;
}
}
return cloneObjOrArray(objOrArray);
}
We can utilize recursion for making deepCopy. It can create copy of array, object, array of object, object with function.
if you want, you can add function for other type of data structure like map etc.
function deepClone(obj) {
var retObj;
_assignProps = function(obj, keyIndex, retObj) {
var subType = Object.prototype.toString.call(obj[keyIndex]);
if(subType === "[object Object]" || subType === "[object Array]") {
retObj[keyIndex] = deepClone(obj[keyIndex]);
}
else {
retObj[keyIndex] = obj[keyIndex];
}
};
if(Object.prototype.toString.call(obj) === "[object Object]") {
retObj = {};
for(key in obj) {
this._assignProps(obj, key, retObj);
}
}
else if(Object.prototype.toString.call(obj) == "[object Array]") {
retObj = [];
for(var i = 0; i< obj.length; i++) {
this._assignProps(obj, i, retObj);
}
};
return retObj;
};
Use immutableJS
import { fromJS } from 'immutable';
// An object we want to clone
let objA = {
a: { deep: 'value1', moreDeep: {key: 'value2'} }
};
let immB = fromJS(objA); // Create immutable Map
let objB = immB.toJS(); // Convert to plain JS object
console.log(objA); // Object { a: { deep: 'value1', moreDeep: {key: 'value2'} } }
console.log(objB); // Object { a: { deep: 'value1', moreDeep: {key: 'value2'} } }
// objA and objB are equalent, but now they and their inner objects are undependent
console.log(objA === objB); // false
console.log(objA.a === objB.a); // false
console.log(objA.moreDeep === objB.moreDeep); // false
Or lodash/merge
import merge from 'lodash/merge'
var objA = {
a: [{ 'b': 2 }, { 'd': 4 }]
};
// New deeply cloned object:
merge({}, objA );
// We can also create new object from several objects by deep merge:
var objB = {
a: [{ 'c': 3 }, { 'e': 5 }]
};
merge({}, objA , objB ); // Object { a: [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
This one, using circular reference, works for me
//a test-object with circular reference :
var n1 = { id:0, text:"aaaaa", parent:undefined}
var n2 = { id:1, text:"zzzzz", parent:undefined }
var o = { arr:[n1,n2], parent:undefined }
n1.parent = n2.parent = o;
var obj = { a:1, b:2, o:o }
o.parent = obj;
function deepClone(o,output){
if(!output) output = {};
if(o.______clone) return o.______clone;
o.______clone = output.______clone = output;
for(var z in o){
var obj = o[z];
if(typeof(obj) == "object") output[z] = deepClone(obj)
else output[z] = obj;
}
return output;
}
console.log(deepClone(obj));
var newDate = new Date(this.oldDate);
I was passing oldDate to function and generating newDate from this.oldDate, but it was changing this.oldDate also.So i used that solution and it worked.
This solution will avoid recursion problems when using [...target] or {...target}
function shallowClone(target) {
if (typeof a == 'array') return [...target]
if (typeof a == 'object') return {...target}
return target
}
/* set skipRecursion to avoid throwing an exception on recursive references */
/* no need to specify refs, or path -- they are used interally */
function deepClone(target, skipRecursion, refs, path) {
if (!refs) refs = []
if (!path) path = ''
if (refs.indexOf(target) > -1) {
if (skipRecursion) return null
throw('Recursive reference at ' + path)
}
refs.push(target)
let clone = shallowCopy(target)
for (i in target) target[i] = deepClone(target, refs, path + '.' + i)
return clone
}
Hello i just wanted to post my answer since i think its more readable. Note:this doesnt cover classes since i dont use them but you can easily add a condition for that
/** Copies any type of object/array of objects
* #param obj The object to be copied
* #param customKeys A list of keys that are to be excluded from deepCopy (optional)
*/
export function deepCopyObject(obj: any, customKeys?: Array<string|number|symbol>) {
if (obj == undefined)
return;
if (typeof obj !== 'object')
return obj;
if (typeof obj === 'function')
return obj;
const isArray = obj.length > -1;
if (isArray)
return copyArray(obj);
const isObjectDate = obj instanceof Date;
if(isObjectDate)
return new Date(obj);
const isDOM = obj.nodeType && typeof obj.cloneNode == "function";
if (isDOM)
return obj.cloneNode(true);
const isHtmlComponent = obj.$$typeof != undefined; // you can pass html/react components and maybe setup a custom function to copy them
if (isHtmlComponent)
return obj;
const newObject = <typeof obj>{};
const keys = Object.keys(obj);
keys.forEach((key: keyof (typeof obj)) => {
newObject[key] = copyKeysOfTypeObject(obj, key, customKeys);
})
const cantAccessObjectKeys = keys.lenght ==0; // ex: window.navigator
if (cantAccessObjectKeys)
return obj;
return newObject
}
function copyArray(arr: any) {
const newArr = new Array(0);
arr.forEach((obj: any) => {
newArr.push(deepCopyObject(obj));
})
return newArr;
}
function copyKeysOfTypeObject(obj: any, key: string | number | symbol, customKeys?: Array<string | number | symbol>) {
if (!key)
return;
if (customKeys && customKeys.includes(key))
return obj[key];
return deepCopyObject(obj[key]);
}
structuredClone now is supported by most the browsers
its main limitation is about DONT coping functions. It would require some extra work to copy/move it manually.
We can at least copy classes in an easy way by adding the prototypes later
const proto = Object.getPrototypeOf(object)
const newObject = structuredClone(object)
Object.setPrototypeOf(newObject, proto)
let obj1 = {
a: 100,
b: {
c: 200,
d: [1, 2, 3],
e: () => {}
}
}
function deepClone(obj) {
let newObj = {};
for (let key in obj) {
let val = obj[key];
if (val instanceof Array) {
newObj[key] = [...val]
} else if (typeof val === 'object') {
newObj[key] = deepClone(val)
} else {
newObj[key] = val;
}
}
return newObj;
}
obj2 = deepClone(obj1);
obj1.b.c = 300;
console.log(obj1);
console.log(obj2);

iterating an object properties

is there a way to iterate an object properties and methods. i need to write a utility function like so:
function iterate(obj)
{
//print all obj properties
//print all obj methods
}
so running this function:
iterate(String);
will print:
property: lenght
function: charAt
function: concat...
any ideas?
Should be as simple as this:
function iterate(obj) {
for (p in obj) {
console.log(typeof(obj[p]), p);
}
}
Note: The console.log function is assuming you are using firebug. At this point, the following:
obj = {
p1: 1,
p2: "two",
m1: function() {}
};
iterate(obj);
would return:
number p1
string p2
function m1
See my answer in this other question, but you can't read built-in properties like that.
This only works in modern browsers (Chrome, Firefox 4+, IE9+), but in ECMAScript 5, you can get all the properties of an object with Object.getOwnPropertyNames. It just takes a little extra code to get the inherited properties from the prototype.
// Put all the properties of an object (including inherited properties) into
// an object so they can be iterated over
function getProperties(obj, properties) {
properties = properties || {};
// Get the prototype's properties
var prototype = Object.getPrototypeOf(obj);
if (prototype !== null) {
getProperties(prototype, properties);
}
// Get obj's own properties
var names = Object.getOwnPropertyNames(obj);
for (var i = 0; i < names.length; i++) {
var name = names[i];
properties[name] = obj[name];
}
return properties;
}
function iterate(obj) {
obj = Object(obj);
var properties = getProperties(obj);
for (var name in properties) {
if (typeof properties[name] !== "function") {
console.log("property: " + name);
}
}
for (var name in properties) {
if (typeof properties[name] === "function") {
console.log("function: " + name);
}
}
}
You can use the for loop to iterate an object's properties.
Here is a simple example
var o ={'test':'test', 'blah':'blah'};
for(var p in o)
alert(p);

Categories