Javascript setattr or setOwnProperty - javascript

I have a simple array:
var arr = ['has_cats', 'has_dogs'];
and an object:
var obj = new Object();
and from the array I want to set object attributes:
for( i=0; i < arr.length; i++ ) {
if(!arr.hasOwnProperty(arr[i])) {
// set the object property
}
}
After looping I should be able to call obj.has_cats but I can't seem to find a proper way to do it in javascript. In python I would call setattr(obj,arr[i], value). I figured that if objects have a hasOwnProperty they should also have a getOwnProperty and a setOwnProperty.
Any guidance?

"I figured that if objects have a hasOwnProperty they should also have
a getOwnProperty and a setOwnProperty"
The hasOwnProperty() function tells you whether the named property exists as a direct property of the object, as compared to being an inherited property from somewhere in the object's prototype chain. The in operator - used like if (someProperty in someObject) {} - will tell you whether the object has that property anywhere in the prototype chain.
You don't need a corresponding setOwnProperty() function because you can just say:
someObject[someProperty] = someValue;
I guess the idea of a corresponding getOwnProperty() function kind of makes sense if you want a function that only returns a value if the specified property is a direct property, but then there wouldn't be any way to indicate that the specified property wasn't found because null, undefined, false, etc. are all legitimate potential values if the property is found. So to achieve that you need to do it as a two-step process using if (hasOwnProperty()).
But it doesn't sound like that's what you're trying to do. If I understand you correctly, you just want some way to set a property where the property name is in a variable (in your case, an array element). You don't make it clear what values you want associated to those properties, so I'll just use true.
var arr = ['has_cats', 'has_dogs'];
var obj = {}; // note {} is generally preferred to new Object();
for(var i=0; i < arr.length; i++ ) {
// if the property doesn't already exist directly on
// the object
if(!obj.hasOwnProperty(arr[i])) {
// set the object property
obj[arr[i]] = true;
}
}
// can access with bracket notation
alert(obj["has_cats"]);
// can access with dot notation
alert(obj.has_cats);

You can set the value via:
for(i = 0; i < arr.length; i++ ) {
if(!obj.hasOwnProperty(arr[i])) {
obj[arr[i]] = 'value';
}
}

Neither getOwnProperty nor setOwnProperty would add any value:
The following always set the property on the object that evaluated from x. Therefore, setOwnProperty is nothing more but a property assignment.
x[prop] = v
Likewise, using a combination of hasOwnProperty and property existence it is possible to derive (and supersede) getOwnProperty:
if (x.hasOwnProperty(prop)) {
// x has prop
// x[prop] may evaluate to undefined
} else if (prop in x) {
// prop resolved through [[prototype]] chain
// x[prop] may evaluate to undefined
} else {
// property prop not set
// x[prop] will evaluate to undefined
}
Happy coding.

I think you are overcomplicating this somewhat. Try this:
var arr = ['has_cats', 'has_dogs'];
var obj = new Object();
for( i=0; i < arr.length; i++ ) {
obj[arr[i]] = true;
}
You don't need to use hasOwnProperty against an array when iterating it by its indices. Though perhaps you meant to check against obj as a guard against overwriting anything that was already set?

You can set the property with:
obj[arr[i]] = "my value";
In javascript property access can be either done by .name or ['name'].

Related

Unwrap objects in array

