How to remove Empty Properties from a multi depth JavaScript Object? - javascript

I've got this JS Object:
var test = {"code_operateur":[""],"cp_cult":["",""],"annee":["2011"],"ca_cult":[""]}
When I use this function:
for (i in test) {
if ( test[i] == "" || test[i] === null ) {
delete test[i];
}
}
I get:
{"cp_cult":["",""],"annee":["2011"]}
Okay not bad, but I'd like to remove the empty "cp_cult" property (which is an array and not a string like the other).
Note: I don't want to manually delete the key!

It looks like you're asking 2 questions here.
How do I remove a property of an object; and
How can I tell if an object is actually an array.
You can delete a property of an object using the delete operator.
delete test.cp_cult;
In JavaScript arrays are objects, which means that typeof([]) unhelpfully returns object. Typically people work around this by using a function in a framework (dojo.isArray or something similar) or rolling their own method that determines if an object is an array.
There is no 100% guaranteed way to determine if an object is actually an array. Most people just check to see if it has some of the methods/properties of an array length, push, pop, shift, unshift, etc.

Try:
function isEmpty(thingy) {
for(var k in thingy){
if(thingy[k]) {
return false;
}
}
return true;
}
for(i in test) {
if ( test[i] == "" || test[i] === null || (typeof test[i] == "object" && isEmpty(test[i])) ) {
delete test[i];
}
}
However, depending on the complexity of the object, you'd need more advanced algorithms. For example, if the array can contain another array of empty strings (or even more levels) and it should be deleted, you'd need to check for that as well.
EDIT: Trying to make something to fit your needs, please have a look at: http://jsfiddle.net/jVHNe/

Related

How to check for multiple undefined in dojo or JavaScript?

I have the below piece of code in my project. As you can see, I had to check the undefined for all the object and properties this.view && this.view.formView && this.view.formView._dapSections && this.view.formView._dapSections.scrollTop.
I'm looking for a way to check undefined for all at once.Is there any way to do that in JavaScript or dojo?
if(this.view && this.view.formView && this.view.formView._dapSections && this.view.formView._dapSections.scrollTop) {
globals.lastScrollPosition = this.view.formView._dapSections.scrollTop;
}
You might also want to try lang.exists()
https://dojotoolkit.org/reference-guide/1.10/dojo/_base/lang.html#dojo-base-lang-exists
if (lang.exists('view.view.formView._dapSections.scrollTop', this) {
globals.lastScrollPosition = this.view.formView._dapSections.scrollTop;
}
This is precisely the sort of thing that dojo/_base/lang.getObject is designed for.
var scrollTop = lang.getObject('view.formView._dapSections.scrollTop', false, this);
if (scrollTop) {
globals.lastScrollPosition = scrollTop;
}
The first argument is a string representing the properties on the object to look up
The second argument is whether to create each property if it doesn't exist (you usually don't want to do that)
The third argument is the object to use as the context for the lookup

Using 'in' when the object may be a string

I was looking up how to check if a variable in JavaScript is an array, but then as the SO page was loading, I thought of a solution to the problem. Looking through the answers, I found that none of them had thought of this simple answer: Just check for the methods we need to use on the array, so that it still works for any user defined types that implement the same methods. Being the helpful person I am, I thought I'd submit my answer for future people trying to solve the same problem..But after testing it, I found it does not work.
function print(object) {
if ('map' in object) { // If the object implements map, treat it like an array
object.map(function(current) {
console.log(current);
});
} else { // Otherwise, treat it as a string
console.log(object);
}
}
Now, this works fine when I call it with an array, but if I use a string it fails. Since strings are objects in javascript, why shouldn't the 'in' keyword work for them? Is there any way to implement this that is as simple as what it currently is?
You can access the property and test its type:
if (object != null && typeof object.map === 'function')
object.map(...);
// ...
Since strings are objects in javascript, why shouldn't the 'in' keyword work for them?
Not quite. There is a difference between a primitive string value and a String instance object.
typeof "foo"; // "string"
typeof new String(); // "object"
Primitive values don't have properties themselves, which is why the in operator throws an Error when used on them. They will, however, be temporarily boxed into Objects by property accessors:
var a = "foo";
a.bar = 'bar'; // no error, but...
console.log(a.bar); // undefined
String.prototype.baz = function () {
return this + this;
};
console.log(a.baz()); // "foofoo"
I suppose you could do something like this:
var y = function (o) {
if (typeof o != "string" && "map" in o)
console.log("not a string"); //your code here
else
console.log("It's a string!"); //your code here
}
I tested this with var x = "hello" and it worked. Because && short circuits in JavaScript, it will stop at typeof o != "string", which is good, since "map" in o fails for strings. Note the intentional use of lowercase, which is for primitives; Strings are objects. I'm not exactly sure if this is what you were aiming for.

