Good afternoon. I have an array with some keys, and values in them. I then need to fetch the array keys and not the data in them. I want to do this with jQuery. I know for example that PHP has a function called array_keys(); which takes the array as a parameter and gives you an array back with each key in each index.
This is what I came up with, and it works... the only problem is that it seems so unefficent;
var foo = [];
foo['alfa'] = "first item";
foo['beta'] = "second item";
for (var key in foo) {
console.log(key);
}
This will output;
alfa
beta
But is there any predefined function for this, as in PHP or any other more effective way of getting this?
you can use the each function:
var a = {};
a['alfa'] = 0;
a['beta'] = 1;
$.each(a, function(key, value) {
alert(key)
});
it has several nice shortcuts/tricks: check the gory details here
Using jQuery, easiest way to get array of keys from object is following:
$.map(obj, function(element,index) {return index})
In your case, it will return this array: ["alfa", "beta"]
In modern browsers, the easiest way to get the keys of an array is Object.keys(). For example:
console.log( Object.keys( {'a':1,'b':2} ) );
Don't Reinvent the Wheel, Use Underscore
I know the OP specifically mentioned jQuery but I wanted to put an answer here to introduce people to the helpful Underscore library if they are not aware of it already.
By leveraging the keys method in the Underscore library, you can simply do the following:
_.keys(foo) #=> ["alfa", "beta"]
Plus, there's a plethora of other useful functions that are worth perusing.
Use an object (key/value pairs, the nearest JavaScript has to an associative array) for this and not the array object. Other than that, I believe that is the most elegant way
var foo = {};
foo['alfa'] = "first item";
foo['beta'] = "second item";
for (var key in foo) {
console.log(key);
}
Note: JavaScript doesn't guarantee any particular order for the properties. So you cannot expect the property that was defined first to appear first, it might come last.
EDIT:
In response to your comment, I believe that this article best sums up the cases for why arrays in JavaScript should not be used in this fashion -
"Associative Arrays" considered Harmful
I use something like this function I created...
Object.getKeys = function(obj, add) {
if(obj === undefined || obj === null) {
return undefined;
}
var keys = [];
if(add !== undefined) {
keys = jQuery.merge(keys, add);
}
for(key in obj) {
if(obj.hasOwnProperty(key)) {
keys.push(key);
}
}
return keys;
};
I think you could set obj to self or something better in the first test.
It seems sometimes I'm checking if it's empty too so I did it that way.
Also I don't think {} is Object.* or at least there's a problem finding the function getKeys on the Object that way.
Maybe you're suppose to put prototype first, but that seems to cause a conflict with GreenSock etc.
I'm seeing something weird when I try to include the ember.js library (ember-1.0.0-rc.7.js).
The javacode I have just prints out a javascript array:
<script type="application/javascript">
var songs = [ 'a','b','c'];
console.debug(songs.toString());
for(key in songs)
{
console.debug(songs[key]);
}
</script>
When I don't include the library, it'll print out a , b, c in the console. However, when i do include it, it start printing out a, b, c, but as well as all the functions to...
Example:
function (idx) {
return this.objectAt(idx);
}
function superWrapper() {
var ret, sup = this._super;
this._super = superFunc || K;
ret = func.apply(this, arguments);
this._super = sup;
return ret;
}
function (key) {
return this.mapProperty(key);
}
Any reason why this occurs with the ember.js library, and how do I resolve this issue?
Any advice appreciated,
Thanks,
D
By default, Ember extends built-in prototypes such as Array.prototype to provide extra methods or shim ES5 methods for non-supporting browsers. You are seeing these methods because for...in iterates over the enumerable properties of an object. These include all properties, even those inherited through the prototype chain.
Instead, you should use a regular for loop to iterate over an array:
for(var i=0; i<songs.length; i++) {
console.debug(songs[i]);
}
This will only ever go over actual array elements, i.e. properties with a numerical key. There are nicer ways though, for example using ES5 Array.forEach (shimmed by Ember in older browsers):
songs.forEach(function(song, i) {
console.debug(song);
});
Optionally, you can disable Ember's prototype extension by configuring Ember.EXTEND_PROPERTIES if you're not planning to use them or if they might conflict with other libraries/scripts. There's a whole page dedicated to this issue in the Ember documentation.
embjer.js must be adding functions to the native Array.prototype. You can check if each key is actually a property on the array itself, and not an inherited property, using hasOwnProperty:
for(key in songs) {
if(songs.hasOwnProperty(key)){
console.debug(songs[key]);
}
}
But, it is usually recommended to always use ordinary for loops with arrays, since they have numerical keys:
for(var i = 0; i < songs.length; i++) {
console.debug(songs[i]);
}
You can also use the forEach function that, ironically, Ember added to the Array prototype if it didn't already exist (in older browsers).
songs.forEach(function(song){
console.debug(song);
});
Demo
I have defined prototype for Array indexOf ( to support array indexOf in Internet Explorer )
if(!Array.prototype.indexOf){
Array.prototype.indexOf = function(obj){
for(var i=0; i<this.length; i++){
if(this[i]==obj){
return i;
}
}
return -1;
}
}
When I am creating array with values [1,2,3], this indexOf code snippet added into the Array like below
["1","2","3",function(obj){for(var i=0;i<this.length;i++){if(this[i]==obj){return i;}}return -1;}]
This problem happens only in IE.
Can anyone help me to resolve this issue. Thanks in advance.
I didn't use for...in loop anywhere, for this I am using jQuery sortable toArray method .sortable("toArray");.
I am assuming that at some point you are using a for...in loop to iterate over the elements of your array. For example:
for (var elem in myArray) {
//Do stuff...
}
A for...in loop will enumerate all enumerable properties of an object, including those it has inherited from it's ancestors in its prototype chain. You've added a method to the Array prototype:
Array.prototype.indexOf = function(obj){ //...
This property is enumerable (you can't define non-enumerable properties - see Object.defineProperty - in older versions of IE), so a for...in loop will include this property.
The simple solution is to never use a for...in loop to iterate over an array! Use a normal for loop instead.
Your problem is that your new indexOf() method is marked "enumerable." Unfortunately, there is no fix for this in IE7 or non-standards-mode IE8. But you can at least patch the issue for standards mode IE8 by using some ES5 trickery. Modify your code to look like this and it should get rid of the extra element if you're in IE8 standards mode:
(function () {
var indexOfFn = function(obj){
for(var i=0; i<this.length; i++){
if(this[i]==obj){
return i;
}
}
return -1;
};
if(!Array.prototype.indexOf){
if(typeof Object.defineProperty === "function") {
Object.defineProperty(Array.prototype, "indexOf", {
value: indexOfFn,
enumerable: false
});
} else {
Array.prototype.indexOf = indexOfFn;
}
}
}());
I know it's wordy, so it might not be worth the effort. But it will also protect your JavaScript from other people's bad coding where they might end up using an Array with a for-in loop.
It's quite simple, you're array now contains 4 elements, of which the forth is a function object, you're not defining a new method for the array object, let alone all array objects. Just paste the first snippet at the very top of your script, then:
var foo = [1,2,3];
alert(foo.indexOf(2));//alerts 1
Think of Array.prototype as the template of every array. Whenever you try to access some property or method of an array, that isn't defined, rather then throwing errors, JS will first check the Array.prototype if that object doesn't have that method/property. If it does, JS will use that code, and apply it to the array that initially called it. In the above example foo.indexOf(2) could have been written as Array.prototype.indexOf.apply(foo,[2]);. In other words: JS automatically applied the function of the prototype to foo.
Your "full" code should look like this:
if(!Array.prototype.indexOf)
{
Array.prototype.indexOf = function(obj)
{
for(var i=0; i<this.length; i++)
{
if(this[i] === obj)//preferable, use strict comparison
{
return i;
}
}
return -1;
};
}
var yourArray = [1,2,3,4,'4'];
alert(yourArray.indexOf(4));//alerts 3
alert(yourArray.indexOf('4'));//alerts 4 when using strict comparison, if not, alerts 3
Here's a fiddle, checked in IE8, and it's working just fine
Just google prototypal inheritance and prototype chains or augmenting prototypes in JS and the like, read up and be baffled! ;)
I have a Javascript object that I'm trying to use as a "hashmap". The keys are always strings, so I don't think I need anything as sophisticated as what's described in this SO question. (I also don't expect the number of keys to go above about 10 so I'm not particularly concerned with lookups being O(n) vs. O(log n) etc.)
The only functionality I want that built-in Javascript objects don't seem to have, is a quick way to figure out the number of key/value pairs in the object, like what Java's Map.size returns. Of course, you could just do something like:
function getObjectSize(myObject) {
var count=0
for (var key in myObject)
count++
return count
}
but that seems kind of hacky and roundabout. Is there a "right way" to get the number of fields in the object?
There is an easier way spec'd in ECMAScript 5.
Object.keys(..) returns an array of all keys defined on the object. Length can be called on that. Try in Chrome:
Object.keys({a: 1, b: 2}).length; // 2
Note that all objects are basically key/value pairs in JavaScript, and they are also very extensible. You could extend the Object.prototype with a size method and get the count there. However, a much better solution is to create a HashMap type interface or use one of the many existing implementations out there, and define size on it. Here's one tiny implementation:
function HashMap() {}
HashMap.prototype.put = function(key, value) {
this[key] = value;
};
HashMap.prototype.get = function(key) {
if(typeof this[key] == 'undefined') {
throw new ReferenceError("key is undefined");
}
return this[key];
};
HashMap.prototype.size = function() {
var count = 0;
for(var prop in this) {
// hasOwnProperty check is important because
// we don't want to count properties on the prototype chain
// such as "get", "put", "size", or others.
if(this.hasOwnProperty(prop) {
count++;
}
}
return count;
};
Use as (example):
var map = new HashMap();
map.put(someKey, someValue);
map.size();
A correction: you need to check myObject.hasOwnProperty(key) in each iteration, because there're can be inherited attributes. For example, if you do this before loop Object.prototype.test = 'test', test will aslo be counted.
And talking about your question: you can just define a helper function, if speed doesn't matter. After all, we define helpers for trim function and other simple things. A lot of javascript is "kind of hacky and roundabout" :)
update
Failure example, as requested.
Object.prototype.test = 'test';
var x = {};
x['a'] = 1;
x['b'] = 2;
The count returned will be 3.
you could also just do myObject.length (in arrays)
nevermind, see this: JavaScript object size
That's all you can do. Clearly, JavaScript objects are not designed for this. And this will only give you the number of Enumerable properties. Try getObjectSize(Math).
In SQL we can see if a string is in a list like so:
Column IN ('a', 'b', 'c')
What's a good way to do this in JavaScript? It's so clunky to do this:
if (expression1 || expression2 || str === 'a' || str === 'b' || str === 'c') {
// do something
}
And I'm not sure about the performance or clarity of this:
if (expression1 || expression2 || {a:1, b:1, c:1}[str]) {
// do something
}
Or one could use the switch function:
var str = 'a',
flag = false;
switch (str) {
case 'a':
case 'b':
case 'c':
flag = true;
default:
}
if (expression1 || expression2 || flag) {
// do something
}
But that is a horrible mess. Any ideas?
In this case, I have to use Internet Explorer 7 as it's for a corporate intranet page. So ['a', 'b', 'c'].indexOf(str) !== -1 won't work natively without some syntax sugar.
ES6 (ES2015) and up
If you're using ECMAScript 6 (a.k.a. ES2015) or higher, the cleanest way is to construct an array of the items and use Array.includes:
['a', 'b', 'c'].includes('b')
This has some inherent benefits over indexOf because it can properly test for the presence of NaN in the list, and can match missing array elements such as the middle one in [1, , 2] to undefined. It also treats +0 and -0 as equal. includes also works on JavaScript typed arrays such as Uint8Array.
If you're concerned about browser support (such as for IE or Edge), you can check Array.includes at CanIUse.Com, and if you want to target a browser or browser version that's missing includes, you'll need to transpile to a lower ECMAScript version using a tool such as Babel, or include a polyfill script in the browser, such as those available at polyfill.io.
Higher Performance
Note that there is no guarantee that Array.includes() execution time won't scale with the number of elements in the array: it can have performance O(n). If you need higher performance, and won't be constructing the set of items repeatedly (but will be repeatedly checking if the items contain some element), you should use a Set because the ES spec requires implementations of Set (and Map as well) to be sub-linear for reads:
The specification requires sets to be implemented "that, on average, provide access times that are sublinear on the number of elements in the collection". Therefore, it could be represented internally as a hash table (with O(1) lookup), a search tree (with O(log(N)) lookup), or any other data structure, as long as the complexity is better than O(N).
const interestingItems = new Set(['a', 'b', 'c'])
const isItemInSet = interestingItems.has('b')
Note that you can pass in any iterable item to the Set constructor (anything that supports for...of). You can also convert a Set to an array using Array.from(set) or by spreading it [...set].
Without An Array
This is not really recommended, but you could add a new isInList property to strings as follows:
if (!String.prototype.isInList) {
Object.defineProperty(String.prototype, 'isInList', {
get: () => function(...args) {
let value = this.valueOf();
for (let i = 0, l = args.length; i < l; i += 1) {
if (arguments[i] === value) return true;
}
return false;
}
});
}
Then use it like so:
'fox'.isInList('weasel', 'fox', 'stoat') // true
'fox'.isInList('weasel', 'stoat') // false
You can do the same thing for Number.prototype.
Note that Object.defineProperty cannot be used in IE8 and earlier, or very old versions of other browsers. However, it is a far superior solution to String.prototype.isInList = function() { ... } because using simple assignment like that will create an enumerable property on String.prototype, which is more likely to break code.
Array.indexOf
If you are using a modern browser, indexOf always works. However, for IE8 and earlier you'll need a polyfill.
If indexOf returns -1, the item is not in the list. Be mindful though, that this method will not properly check for NaN, and while it can match an explicit undefined, it can’t match a missing element to undefined as in the array [1, , 2].
Polyfill for indexOf or includes in IE, or any other browser/version lacking support
If you don't want to use a service like polyfill.io as mentioned above, you can always include in your own source code standards-compliant custom polyfills. For example, the CoreJs library has an implementation of indexOf.
In this situation where I had to make a solution for Internet Explorer 7, I "rolled my own" simpler version of the indexOf() function that is not standards-compliant:
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(item) {
var i = this.length;
while (i--) {
if (this[i] === item) return i;
}
return -1;
}
}
Notes On Modifying Object Prototypes
However, I don't think modifying String.prototype or Array.prototype is a good strategy long term. Modifying object prototypes in JavaScript can lead to serious bugs. You need to decide whether doing so is safe in your own environment. Of primary note is that iterating an array (when Array.prototype has added properties) with for ... in will return the new function name as one of the keys:
Array.prototype.blah = function() { console.log('blah'); };
let arr = [1, 2, 3];
for (let x in arr) { console.log(x); }
// Result:
0
1
2
blah // Extra member iterated over!
Your code may work now, but the moment someone in the future adds a third-party JavaScript library or plugin that isn't zealously guarding against inherited keys, everything can break.
The old way to avoid that breakage is, during enumeration, to check each value to see if the object actually has it as a non-inherited property with if (arr.hasOwnProperty(x)) and only then work with that x.
The new ES6 ways to avoid this extra-key problem are:
Use of instead of in, for (let x of arr). However, depending on the output target and the exact settings/capabilities of your down-leveling transpiler, this may not be reliable. Plus, unless you can guarantee that all of your code and third-party libraries strictly stick to this method, then for the purposes of this question you'll probably just want to use includes as stated above.
Define your new properties on the prototype using Object.defineProperty(), as this will make the property (by default) non-enumerable. This only truly solves the problem if all the JavaScript libraries or modules you use also do this.
Be Aware of One Last Issue
Last, be aware that while polyfills make sense, and modifying object prototypes is a useful strategy, there can occasionally still be scoping problems with that approach.
In a browser, each distinct document object is its own new global scope, and in browser JS it is possible to create new documents (such as those used for off-screen rendering or to create document fragments) or to get a reference to another page's document object (such as via inter-page communication using a named-target link) so it's possible in certain (rare?) circumstances that object prototypes won't have the methods you expect them to have—though you could always run your polyfills again against the new global objects...
In Node.js, modifying prototypes of global objects may be safe, but modifying the prototypes of non-global, imported objects could lead to breakage if you ever end up with two versions of the same package being required/imported, because imports of the two versions will not expose the same objects, thus won't have the same object prototypes. That is, your code could work fine until a dependency or sub-dependency uses a different version from the one you expect, and without any of your own code changing, a simple npm install or yarn install could trigger this problem. (There are options to deal with this, such as yarn's resolutions property in the package.json, but that's not a good thing to rely on if you have other options.)
You can call indexOf:
if (['a', 'b', 'c'].indexOf(str) >= 0) {
//do something
}
Most of the answers suggest the Array.prototype.indexOf method, the only problem is that it will not work on any IE version before IE9.
As an alternative I leave you two more options that will work on all browsers:
if (/Foo|Bar|Baz/.test(str)) {
// ...
}
if (str.match("Foo|Bar|Baz")) {
// ...
}
Arrays have an indexOf method which can be used to search for strings:
js> a = ['foo', 'bar', 'baz']
foo,bar,baz
js> a.indexOf('bar')
1
js> a.indexOf('quux')
-1
In addition to indexOf (which other posters have suggested), using prototype's Enumerable.include() can make this more neat and concise:
var list = ['a', 'b', 'c'];
if (list.includes(str)) {
// do stuff
}
A trick I've used is
>>> ("something" in {"a string":"", "somthing":"", "another string":""})
false
>>> ("something" in {"a string":"", "something":"", "another string":""})
true
You could do something like
>>> a = ["a string", "something", "another string"];
>>> b = {};
>>> for(var i=0; i<a.length;i++){b[a[i]]="";} /* Transform the array in a dict */
>>> ("something" in b)
true
Using indexOf(it doesn’t work with IE8).
if (['apple', 'cherry', 'orange', 'banana'].indexOf(value) >= 0) {
// found
}
To support IE8, you could implement Mozilla’s indexOf.
if (!Array.prototype.indexOf) {
// indexOf polyfill code here
}
Regular Expressions via String.prototype.match (docs).
if (fruit.match(/^(banana|lemon|mango|pineapple)$/)) {
}
Here's mine:
String.prototype.inList=function(list){
return (Array.apply(null, arguments).indexOf(this.toString()) != -1)
}
var x = 'abc';
if (x.inList('aaa','bbb','abc'))
console.log('yes');
else
console.log('no');
This one is faster if you're OK with passing an array:
String.prototype.inList=function(list){
return (list.indexOf(this.toString()) != -1)
}
var x = 'abc';
if (x.inList(['aaa','bbb','abc']))
console.log('yes')
Here's the jsperf: http://jsperf.com/bmcgin-inlsit
RegExp is universal, but I understand that you're working with arrays. So, check out this approach. I use to use it, and it's very effective and blazing fast!
var str = 'some string with a';
var list = ['a', 'b', 'c'];
var rx = new RegExp(list.join('|'));
rx.test(str);
You can also apply some modifications, i.e.:
One-liner
new RegExp(list.join('|')).test(str);
Case insensitive
var rx = new RegExp(list.join('|').concat('/i'));
And many others!
Looks like you need to use in_array function.
jQuery -> inArray
Prototype -> Array.indexOf
Or, see these examples if you are not using jQuery or Prototype:
http://phpjs.org/functions/in_array:432
http://www.bitrepository.com/equivalent-of-phps-in_array-function.html
http://codingforums.com/showthread.php?t=63796
Stylistic note: variables named thisthing thatthing, should be named to tell you something about what they contain (noun).
Thanks for the question, and the solution using the Array.indexOf method.
I used the code from this solution to create a inList() function that would, IMO, make the writing simpler and the reading clearer:
function inList(psString, psList)
{
var laList = psList.split(',');
var i = laList.length;
while (i--) {
if (laList[i] === psString) return true;
}
return false;
}
USAGE:
if (inList('Houston', 'LA,New York,Houston') {
// THEN do something when your string is in the list
}
My solution results in a syntax like this:
// Checking to see if var 'column' is in array ['a', 'b', 'c']
if (column.isAmong(['a', 'b', 'c']) {
// Do something
}
And I implement this by extending the basic Object prototype, like this:
Object.prototype.isAmong = function (MyArray){
for (var a=0; a<MyArray.length; a++) {
if (this === MyArray[a]) {
return true;
}
}
return false;
}
We might alternatively name the method isInArray (but probably not inArray) or simply isIn.
Advantages: Simple, straightforward, and self-documenting.
I'm surprised no one had mentioned a simple function that takes a string and a list.
function in_list(needle, hay)
{
var i, len;
for (i = 0, len = hay.length; i < len; i++)
{
if (hay[i] == needle) { return true; }
}
return false;
}
var alist = ["test"];
console.log(in_list("test", alist));
A simplified version of SLaks' answer also works:
if ('abcdefghij'.indexOf(str) >= 0) {
// Do something
}
....since strings are sort of arrays themselves. :)
If needed, implement the indexof function for Internet Explorer as described before me.
My little contribution:
function fnListIndexOf(pList, pValue)
{
return pList.split(",").indexOf (pValue);
}
fnListIndexOf("1,2,3,4,5,a,b,c","a")