How to make JavaScript objects and arrays behave the same way? - javascript

I wanted to write one version of a function that iterated over both Array objects and Objects, with minimal duplicate code. Something like:
function (arr_or_obj) {
arr_or_obj.forEach( function(key,value) {
// do stuff with key and value
});
}
This was before I realized that (in Chrome at least), Object.keys returns a list of the keys for an array. So I could use that to treat the Array like an object. Like so:
function (arr_or_obj) {
var keys = Object.keys(arr_or_obj);
keys.forEach( function(key) {
var value = arr_or_obj[key];
// do stuff with key and value
});
}
Problem solved. But this was not before I wrote my own "JavaScript pseudo-Array iterator". The only advantage of this was that instead of getting a list of keys for the Array (which could be very long), we save memory by producing only the return values we need. Like so:
function create_iterator(max) {
var jkeys = {};
jkeys.count_ = 0;
jkeys.length = max;
jkeys.getter_ = function() {
var returnable = jkeys.count_;
jkeys.count_ += 1;
jkeys.__defineGetter__(jkeys.count_,jkeys.getter_);
delete jkeys[jkeys.count_-1];
return returnable;
};
jkeys.__defineGetter__(0, jkeys.getter_);
return jkeys;
}
Which you can then call by going:
var z = create_iterator(100);
z[0];
>> 0
z[0];
>> undefined
z[1];
>> 1;
z[2]
>> 2;
...
This is sort of a question and answer in one, but the obvious question is, is there a better way to do this without using Object.keys?

Object.keys gives you an array of the object's own enumerable properties. That is, properties it has itself, not from its prototype, and that are enumerable (so not including things like length on arrays, which is a non-enumerable property).
You can do the same thing with for-in if you use correct safeguards:
var key;
for (key in arr_or_obj) {
if (arr_or_obj.hasOwnProperty(key)) {
// do something with it
}
}
Now you're doing the same thing you were doing with Object.keys.
But, note that this (and Object.keys) will include properties people put on arrays that aren't array indexes (something which is perfectly valid in JavaScript). E.g.:
var key;
var a = [1, 2, 3];
a.foo = "bar";
for (key in a) {
if (a.hasOwnProperty(key)) {
console.log(key); // Will show "foo" as well as "0", "1", and "2"
}
}
If you want to only process array indexes and not other properties, you'll need to know whether the thing is an array, and then if so use the "is this an index" test:
var key;
var isArray = Array.isArray(arr_or_obj);
// Or (see below):
//var isArray = Object.prototype.toString.call(arr_or_obj) === "[object Array]";
for (key in arr_or_obj) {
if (a.hasOwnProperty(key) &&
(!isArray || isArrayIndex(key))
) {
console.log(key); // Will only show "0", "1", and "2" for `a` above
}
}
...where Array.isArray is a new feature of ES5 which is easily shimmed for older browsers if necessary:
if (!Array.isArray) {
Array.isArray = (function() {
var toString = Object.prototype.toString;
function isArray(arg) {
return toString.call(arg) === "[object Array]";
}
return isArray;
})();
}
...and isArrayIndex is:
function isArrayIndex(key) {
return /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294; // 2^32 - 2
}
See this other answer for details on that (where the magic numbers come from, etc.).
That loop above will loop through an object's own enumerable properties (all of them) if it's not an array, and loop through the indexes (but not other properties) if it's an array.
Taking it a step further, what if you want to include the properties the object gets from its prototype? Object.keys omits those (by design). If you want to include them, just don't use hasOwnProperty in the for-in loop.

You can try something like this...
Live Demo
function forIn(obj) {
var isArray = Array.isArray(obj),
temp = isArray ? obj : Object.keys(obj);
temp.forEach(function (value, index, array) {
console.log(this[isArray ? index : value]);
}, obj);
}

