Determine if string is in list in JavaScript - javascript

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")

Related

Is there something wrong with using window['variableAsString']?

It's been very useful for writing functions that require iterating through variables, but I've heard users advising against using similar methods.
Is there something wrong with writing code this way?
Example of use:
Say I have three arrays and want to add a value to all three:
array1=[];
array2=[1,2];
array3=[4,4];
for (var i=1;i< 4; i++){
window['array'+i].push(1);
}
If you're going to need to iterate through a set of variables, plan ahead and put them inside an object:
var myArrays = {
array1: [],
array2: [1, 2],
array3: [4, 4],
"any-name-you-want-works": []
};
Accessing them is still straightforward:
myArrays.array1.push(1);
myArrays["any-name-you-want-works"].push(1);
Adding a new array to myArrays:
myArrays.array4 = [3, 5];
And iterating is made easy (this is the recommended way):
for (var arr in myArrays) {
if (object.hasOwnProperty(arr)) {
arr.push(1);
}
}
If you don't need to support old browsers, you can use newer features as well (source):
Object.keys(myArrays).forEach(function(key, index) {
myArrays[key].push(1);
});
More info on Object.keys().
Then, if you're using a popular lib like underscore or lodash, you can do lots of thing easily on objects and arrays:
_.chain(myArrays)
.each(function(arr) { arr.push(1) }) // adds one to each array
.first() // takes the first array
.map(function(val) { return val *2; }) // and multiply each value
.reverse() // then reverse those values
.value(); // and get the array
As I mentioned in a comment, you shouldn't pollute the global window object and also iterate through it to avoid collision or unexpected behaviors.
Wrapping your code inside an IIFE (Immediatly-Invoked Function Expression) is always a good idea, instead of using the global scope, for multiple reasons, but that's a whole other discussion and we can achieve what you want without it (for this question anyway).
It's not good practice to stick all of your variables in the global scope. There are certain cases where it's acceptable, for instance if you have a library that you want to be available everywhere, but it's generally best to avoid using window, particularly in the way you are using it. The good news is you don't need window to do what you want to at all. You can just add your arrays as attributes on an object, and reference them using strings the same way you did with window (which is just a globally scoped object). Note the use of var to scope the object locally.
var arrays = {
array1: [],
array2: [1,2],
array3: [4,4]
};
for (var i=1;i< 4; i++){
arrays['array'+i].push(1);
}

Javascript collection

sorry for noobie question. Can you explain please, what is the difference between:
1. var a = [];
a['b'] = 1;
2. var a = {};
a['b'] = 1;
I could not find article in the internet so wrote here.
Literals
The [] and {} are called the array and object literals respectively.
var x = [] is short for var x = new Array();
and var y = {} is short for var y = new Object();
Arrays
Arrays are structures with a length property. You can access values via their numeric index.
var x = [] or var x = new Array();
x[0] = 'b';
x[1] = 'c';
And if you want to list all the properties you do:
for(var i = 0; i < x.length; i++)
console.log(x[i]);// numeric index based access.
Performance tricks and gotchas
1. Inner-caching the length property
The standard array iteration:
for (var i = 0; i < arr.length; i++) {
// do stuff
};
Little known fact: In the above scenario, the arr.length property is read at every step of the for loop. Just like any function you call there:
for (var i = 0; i < getStopIndex(); i++) {
// do stuff
};
This decreases performance for no reason. Inner caching to the rescue:
for (var i = 0, len = arr.length; i < len; i++) {
// enter code here
};
Here's proof of the above.
2. Don't specify the Array length in the constructor.
// doing this:
var a = new Array(100);
// is very pointless in JS. It will result in an array with 100 undefined values.
// not even this:
var a = new Array();
// is the best way.
var a = [];
// using the array literal is the fastest and easiest way to do things.
Test cases for array definition are available here.
3. Avoid using Array.prototype.push(arr.push)
If you are dealing with large collections, direct assignment is faster than using the Array.prototype.push(); method.
myArray[i] = 0; is faster than myArray.push(0);, according to jsPerf.com test cases.
4. It is wrong to use arrays for associative assignments.
The only reason why it works is because Array extends the Object class inside the core of the JS language. You can just as well use a Date(); or RegEx(); object for instance. It won't make a difference.
x['property'] = someValue MUST always be used with Objects.
Arrays should only have numeric indexes. SEE THIS, the Google JS development guidelines! Avoid for (x in arr) loops or arr['key'] = 5;.
This can be easily backed up, look HERE for an example.
var x = [];
console.log(x.prototype.toString.call);
 will output: [object Array]