Hashing JavaScript objects

I have a function that receives a list of JS objects as an argument. I need to store information about those objects in a private variable for future reference. I do not want to stuff a property into the objects themselves, I just want to keep it out of band in a dictionary. I need to be able to lookup metadata for an object in sub-linear time.
For this I need a hash function such that, for any two objects o1 and o2,
hash(o1) !== hash(o2) whenever o1 !== o2.
A perfect example of such a hash function would be the memory address of the object, but I don't think JS exposes that. Is there a way?
Each object reference is different. Why not push the object onto an array? Traversing the array looking for an object reference might still perform better than inspecting each object in a recursive manor to generate a hash key.
function Dictionary() {
var values = [];
function contains(x) {
var i = values.length;
while(i--) {
if (values[i] === x) {
return true;
}
}
return false;
}
function count() {
return values.length;
}
function get(i) {
return (i >= 0 && i < values.length) ? values[i] : null;
}
function set(o) {
if (contains(o)) {
throw new Error("Object already exists in the Dictionary");
}
else {
return values.push(o) - 1;
}
}
function forEach(callback, context) {
for (var i = 0, length = values.length; i < length; i++) {
if (callback.call(context, values[i], i, values) === false) {
break;
}
}
}
return {
get: get,
set: set,
contains: contains,
forEach: forEach,
count: count
};
}
And to use it:
var objects = Dictionary();
var key = objects.set({});
var o = objects.get(key);
objects.contains(key); // returns true
objects.forEach(function(obj, key, values) {
// do stuff
}, this);
objects.count(); // returns 1
objects.set(o); // throws an error
To store metadata about objects, you can use an WeakMap:
WeakMaps are key/value maps in which keys are objects.
Note that this API is still experimental and thus not widely supported yet (see support table). There is a polyfill implementation which makes use of defineProperty to set GUIDs (see details here).
Javascript does not provide direct access to memory (or to the file system for that matter).
You'd probably just want to create your properties/variables within the analysis (hash) function, and then return them to where the function was called from to be stored/persisted for later reference.
Thanks everyone who chipped in to reply. You all have convinced me that what I want to do is currently not possible in JavaScript.
There seem to be two basic compromises that someone with this use case can chose between:
Linear search using ===
=== appears to be the only built-in way to distinguish between two identically-valued objects that have different references. (If you had two objects, o1 and o2, and did a deep comparison and discovered that they were value-identical, you might still want to know if they're reference-identical. Besides === you could do something weird like add a property to o1 and see if showed up in o2).
Add a property to the object.
I didn't like this approach because there's no good reason why I should have to expose this information to the outside world. However, a colleague tipped me off to a feature that I didn't know about: Object.defineProperty. With this, I can alleviate my main concerns: first, that my id would show up, unwanted, during object enumeration, and second, that someone could inadvertently alter my id if there were to be a namespace collision.
So, in case anyone comes here wanting the same thing I wanted, I'm putting it up there for the record that I'm going to add a unique id using Object.defineProperty.

Checking for undefined

I am utterly confused. I know this has been asked a million times. And I have looked at questions like:
Test if something is not undefined in JavaScript
Now the problem is when doing the check I have found multiple things you can do.
I need to check if an object is an array, to do that I check if the "length" property is there. Now what one would I use?
if (obj.length)
or
if (obj.length === undefined)
or
if (typeof obj.length === "undefined")
or
if (obj.length == null)
or something else?
I understand that === doesn't do any type conversion, and the if statement is just wanting a "truthy" or "falsey" value, meaning obj.length will return false if the length is 0, but that's not what we want. We want to now if it is defined. Which is why I go to type test. But which way is the best?
Here are some tests I did. 2, 3 and 4 work.
Sorry for the stuff in between. I was doing it in the console for this page.
Short answer:
if (obj instanceof Array) {
// obj is an array
}
Or, if you don't know whether obj is defined or not:
if ((typeof obj !== "undefined") && (obj instanceof Array)) {
// obj is an array
}
To discuss why yours aren't quite right:
obj.anyProperty will throw a ReferenceError if obj is undefined. This affects all four of the things you put.
if (obj.length) will evaluate to false for an empty array, which isn't what you want. Because the length is 0 (a falsy value), it will falsely be inaccurate. This could also have issues if another object has a length property.
if (obj.length === undefined) will usually work, but it's frowned upon because undefined can be redefined. Someone could break your code by writing undefined = obj.length. This can also create false negatives; obj could happen to have a property called "length" and it would falsely call it an array.
if (typeof obj.length === "undefined") works fine, but could detect the same false negatives as the above.
if (obj.length == null) will work okay, but has the same bugs as above. In a double-equals (==), it matches null and undefined.
I would do `
obj instanceof Array
to check if obj is an array
http://jsfiddle.net/Tcjk4/
For what it's worth, here's how jQuery checks whether something is an array:
isArray: Array.isArray || function( obj ) {
return jQuery.type(obj) === "array";
},
This uses ES5's Array.isArray if available, or a custom check in older browsers. jQuery makes this function accessible as $.isArray.
jQuery.type is basically an enhanced typeof that works around some limitations of the JavaScript language and browser bugs. Whereas typeof returns 'object' for anything object-like ({}, [], even null), $.type returns the internal JavaScript [[Class]] property of the object.
In fact, this method of determining type is actually safer than instanceof:
Both instanceof and constructor look very innocent and seem like great
ways to check if an object is an array.
The problems arise when it comes to scripting in multi-frame DOM
environments. In a nutshell, Array objects created within one iframe
do not share [[Prototype]]s with arrays created within another
iframe. Their constructors are different objects and so both
instanceof and constructor checks fail:
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // [1,2,3]
// Boom!
arr instanceof Array; // false
// Boom!
arr.constructor === Array; // false
More comment than answer.
While a test like object instanceof Array will work in most cases (it may fail where frames or inter–window communication are involved), it's a good idea to consider what you really need to test for and design the test accordingly. Testing explicitly whether an object is an array or not is almost always unnecessary.
In this case, it seems that you just want to use the length property for iterating over the object's numeric properties.
If that's the case, all you need to do is read the value of the length property and use it. Whether the property is missing, or hasn't been assigned a value, or has a value of undefined or 0, you don't want to do the loop. Fortunately, you can do all of those tests in one go (and also skip processing if the value is Null or '', which seems sensible too):
if (obj.length) {
// iterate over numeric properties of obj
}
That will make the method generic, so it can be applied to any Object that has a suitable length property and some numeric properties (e.g. a jQuery object or an HTMLCollection object).
If you need some other feature of an array (say push or slice), you can also test for those.
If you are using the test as a logic fork (e.g. if it's an array do one thing, if it's a plain object do something else) then you should consider whether that's a sensible thing to do.
var sizeArrayOrObject = function(obj) {
var size = 0, key;
for (key in obj) {
if (typeof obj.key === 'undefined') size++;
}
return size;
};
sizeArrayOrObject([]); // 0
sizeArrayOrObject([5,6]); // 2
sizeArrayOrObject({}); // 0
sizeArrayOrObject({id:8}); // 1
to use underscore.js http://underscorejs.org/#isObject
_.isArray(object)
Returns true if object is an Array.
(function(){ return _.isArray(arguments); })();
=> false
_.isArray([1,2,3]);
=> true
_.isObject(value)
Returns true if value is an Object. Note that JavaScript arrays and functions are objects, while (normal) strings and numbers are not.
_.isObject({});
=> true
_.isObject(1);
=> false

How can I index an array of objects in Javascript faster?

In order to build the array of strings necessary for JQuery autocomplete, I'm traversing an array of objects and flattening it into an array of unique strings. I'm doing this about how you might expect:
var input = [{prop1:'value1', prop2: 'value2'}];
$.each(input, function (index, value) {
$.each(value, function (i, v) {
if (v != undefined && v != null && v != '' && ($.inArray(v, keywords) < 0)) {
keywords.push(v);
}
});
});
The problem is that it performs poorly for large input sets, and blocks the UI while it's running. How can I make this better?
You've got an O(n^2) algorithm there. Looking through that keywords array over and over again is going to get really slow (as you've noticed).
Instead, keep the keywords as an object:
var keywords = {};
// ... inside your ".each():
if (v && !keywords[v])
keywords[v] = true;
Note that your tests of "v" against undefined, null, and the empty string can be replaced by letting JavaScript check it's truthiness. That's not always the right thing, but it's fine here.
You can also keep the keywords in an array, if you like. Just don't search the array to determine whether a keyword has been seen yet.
i think you're trying to fix wrong problem
why is your autosuggestion list so big that javascript performs poorly? just send top 10 autosuggestions to client and you'll be fine

Categories