You can write:
for (key in arr_or_obj) {
if (arr_or_obj.hasOwnProperty(key) {
value = arr_or_obj[key];
// do stuff with key and value
}
}

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>

Comparing 2 JSON objects structure in JavaScript

I am using angular-translate for a big application. Having several people committing code + translations, many times the translation objects are not in sync.
I am building a Grunt plugin to look at both files' structure and compare it (just the keys and overall structure, not values).
The main goals are:
Look into each file, and check if the structure of the whole object
(or file, in this case) is the exact same as the translated ones;
On error, return the key that doesn't match.
It turns out it was a bit more complicated than I anticipated. So i figured I could do something like:
Sort the object;
Check the type of data the value contains (since they are translations, it will only have strings, or objects for the nestings) and store it in another object, making the key equal to the original key and the value would be a string 'String', or an object in case it's an object. That object contains the children elements;
Recursively repeat steps 1-2 until the whole object is mapped and sorted;
Do the same for all the files
Stringify and compare everything.
A tiny example would be the following object:
{
key1: 'cool',
key2: 'cooler',
keyWhatever: {
anotherObject: {
key1: 'better',
keyX: 'awesome'
},
aObject: 'actually, it\'s a string'
},
aKey: 'more awesomeness'
}
would map to:
{
aKey: 'String',
key1: 'String',
key2: 'String',
keyWhatever: {
aObject: 'String',
anotherObject: {
key1: 'String',
keyX: 'String'
}
}
}
After this, I would stringify all the objects and proceed with a strict comparison.
My question is, is there a better way to perform this? Both in terms of simplicity and performance, since there are many translation files and they are fairly big.
I tried to look for libraries that would already do this, but I couldn't find any.
Thank you
EDIT: Thank you Jared for pointing out objects can't be sorted. I am ashamed for saying something like that :D Another solution could be iterating each of the properties on the main translation file, and in case they are strings, compare the key with the other files. In case they are objects, "enter" them, and do the same. Maybe it is even simpler than my first guess. What should be done?
Lets say you have two JSON objects, jsonA and jsonB.
function compareValues(a, b) {
//if a and b aren't the same type, they can't be equal
if (typeof a !== typeof b) {
return false;
}
// Need the truthy guard because
// typeof null === 'object'
if (a && typeof a === 'object') {
var keysA = Object.keys(a).sort(),
keysB = Object.keys(b).sort();
//if a and b are objects with different no of keys, unequal
if (keysA.length !== keysB.length) {
return false;
}
//if keys aren't all the same, unequal
if (!keysA.every(function(k, i) { return k === keysB[i];})) {
return false;
}
//recurse on the values for each key
return keysA.every(function(key) {
//if we made it here, they have identical keys
return compareValues(a[key], b[key]);
});
//for primitives just use a straight up check
} else {
return a === b;
}
}
//true if their structure, values, and keys are identical
var passed = compareValues(jsonA, jsonB);
Note that this can overflow the stack for deeply nested JSON objects. Note also that this will work for JSON but not necessarily regular JS objects as special handling is needed for Date Objects, Regexes, etc.
Actually you do need to sort the keys, as they are not required to be spit out in any particular order. Write a function,
function getComparableForObject(obj) {
var keys = Object.keys(obj);
keys.sort(a, b => a > b ? 1 : -1);
var comparable = keys.map(
key => key + ":" + getValueRepresentation(obj[key])
).join(",");
return "{" + comparable + "}";
}
Where getValueRepresentation is a function that either returns "String" or calls getComparableForObject. If you are worried about circular references, add a Symbol to the outer scope, repr, assign obj[repr] = comparable in the function above, and in getValueRepresentation check every object for a defined obj[repr] and return it instead of processing it recursively.
Sorting an array of the keys from the object works. However, sorting has an average time complexity of O(n⋅log(n)). We can do better. A fast general algorithm for ensuring two sets A and B are equivalent is as follows:
for item in B
if item in A
remove item from A
else
sets are not equivalent
sets are equivalent iff A is empty
To address #Katana31, we can detect circular references as we go by maintaining a set of visited objects and ensuring that all descendents of that object are not already in the list:
# poorly written pseudo-code
fn detectCycles(A, found = {})
if A in found
there is a cycle
else
found = clone(found)
add A to found
for child in A
detectCycles(child, found)
Here's a complete implementation (you can find a simplified version that assumes JSON/non-circular input here):
var hasOwn = Object.prototype.hasOwnProperty;
var indexOf = Array.prototype.indexOf;
function isObjectEmpty(obj) {
for (var key in obj) {
return false;
}
return true;
}
function copyKeys(obj) {
var newObj = {};
for (var key in obj) {
newObj[key] = undefined;
}
return newObj;
}
// compares the structure of arbitrary values
function compareObjectStructure(a, b) {
return function innerCompare(a, b, pathA, pathB) {
if (typeof a !== typeof b) {
return false;
}
if (typeof a === 'object') {
// both or neither, but not mismatched
if (Array.isArray(a) !== Array.isArray(b)) {
return false;
}
if (indexOf.call(pathA, a) !== -1 || indexOf.call(pathB, b) !== -1) {
return false;
}
pathA = pathA.slice();
pathA.push(a);
pathB = pathB.slice();
pathB.push(b);
if (Array.isArray(a)) {
// can't compare structure in array if we don't have items in both
if (!a.length || !b.length) {
return true;
}
for (var i = 1; i < a.length; i++) {
if (!innerCompare(a[0], a[i], pathA, pathA)) {
return false;
}
}
for (var i = 0; i < b.length; i++) {
if (!innerCompare(a[0], b[i], pathA, pathB)) {
return false;
}
}
return true;
}
var map = copyKeys(a), keys = Object.keys(b);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (!hasOwn.call(map, key) || !innerCompare(a[key], b[key], pathA,
pathB)) {
return false;
}
delete map[key];
}
// we should've found all the keys in the map
return isObjectEmpty(map);
}
return true;
}(a, b, [], []);
}
Note that this implementation directly compares two objects for structural equivalency, but doesn't reduce the objects to a directly comparable value (like a string). I haven't done any performance testing, but I suspect that it won't add significant value, though it will remove the need to repeatedly ensure objects are non-cyclic. For that reason, you could easily split compareObjectStructure into two functions - one to compare the structure and one to check for cycles.