This reveals the core language's 'class' inheritance pattern.  
var x = new String();
console.log(x.prototype.toString.call);
will output [object String].
5. Getting the minimum and maximum from an array.
A little known, but really powerful trick:
function arrayMax(arr) {
return Math.max.apply(Math, arr);
};
, respectively:
function arrayMin(arr) {
return Math.min.apply(Math, arr);
};
Objects
With an object you can only do:
var y = {} or var y = new Object();
y['first'] = 'firstValue' is the same as y.first = 'firstValue', which you can't do with an array. Objects are designed for associative access with String keys.
And the iteration is something like this:
for (var property in y) {
if (y.hasOwnProperty(property)) {
console.log(y.property);
};
};
Performance tricks and gotchas
1. Checking if an object has a property.
Most people use Object.prototype.hasOwnProperty. Unfortunately that often gives erroneous results leading to unexpected bugs.
Here's a good way to do it:
function containsKey(obj, key) {
return typeof obj[key] !== 'undefined';
};
2. Replacing switch statements.
One of the simple but efficient JS tricks is switch replacement.
switch (someVar) {
case 'a':
doSomething();
break;
case 'b':
doSomethingElse();
break;
default:
doMagic();
break;
};
In most JS engines the above is painfully slow. When you are looking at three possible outcomes, it doesn't make a difference, but what if you had tens or hundreds?
The above can easily be replaced with an object. Don't add the trailing (), this is not executing the functions, but simply storing references to them:
var cases = {
'a': doSomething,
'b': doSomethingElse,
'c': doMagic
};
Instead of the switch:
var x = ???;
if (containsKey(cases, x)) {
cases[x]();
} else {
console.log("I don't know what to do!");
};
3. Deep-cloning made easy.
function cloneObject(obj) {
var tmp = {};
for (var key in obj) {
tmp[key] = fastDeepClone(obj[key];
};
return tmp;
}
function cloneArr(arr) {
var tmp = [];
for (var i = 0, len = arr.length; i < len; i++) {
tmp[i] = fastDeepClone(arr[i]);
}
return tmp;
}
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
};
function isArray(obj) {
return obj instanceof Array;
}
function isObject(obj) {
var type = typeof obj;
return type === 'object' && obj !== null || type === 'function';
}
function fastDeepClone(obj) {
if (isArray(obj)) {
return cloneArr(obj);
} else if (isObject(obj)) {
return cloneObject(obj);
} else {
return obj;
};
};
HERE is the deep clone function in action.
Auto-boxing
As a dynamically typed language, JavaScript is limited in terms of native object types:
Object
Array
Number
Boolean
Date
RegEx
Error
Null is not a type, typeof null is object.
What's the catch? There is a strong distinction between primitive and non-primitive objects.
var s = "str";
var s2 = new String("str");
They do the same thing, you can call all string methods on s and s2.
Yet:
type of s == "string"; // raw data type
type of s2 == "object" // auto-boxed to non-primitive wrapper type
s2.prototype.toString.call == "[object String]";
You may hear in JS everything is an object. That's not exactly true, although it's a really easy mistake to make.
In reality there are 2 types, primitives and objects, and when you call s.indexOf("c"), the JS engine will automatically convert s to its non-primitive wrapper type, in this case object String, where all the methods are defined on the String.prototype.
This is called auto-boxing. The Object.prototype.valueOf(obj) method is a way to force the cast from primitive to non-primitive. It's the same behaviour a language like Java introduces for many of it's own primitives, specifically the pairs: int - Integer, double - Double, float - Float, etc.
Why should you care?
Simple:
function isString(obj) {
return typeof obj === "string";
}
isString(s); // true
isString(s2); // false
So if s2 was created with var s2 = new String("test") you are getting a false negative, even for an otherwise conceivably simple type check. More complex objects also bring with themselves a heavy performance penalty.
A micro-optimization as some would say, but the results are truly remarkable, even for extremely simple things such as string initialisation. Let's compare the following two in terms of performance:
var s1 = "this_is_a_test"
and
var s2 = new String("this_is_a_test")
You will probably expected matching performance across the board, but rather surprisingly the latter statement using new String is 92% slower than the first one, as proven here.
Functions
1. Default parameters
The || operator is the simplest possible way of defaulting. Why does it work? Because of truthy and falsy values.
When evaluated in a logical condition, undefined and null values will autocast to false.
A simple example(code HERE):
function test(x) {
var param = x || 5;
// do stuff with x
};
2. OO JS
The most important thing to understand is that the JavaScript this object is not immutable. It is simply a reference that can be changed with great ease.
In OO JS, we rely on the new keyword to guarantee implicit scope in all members of a JS Class. Even so, you can easily change the scope, via Function.prototype.call and Function.prototype.apply.
Another very important thing is the Object.prototype. Non-primitive values nested on an objects prototype are shared, while primitive ones are not.
Code with examples HERE.
A simple class definition:
function Size(width, height) {
this.width = width;
this.height = height;
};
A simple size class, with two members, this.width and this.height.
In a class definition, whatever has this in front of it, will create a new reference for every instance of Size.
Adding methods to classes and why the "closure" pattern and other "fancy name pattern" are pure fiction
This is perhaps where the most malicious JavaScript anti-patterns are found.
We can add a method to our Size class in two ways.
Size.prototype.area = function() {
return this.width * this.height;
};
Or:
function Size2(width, height) {
this.width = width;
this.height = height;
this.area = function() {
return this.width * this.height;
}
}
var s = new Size(5, 10);
var s2 = new Size2(5, 10);
var s3 = new Size2(5, 10);
var s4 = new Size(5, 10);
// Looks identical, but lets use the reference equality operator to test things:
s2.area === s3.area // false
s.area === s4.area // true
The area method of Size2 is created for every instance.
This is completely useless and slow, A LOT slower. 89% to be exact. Look HERE.
The above statement is valid for about 99% of all known "fancy name pattern". Remember the single most important thing in JS, all those are nothing more than fiction.
There are strong architectural arguments that can be made, mostly revolved around data encapsulation and the usage of closures.
Such things are unfortunately absolutely worthless in JavaScript, the performance loss simply isn't worth it. We are talking about 90% and above, it's anything but negligible.
3. Limitations
Because prototype definitions are shared among all instances of a class, you won't be able to put a non-primitive settings object there.
Size.prototype.settings = {};
Why? size.settings will be the same for every single instance.
So what's with the primitives?
Size.prototype.x = 5; // won't be shared, because it's a primitive.
// see auto-boxing above for primitive vs non-primitive
// if you come from the Java world, it's the same as int and Integer.
The point:
The average JS guy will write JS in the following way:
var x = {
doStuff: function(x) {
},
doMoreStuff: 5,
someConstant: 10
}
Which is fine (fine = poor quality, hard to maintain code), as long as you understand that is a Singleton object, and those functions should only be used in global scope without referencing this inside them.
But then it gets to absolutely terrible code:
var x = {
width: 10,
height: 5
}
var y = {
width: 15,
height: 10
}
You could have gotten away with: var x = new Size(10, 5); var y = new Size(15, 5);.
Takes longer to type, you need to type the same thing every time. And again, it's A LOT SLOWER. Look HERE.
Poor standards throughout
This can be seen almost anywhere:
function() {
// some computation
var x = 10 / 2;
var y = 5;
return {
width: x,
height: y
}
}
Again with the alternative:
function() {
var x = 10 / 2;
var y = 5;
return new Size(10, 5);
};
The point: USE CLASSES WHEREVER APPROPRIATE!!
Why? Example 1 is 93% Slower. Look HERE.
The examples here are trivial, but they illustrate something being ignored in JS, OO.
It's a solid rule of thumb not to employ people who think JS doesn't have classes and to get jobs from recruiters talking about "Object Orientated" JS.
Closures
A lot of people prefer them to the above because it gives them a sense of data encapsulation. Besides the drastic 90% performance drop, here's something equally easy to overlook. Memory leaks.
function Thing(someParam) {
this.someFn = function() {
return someParam;
}
}
You've just created a closure for someParam. Why is this bad? First, it forces you to define class methods as instance properties, resulting in the big performance drop.
Second, it eats up memory, because a closure will never get dereferenced. Look here for proof. Sure, you do get some fake data encapsulation, but you use three times the memory with a 90% performance drop.
Or you can add #private and get a way with an underscore function name.
Other very common ways of generating closures:
function bindSomething(param) {
someDomElement.addEventListener("click", function() {
if (param) //do something
else // do something else
}, false);
}
param is now a closure! How do you get rid of it? There are various tricks, some found here. The best possible approach, albeit more rigorous is to avoid using anonymous functions all-together, but this would require a way to specify scopes for event callbacks.
Such a mechanism is only available in Google Closure, as far as I know.
The singleton pattern
Ok, so what do I do for singletons? I don't want to store random references. Here's a wonderful idea shamelessly stolen from Google Closure's base.js
/**
* Adds a {#code getInstance} static method that always return the same instance
* object.
* #param {!Function} ctor The constructor for the class to add the static
* method to.
*/
function addSingletonGetter(ctor) {
ctor.getInstance = function() {
if (ctor.instance_) {
return ctor.instance_;
}
return ctor.instance_ = new ctor;
};
};
It's Java-esque, but it's a simple and powerful trick. You can now do:
project.some.namespace.StateManager = function() {
this.x_ = 5;
};
project.some.namespace.prototype.getX = function() { return x; }
addSingletonGetter(project.some.namespace.StateManager);
How is this useful? Simple. In all other files, every time you need to reference project.some.namespace.StateManager, you can write:
project.some.namespace.StateManager.getInstance(). This is more awesome than it looks.
You can have global state with the benefits of a class definition (inheritance, stateful members, etc.) and without polluting the global namespace.
The single instance pattern
You may now be tempted to do this:
function Thing() {
this.someMethod = function() {..}
}
// and then use it like this:
Thing.someMethod();
That is another big no-no in JavaScript. Remember, the this object is only guaranteed to be immutable when the new keyword is used. The magic behind the above code is interesting. this is actually the global scope, so without meaning to you are adding methods to the global object. And you guessed it, those things never get garbage collected.
There is nothing telling JavaScript to use something else. A function on it's own doesn't have a scope. Be really careful what you do with static properties. To reproduce a quote I once read, the JavaScript global object is like a public toilet. Sometimes you have no choice but to go there, yet try and minimise contact with the surfaces as much as possible.
Either stick to the above Singleton pattern or use a settings object nested under a namespace.
Garbage collection in JavaScript
JavaScript is a garbage collected language, but JavaScript GC is often rather poorly understood. The point is again speed. This is perhaps all too familiar.
// This is the top of a JavaScript file.
var a = 5;
var b = 20;
var x = {};//blabla
// more code
function someFn() {..}
That is bad, poor performance code. The reason is simple. JS will garbage collect a variable and free up the heap memory it holds only when that variable gets de-scoped, e.g. there are no references to it anywhere in the memory.
For example:
function test(someArgs) {
var someMoreStuf = // a very big complex object;
}
test();
Three things:
Function arguments are transformed into local definitions
Inner declarations are hoisted.
All the heap memory allocated for inner variables is freed up when the function finishes execution.
Why?
Because they no longer belong to the "current" scope. They are created, used, and destroyed. There are no closures either, so all the memory you've used is freed up through garbage collection.
For that reason, you should never, your JS files should never look like this, as global scope will just keep polluting memory.
var x = 5;
var y = {..}; //etc;
Alright, now what?
Namespaces.
JS doesn't have namespaces per say, so this isn't exactly a Java equivalent, yet from a codebase administration perspective you get what you want.
var myProject = {};
myProject.settings = {};
myProject.controllers = {};
myProject.controlls.MainController = function() {
// some class definition here
}
Beautiful. One global variable. Proper project structure.
With a build phase, you can split your project across files, and get a proper dev environment.
There's no limit to what you can achieve from here.
Count your libraries
Having had the pleasure of working on countless codebases, the last and most important argument is to be very mindful of your code dependencies. I've seen programmers casually adding jQuery into the mix of the stack for a simple animation effect and so forth.
Dependency and package management is something the JavaScript world hadn't addresses for the longest time, until the creation of tools like Bower. Browsers are still somewhat slow, and even when they're fast, internet connections are slow.
In the world of Google for instance, they go through the lengths of writing entire compilers just to save bytes, and that approach is in many ways the right mentality to have in web programming. And I uphold Google in very high regard as their JS library powers apps like Google Maps, which are not only insanely complex, but also work everywhere.
Arguably JavaScript has an immense variety of tools available, given its popularity, accessibility, and to some extent very low quality bar the ecosystem as a whole is willing to accept.
For Hacker News subscribers, a day doesn't go by without a new JS library out there, and they are certainly useful but one cannot ignore the fact that many of them re-implement the exact same concerns without any strong notion of novelty or any killer ideas and improvements.
It's a strong rule of thumb to resist the urge of mixing in all the new toys before they have the time to prove their novelty and usefulness to the entire ecosystem and to strongly distinguish between Sunday coding fun and production deployments.
If your <head></head> tag is longer than this post, you're doing it all wrong.
Testing your knowledge of JavaScript
A few "perfectionist" level tests:
http://perfectionkills.com/javascript-quiz/, thanks to Kangax.
http://javascript-puzzlers.herokuapp.com/
A collection of objects? Use this notation (JavaScript arrays):
var collection = [ {name:"object 1"} , {name:"object 2"} , {name:"object 3"} ];
To put a new element into your collection:
collection.push( {name:"object 4"} );
In JavaScript all objects are associative arrays. In first case you create an array in the second case you created an empty object which is array too :).
So in JS you can work with any object as with array:
var a = {};
a["temp"] = "test";
And as object:
var a = {};
a.temp = "test";
I would use an array of objects:
collection = [
{ "key":"first key", "value":"first value" },
{ "key":"second key", "value":"second value" }
];
etc
1) Is an Array
2) Is an Object
With Array all is usual as in other languages
With Object also.
- You can get value a.b == 1
- But in JS you can also get value with such syntax a["b"] == 1
This could be usefull when key look like something this "some key", in this case you can't use "chaining"
also this usefull if key is the variable
you can write like this
function some(f){
var Object = {name: "Boo", age: "foo"}, key;
if(f == true){
key = "name";
}else{
key = "age";
}
return Object[key];
}
but I want to use it as collection, which I have to choose?
This depends of what data you want to store