I have an array of objects:
var Props = [booleanPoint, buttonPoint, checkboxPoint, datePoint, dialPoint, gaugePoint,
groupboxPoint, htmlPoint, imagePoint, livetextPoint, livetrendsPoint, permissionsPoint,
rangePoint, selectPoint, spectrumPoint];
Console log shows:
Edited:
I want to extract the properties inside each object. How do I do it?
To be clear I just want the first property in the array, so that I can do Props.booleanPoint, Props.buttonPoint etc.
You question is not very clear, but I guess you're trying to extract the first (and only) property from each object in the list, whose name you don't know.
If yes, consider this:
extracted = Props.map(function(obj) {
for(var p in obj)
return obj[p];
});
If you want to combine all properties into one big object, try this:
allProps = Object.assign.apply(null, Props)
I'm not sure exactly what result you're after, but the best solution is probably either a forEach or a map.
var properties = {};
Props.forEach(function(object) {
// update properties somehow based on object
});
or
var properties = Props.map(function(object) {
return [some property of object];
});
The first just runs some code on each entry in the array; the second returns a new array with the results of that code.
Otherwise, the classic for loop works too:
var properties = {};
for (var i = 0; i < Props.length; i++ {
// update properties somehow based on Props[i]
}

Which Objects in JavaScript have a .length property? (aka Why does Underscore _.each treat my Function Object like an Array?)

I've been under the impression that only Array objects have a .length property. But, then again, I've also seen mentions of objects that are "array-like". I've not looked into this, and now it seems like my ignorance of this topic in JS may be biting me in the ass. Case in point:
I've got the following code:
var View = function(options) {
// code
};
_.extend(View, Backbone.Events, {
make_children: function(parent) {
// code
}
});
Later on, I use this View Function with Underscore's _.each, which decides this function object is an array, because it has a .length property:
// Code from Underscore.js's `_.each`:
} else if (obj.length === +obj.length) { // This is true
for (var i = 0, l = obj.length; i < l; i++) { // **So, execution goes here**
if (iterator.call(context, obj[i], i, obj) === breaker) return
}
} else {
for (var key in obj) {
if (_.has(obj, key)) { // **Execution does __not__ go here**
if (iterator.call(context, obj[key], key, obj) === breaker) return;
}
}
}
This results in code that doesn't work, because obj[i] where i is an integer index, is not actually defined on my obj View. To be precise, in the above code, obj[0] is undefined while obj.length === +obj.length is true and obj.length is 1. What's going on here?
Addendum
Underscore's chief maintainer says the following on https://github.com/documentcloud/underscore/pull/510:
Simply making each reject function objects doesn't really help. We've
made a conscious decision to use a numerical length property to detect
array-like objects.
Instead, don't pass function objects to each.
Addendum 2
Realized that since I couldn't pass a function object to _.each, I could just "cast it" to a regular object like so:
var regular_obj = _.extend({}, View);
The issue here is that underscore.js, much like jquery, both use the .length property as a flag in their each functions. When the length property is present, the function assumes that the argument passed can be iterated through with a normal for loop. The reason behind this logic is there is an expectation that when the length property is defined then it is possible to iterate through the argument in order which is why the for loop is used.
The result of misusing length is essentially a name collision where there is an unintended result. I would suggest changing length to another synonym such as size or capacity or totalViews, etc.
Edit
If there are no other alternatives for you to use, and you must have length in there while still retaining _.each's functionality, then you can slightly hack it. This plug works with the minified version of underscore version 1.4.3
var s = Array.prototype.ForEach;
var r = {};
var myEach = function (n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length&&typeof(n[0])!="undefined"){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(_.has(n,a)&&t.call(e,n[a],a,n)===r)return};
_.each=myEach;
Here is a demo: http://jsfiddle.net/Xa5qq/
Basically what it does is use forEach when the length property exists but typeof(yourObject[0]) == "undefined".
Which Objects in JavaScript have a .length property?
By oh-so-tautological definition, any object which has a length property.
This happens to include functions.
length is a property of a function object, and indicates how many arguments the function expects, i.e. the number of formal parameters.
This is also array-like, because it has a length:
var foo = {
bar: true,
baz: 'quux',
length: 42
}

Iterate over defined elements of a JS array

I'm using a JS array to Map IDs to actual elements, i.e. a key-value store. I would like to iterate over all elements. I tried several methods, but all have its caveats:
for (var item in map) {...}
Does iterates over all properties of the array, therefore it will include also functions and extensions to Array.prototype. For example someone dropping in the Prototype library in the future will brake existing code.
var length = map.lenth;
for (var i = 0; i < length; i++) {
var item = map[i];
...
}
does work but just like
$.each(map, function(index, item) {...});
They iterate over the whole range of indexes 0..max(id) which has horrible drawbacks:
var x = [];
x[1]=1;
x[10]=10;
$.each(x, function(i,v) {console.log(i+": "+v);});
0: undefined
1: 1
2: undefined
3: undefined
4: undefined
5: undefined
6: undefined
7: undefined
8: undefined
9: undefined
10: 10
Of course my IDs wont resemble a continuous sequence either. Moreover there can be huge gaps between them so skipping undefined in the latter case is unacceptable for performance reasons. How is it possible to safely iterate over only the defined elements of an array (in a way that works in all browsers and IE)?
Use hasOwnProperty within for ... in to make sure that prototype additions aren't included:
for (var item in map)
if (map.hasOwnProperty(item)) {
// do something
}
There are three issues:
You should not use for...in to iterate arrays.
You are using the wrong data type for your requirements.
You are not using for...in correctly.
If you want to have something like a hash table then use a plain object:
var map = {};
map[123] = 'something';
map.foo = 'bar';
// same as map['foo'] = 'bar';
//...
It looks like an array, but it is not. It is an object with property 123. You can use either dot notation obj.key (only if the key is a valid identifier - 123 would not be valid so you have to use the following notation) or array notation obj['key'] to access object properties.
It seems that an object would be a more appropriate data structure.
But even then you should make a call to hasOwnProperty (every time you use for...in):
for(var key in obj) {
if(obj.hasOwnProperty(key)) {
//do something
}
}
This checks whether a property is inherited from the prototype (it will return false then) or is truly an own property.
Use the EcmaScript 5 builtin Object.keys, and on non ES5 browsers, define it thus:
Object.keys = function (o) {
var keys = [];
var hasOwnProp = Object.prototype.hasOwnProperty;
if (Object.prototype.toString.call(o) === '[object Array]') {
for (var k in o) {
if (+k === (k & 0x7fffffff) && hasOwnProp.call(o, k)) {
keys[keys.length] = k;
}
}
keys.sort(keys, function (a, b) { return a - b; });
} else {
for (var k in o) {
if (hasOwnProp.call(o, k)) {
keys[keys.length] = k;
}
}
}
return keys;
};
1) use an object like already suggested, it is by far the best solution.
2) if you for some reason need to use an array - don't be scared looping over it with
for(var i, len = arr.length;len < i;i++)
it's very very fast.
3) don't use $.each or similar methods if you want performance - they create a new callstack for every iteration, which is a huge overhead.
Don't use an array. Use an object hash instead
var map = {};
map[key] = value;
...
for (var key in map) {
do something to map[key]
}
You can't do a lot without actually doing a check to see if the value is undefined and then doing operation a or operation b. It would be better to use a predicate to determine if the value is undefined:
x = $.grep(x, function(v, i) { return (typeof(v) != "undefined"); });
There isn't. The only way would be to omit the items from the collection completely, any solution you come up with would still have to do a test on each element for the value.
You could come up with different methods of adding the items key/value to object literals or what have you, but you would still need to omit undefined entries if you do not wish to enumerate over them.