javascript - custom object prototype method turns into index in array loop

Here's something weird. I have defined a custom prototype method for object called getSize:
if (!Object.prototype.getSize) {
Object.prototype.getSize = function() {
var size = 0, key;
for (key in this) {
if (this.hasOwnProperty(key)) size++;
}
return size;
};
}
It gives you the size of an object. Pretty simple so far, right?
Here's where I get confused:
var l = ["foo", "bar"]
for (var i in l) {
console.log(i);
}
results are:
0
1
getSize
Why is getSize there???
edit
I know that arrays in javascript are objects too. My question is why is the method turned into an index, instead of remaining a method. It doesn't make any sense to me...
Because getSize is an enumerable property, you could define it to be non-enumerable:
Object.defineProperty(Object.prototype, 'getSize', {
enumerable: false,
value: function() {
var size = 0, key;
for (key in this) {
if (this.hasOwnProperty(key)) size++;
}
return size;
}
});
But you could also do:
Object.keys(object).length;
Because ["foo", "bar"] is an Object in JavaScript too. Try to run typeof ["foo", "bar"] in console. It will return "object" to you. So you have extended Arrays methods too. Once you have done this you will need to check for hasOwnProperty in all for..in iterations as well.
This happens to all global objects in JavaScript

Creating new variable from another

What would be the best way to create a new array or object from another. Since doing
var oldvar = {x:1,y:2} //or [x,y]
var newvar = oldvar
will link them, what would be the bets best way to clone or cope the new variable?
Numbers in JavaScript
Numbers in JavaScript are what the spec calls 'Primitive Value Type'
From the specification about Numbers:
Number value # Ⓣ
primitive value corresponding to a double-precision 64-bit binary format IEEE 754 value.
NOTE A Number value is a member of the Number type and is a direct representation of a number.
So in your case newvar will be a copy of oldvar and not a reference.
In JavaScript, Number, Boolean, undefined, null or String are value types.
When passing any of these 5 around, you are in fact passing values and not references, no need to clone those.
When you pass anything else around (Objects) need to use cloning since they are reference types.
When cloning objects in JavaScript there are two approaches.
Shallow Cloning
This means you clone 1 level deep. Assuming all our properties in the object are enumerable (This is usually the case if you haven't used property descriptors) you can use something like:
var a = {a:3,b:5};
var copy = {};
for(var prop in a){
copy[prop] = a[prop];
}
However, often we want to copy the object's own properties and not everything it might inherit from its prototype, so we can do:
var copy = {};
for(var prop in a){
if(a.hasOwnProperty(prop)){//check that the cloned property belongs to _a_ itself
copy[prop] = a[prop];
}
}
Note these two only shallow copy properties off a, they do not deal with setting the prototype, and clone all the properties by reference (Except properties who are primitive value types themselves :) ).
Deep copying
Deep copying means creating a clone of the object that is several levels deep. This calls to recursion since deep copying is defined as such (in psuedocode)
CopyObject(object)
If object is a primitive value type
return object
clone := Empty Object
For every member of object
Add CopyObject(member) as a property to clone
Return clone
We are applying the algorithm recursively on object properties of the clone.
Here is a sample implementation that I documented for you. It assumes ES5 (Chrome) but you can easily adapt it to other/older browsers. It does more stuff like treat Date and Regex like special cases. It also keeps a dictionary of properties it already handled so it will be able to handle circular references in an object. It is intended for learning and not for production use :) If you have any questions about it feel free.
var clone = function (a) {
var passedRefs = []; // Keep track of references you passed to avoid cycles
var passedRefCreated = [];
function clone2(a1) { // Inner function to handle the actual cloning
var obj;
if (typeof a1 !== "object" || a1 === null) { // Handle value type
return a1;
}
var locInpPassed = passedRefs.indexOf(a1); // Detect circular reference
if (locInpPassed !== -1) {
return passedRefCreated[locInpPassed];
}
passedRefs.push(a1); // Add the object to the references to avoid circular references later
if (a1 instanceof Date) { // Handle date and RegExp for special cases
obj = new Date(a1.getTime());
} else if (a1 instanceof RegExp) {
obj = new RegExp(a1);
}else if (Array.isArray(a1)){// handle arrays in order for Array.isArray to work. Thanks FizzyTea for catching this.
obj = [];
} else { // Create a new object with the prototype of the one we're cloning to support prototypical inheritance. Prototypes are _shared_
obj = Object.create(Object.getPrototypeOf(a1));
}
passedRefCreated[passedRefs.indexOf(a1)] = obj; // Add to the references created dict
Object.getOwnPropertyNames(a1).forEach(function (prop) { // Go through all the property, even the ones that are not enumerable
obj[prop] = clone2(a1[prop]); // Call the algorithm recursively, just like in the pseudo code above
});
return obj;
}
return clone2(a); // Call the inner function that has access to the dictionary
}
(For example, you can use a for... in loop to iterate through the properties).
I wrote 2 relation functions for deep copying arrays and objects in javascript:
function clone_object(o) {
var r = {};
for (var p in o) {
if (o[p].constructor == Array) {
r[p] = clone_array(o[p]);
} else if (o[p].constructor == Object) {
r[p] = arguments.callee(o[p]);
} else {
r[p] = o[p];
}
}
return r;
}
function clone_array(o) {
var r = [];
for (var p = 0, l = o.length; p < l; p++) {
if (o[p].constructor == Array) {
r[p] = arguments.callee(o[p]);
} else if (o[p].constructor == Object) {
r[p] = clone_object(o[p]);
} else {
r[p] = o[p];
}
}
return r;
}
Example:
var o = { name: 'Prototype', version: 1.5, authors: ['sam', 'contributors'] };
var o2 = clone_object(o);
o2.authors.pop();
alert(o.authors);
// -> ['sam', 'contributors']
alert(o2.authors);
// -> ['sam']