Determine how many fields a Javascript object has

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).

Do any prevalent Javascript frameworks provide a utility for pruning objects?

We're using jQuery on a less UI-intensive project whereas we have been using ExtJS on other projects. Regardless, I'm curious if any of the prevalent libraries such as ExtJS, jQuery, or others, provide a utility for "pruning" objects? By which I mean, deleting keys if they don't contain values.
I've devised my own (naive) implementation as follows, so its no biggie. Still though just curious as I believe this could be generally useful. I've googled for "jquery prune object" but no results seem worth investigating though of course I could be wrong ;)
function pruneObj(obj) {
var empty = [];
for (var attr in obj) {
if (!obj[attr]) {
empty.push(attr); //rather than trying to delete the element in place
}
}
for (var i=0, n=empty.length; i<n; i++) {
delete(obj[empty[i]]);
}
return obj;
}
So:
var obj = { hasFoo: false, count: 0 }
would (after a call to prunObj(obj)) be just {}?
I don't think any library out there would make the assumption of what values to deem "empty". It's too destructive/mutative a function to include as part of a standard set of utility functions.
Many libraries or browsers include a facility to filter out items from arrays that don't meet a certain criteria. Eg filter:
list.filter(function(item){
return !item.foo
})
will filter out items in list that have a "falsey" value in the foo property.
Edit:
On further thought, undefined seems to be considered "empty" by both jQuery and Prototype. jQuery's extend function can do what I think you're aiming for with undefined, albeit with a slightly different syntax and without mutating the passed argument:
A = { hasFoo: false, count: 0, foo: null, bar: undefined };
B = jQuery.extend({}, A); // B = { hasFoo: false, count: 0, foo: null }
Swap "jQuery" with "Object" for the Prototype equivalent.