JavaScript object literal length === undefined?

I am working on this animation function but I have a problem. I can't seem to perform what should be an easy task, I can not get the length of an object. If you check out that jsFiddle you can see that I am running alert(properties.length); and it is returning undefined. Can anyone see why this might be?
This is supported in node.js and newer environments.
var obj = {a: "a", b: "b"};
Object.keys(obj).length // 2
JavaScript object simply do not have a length property, only Arrays do. If you want to know the number of properties that are defined on a object, you have to iterate over them and count them.
Also, your for in loop is prone to bugs due extension of Object.prototype since in will traverse the complete prototype chain and enumerate all the properties that are on the chain.
Example
// Poisoning Object.prototype
Object.prototype.bar = 1;
var foo = {moo: 2};
for(var i in foo) {
console.log(i); // logs both 'moo' AND 'bar'
}
You have to use the hasOwnProperty method on the object in order to filter out those unwanted properties.
// still the foo from above
for(var i in foo) {
if (foo.hasOwnProperty(i)) {
console.log(i); // only logs 'moo'
}
}
Many JavaScript frameworks out there extend the prototype, not using hasOwnProperty often leads to horrible bugs.
Update
Concerning the actual problem that your code is not animation both properties.
for(var p in properties) {
...
for(var i = 0; i <= frames; i++)
{
setTimeout((function(exti, element) {
return function() {
// p gets overriden by for outer for in loop
element.style[p] = original + (pixels * exti) + 'px';
}
// you need to pass in a copy of the value of p here
// just like you do with i and element
})(i, element), i * (1000 / 60), element);
}
....
}
If you are using Underscore.js, you can use _.size():
_.size({one : 1, two : 2, three : 3});
=> 3
Objects have no length, you'll need to use an array if you want that.
If you have to find the number of properties in an object there is only one way:
var length =0;
for(var i in obj) length++;
Here's #Junaid Qadir Shekhanzai's general function for "finding the length of an object" (which as we're told, should properly be called "counting the properties of an object"). It combines solutions from #Ivo Wetzel and #Martin Jespersen:
function countProperties(myObj){
var length = 0;
if(typeof myObj != 'object'){
return false;
}
for(var i in myObj) {
length++;
}
return length;
}

Check if an array item is set in JS

I've got an array
var assoc_pagine = new Array();
assoc_pagine["home"]=0;
assoc_pagine["about"]=1;
assoc_pagine["work"]=2;
I tried
if (assoc_pagine[var] != "undefined") {
but it doesn't seem to work
I'm using jquery, I don't know if it can help
Thanks
Use the in keyword to test if a attribute is defined in a object
if (assoc_var in assoc_pagine)
OR
if ("home" in assoc_pagine)
There are quite a few issues here.
Firstly, is var supposed to a variable has the value "home", "work" or "about"? Or did you mean to inspect actual property called "var"?
If var is supposed to be a variable that has a string value, please note that var is a reserved word in JavaScript and you will need to use another name, such as assoc_var.
var assoc_var = "home";
assoc_pagine[assoc_var] // equals 0 in your example
If you meant to inspect the property called "var", then you simple need to put it inside of quotes.
assoc_pagine["var"]
Then, undefined is not the same as "undefined". You will need typeof to get the string representation of the objects type.
This is a breakdown of all the steps.
var assoc_var = "home";
var value = assoc_pagine[assoc_var]; // 0
var typeofValue = typeof value; // "number"
So to fix your problem
if (typeof assoc_pagine[assoc_var] != "undefined")
update: As other answers have indicated, using a array is not the best sollution for this problem. Consider using a Object instead.
var assoc_pagine = new Object();
assoc_pagine["home"]=0;
assoc_pagine["about"]=1;
assoc_pagine["work"]=2;
var assoc_pagine = new Array();
assoc_pagine["home"]=0;
Don't use an Array for this. Arrays are for numerically-indexed lists. Just use a plain Object ({}).
What you are thinking of with the 'undefined' string is probably this:
if (typeof assoc_pagine[key]!=='undefined')
This is (more or less) the same as saying
if (assoc_pagine[key]!==undefined)
However, either way this is a bit ugly. You're dereferencing a key that may not exist (which would be an error in any more sensible language), and relying on JavaScript's weird hack of giving you the special undefined value for non-existent properties.
This also doesn't quite tell you if the property really wasn't there, or if it was there but explicitly set to the undefined value.
This is a more explicit, readable and IMO all-round better approach:
if (key in assoc_pagine)
var is a statement... so it's a reserved word... So just call it another way.
And that's a better way of doing it (=== is better than ==)
if(typeof array[name] !== 'undefined') {
alert("Has var");
} else {
alert("Doesn't have var");
}
This is not an Array.
Better declare it like this:
var assoc_pagine = {};
assoc_pagine["home"]=0;
assoc_pagine["about"]=1;
assoc_pagine["work"]=2;
or
var assoc_pagine = {
home:0,
about:1,
work:2
};
To check if an object contains some label you simply do something like this:
if('work' in assoc_pagine){
// do your thing
};
This worked for me
if (assoc_pagine[var] != undefined) {
instead this
if (assoc_pagine[var] != "undefined") {
TLDR; The best I can come up with is this: (Depending on your use case, there are a number of ways to optimize this function.)
function arrayIndexExists(array, index){
if ( typeof index !== 'number' && index === parseInt(index).toString()) {
index = parseInt(index);
} else {
return false;//to avoid checking typeof again
}
return typeof index === 'number' && index % 1===0 && index >= 0 && array.hasOwnKey(index);
}
The other answer's examples get close and will work for some (probably most) purposes, but are technically quite incorrect for reasons I explain below.
Javascript arrays only use 'numerical' keys. When you set an "associative key" on an array, you are actually setting a property on that array object, not an element of that array. For example, this means that the "associative key" will not be iterated over when using Array.forEach() and will not be included when calculating Array.length. (The exception for this is strings like '0' will resolve to an element of the array, but strings like ' 0' won't.)
Additionally, checking array element or object property that doesn't exist does evaluate as undefined, but that doesn't actually tell you that the array element or object property hasn't been set yet. For example, undefined is also the result you get by calling a function that doesn't terminate with a return statement. This could lead to some strange errors and difficulty debugging code.
This can be confusing, but can be explored very easily using your browser's javascript console. (I used chrome, each comment indicates the evaluated value of the line before it.);
var foo = new Array();
foo;
//[]
foo.length;
//0
foo['bar'] = 'bar';
//"bar"
foo;
//[]
foo.length;
//0
foo.bar;
//"bar"
This shows that associative keys are not used to access elements in the array, but for properties of the object.
foo[0] = 0;
//0
foo;
//[0]
foo.length;
//1
foo[2] = undefined
//undefined
typeof foo[2]
//"undefined"
foo.length
//3
This shows that checking typeof doesn't allow you to see if an element has been set.
var foo = new Array();
//undefined
foo;
//[]
foo[0] = 0;
//0
foo['0']
//0
foo[' 0']
//undefined
This shows the exception I mentioned above and why you can't just use parseInt();
If you want to use associative arrays, you are better off using simple objects as other answers have recommended.
if (assoc_pagine.indexOf('home') > -1) {
// we have home element in the assoc_pagine array
}
Mozilla indexOf
function isset(key){
ret = false;
array_example.forEach(function(entry) {
if( entry == key ){
ret = true;
}
});
return ret;
}
alert( isset("key_search") );
The most effective way:
if (array.indexOf(element) > -1) {
alert('Bingooo')
}
W3Schools

Categories

Resources