Count number of object in another object , javascript-json

There seems to have many question asked similar on counting number of element already but I am failing to implement them with mine problem.
After jquery ajax I get JSON data returned which looks something like this
Object {0: Object, 1: Object , xxxx:"asdf" ,yyyy:"asdf", zzzz:"asdf"}
I want to get number of object between this { } braces ( not counting those xxx,yyy element )
I tried .length which doesn't work
I also tried using this Length of a JavaScript object but that return the number of element in each object. I just want the number of object
Thank You
Try this:
var json = { 0: {}, 1: {}, xxxx: "asdf", yyyy: "asdf", zzzz: "asdf" };
function typeOf( obj ) {
return ({}).toString.call( obj )
.match(/\s([a-zA-Z]+)/)[1].toLowerCase();
}
var total = 0;
for ( var o in json ) {
if ( typeOf( json[o] ) == 'object' ) {
total++;
}
}
console.log( total ); //=> 2
Everything is an object in JavaScript. The typeof operator is misleading and won't work in this case. You can use the typeOf function above that I extracted from this blog post: Fixing the JavaScript typeof operator (worth reading). There are other ways of doing it but this seems like the most straightforward.
If it's not just a coincidence that the objects are the ones with numeric property names, and the numeric properties count up sequentially, you could do something like this:
var obj = { /* your object here */ }
for (var i=0; i in obj; i++) {
// use obj[i] for something
}
// i is now equal to the number of numeric properties
This works because as soon as i is high enough that you've run out of properties the in operator will return false. Feel free to use .hasOwnProperty() instead if you prefer.
Obviously this is a specialised solution that doesn't test the type of the different properties at all. (To actually test the type see elclanrs' solution - and either way read the page he linked to.)
Say that the entire json is in a variable called json:
var total_objects = 0;
$.each(json, function () {
if (typeof this == 'object') {
total_objects++;
}
});
However, I am curious as to why you would need to know this.
You can use a customized version from the code of this question Length of Javascript Object (ie. Associative Array) and check for element's type using typeof operator and count only those which are an object (or an array).
Object.sizeObj = function(obj) {
var size = 0, key;
for (key in obj) {
if (typeof key[obj] === 'object' && obj.hasOwnProperty(key)) size++;
}
return size;
};
// Get the count of those elements which are an object
var objectsCount = Object.sizeObj(myArray);

Categories