How do I get number of fields in JavaScript object?

I'm trying to use JavaScript object as an associative array and everything was well until I needed to get number of entries that are stored in it. What is the easiest and most elegant way to do that? All I can think of is to run for each loop or jQuery $.each function and just see how much iterations it would do but that looks like an an awful thing to do.
This worked for me:
Object.keys(obj).length
Old Firefox supports the __count__ property. Newer environments support ES5's Object.keys. For older environments we have to fallback to just iterating over the object and counting manually (ugh!):
function count(obj) {
if (obj.__count__ !== undefined) { // Old FF
return obj.__count__;
}
if (Object.keys) { // ES5
return Object.keys(obj).length;
}
// Everything else:
var c = 0, p;
for (p in obj) {
if (obj.hasOwnProperty(p)) {
c += 1;
}
}
return c;
}
I believe this has been answered on here before, and/or googling can lead you in the right direction. Nevertheless let me point out that one of the biggest gotchas if you use a loop in the form of:
for (var attr in obj) { ....
Is that the object could be cluttered with properties you did not necessarily add, and the standard solution to this as I recall is to additionally use the test for hasOwnProperty, see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Object/hasOwnProperty
It comes down to that, or keeping count when you add and delete properties from the object.
unfortunately there isn't really a good way to know the number of properties in an object without iterating over them. The following is fairly simple though:
function countProps(obj) {
var l = 0;
for (p in obj) l++;
return l;
}
var bob = { a: 1, b: 2};
alert(countProps(bob));

Categories

Resources