Related
I saw this response for extending one array with another
so I tried:
console.log(['a', 'b'].push.apply(['c', 'd']));
but it prints:
2
shouldn't it print:
['a', 'b', 'c', 'd']
if not what was i doing wrong?
if not what was i doing wrong?
First of all, .push returns the new length of the array:
var arr = [1, 1, 1];
console.log(arr.push(1)); // 4
console.log(arr); // [1, 1, 1, 1]
Second, .apply needs two arguments: The object you want to apply the function to, and an array of arguments. You only pass a single argument, so your code is basically equivalent to:
['c', 'd'].push()
I.e. you are not adding anything to the ['c', 'd'] array. That also explains why you see 2 in the output: ['c', 'd'] has length 2 and .push() doesn't add any elements to it so it still has length 2.
If you want to use .push to mutate the original array (instead of creating a new one like .concat does), it would have to look like:
var arr = ['a', 'b'];
arr.push.apply(arr, ['c', 'd']); // equivalent to Array.prototype.push.apply(arr, [...])
// ^ ^--------^
// apply to arr arguments
console.log(arr); // ['a', 'b', 'c', 'd']
See also
How to append something to an array?
Javascript push array values into another array
If your scenario allows for ES6 syntax, you can use the spread element to concatenate arrays:
var arr1 = [1,2];
var arr2 = [3,4];
var arr3 = [...arr1, ...arr2];
console.log(arr3); // Logs [1,2,3,4]
Try this:
console.log(['a', 'b'].concat(['c', 'd']));
If you're using a modern browser then you can use the spread operator, ... like so:
console.log([...['a', 'b'], ...['c', 'd']])
If you're using an older browser/no transpiler then concat is the way to go:
console.log(['a', 'b'].concat(['c', 'd']))
As there seems to be a general misunderstanding here about the use of various array appending methods I will add to it with the safest alternative to ES6's introduction of the spread operator
Functional language
Functional languages were developed to simplify code development allowing programmers and systems engineers to define functions to replace common operations/algorithms.
JS is a functional language, you write functions to make life easier, save you typing and making the program easier to test and validate, so why fight it with dangerous alternatives .
The mistake being made in the answers (with the exception of Jonathan Michalik answer) is they are all trying to either coerce the language into doing something that should be done by a function (Function.apply), or providing a solution without explanation of what it is doing (Array.concat).
Write a function to append arrays, for example.
function appendArray(array,array1){ // adds the items in array1
// array1 can be any type
// to the end of array
var len,i;
array1 = [].concat(array1); // ensure array1 is an array
len = array1.length;
i = 0;
while(i < len){
array[array.length] = array1[i++]; // this is 2* quicker than invoking push
}
return array;
}
For the 60 seconds it takes to write, or less to include as part of a general library you have created a safe and general purpose array append function.
log(appendArray([0, 1, 2, 3], 4)); // 0,1,2,3,4
log(appendArray([0, 1, 2, 3], [4, 5, 6])); // 0,1,2,3,4,5,6
Now to why the other answers are not good solutions.
Array.concat
is the safer option, and should be used if you are in control of all references to the array. It suffers from the fact that it creates a new array when it is used.
var array1 = [1,2,3];
var array2 = [4,5,6];
array1 = array1.concat(array2); // 1,2,3,4,5,6
Many are under the mistaken belief that the concat( array2 ) is added to array1, it is not, it is added to a copy of array1. If you have other references to the original array then you end up creating a copy of the concatenated array, while the original array remains in memory.
function doSomething(array){
... generate some info
array.concat(info);
}
var myArray = [...someData]; // the array
var myObject.setArray(myArray); // create a new referance to the array in myObject
myArray = doSomething(myArray); // adds info via concat to the array.
It is not immediately apparent, but you now have two arrays the original inside myObject, and the concatenated version in myObject which may store the array referance in closure, that you can not change or delete unless you dereference all associated context. Nor do you know how many references to the original array exist.
Function.apply()
There are many reasons not to use this function but of particular note is using it on the Array.push function. It suffers from indeterminacy if you use it without type checking the arrays.
var myArray = [1,2,3,4];
var data = getSomeData(); // may return array or array like data
myArray = doSomeWorkOn(myArray); // the spec says this may return undefined
myArray.push.apply(myArray,data); // what happen here is indeterminate and
// depends on the JS context, the JS mode
// and the JS version
Without vetting myArray for undefined you can not predict what the result of apply will be. It could throw and error, or it may silently fail if the global scope has a push function and you are not in strict mode.
Without knowing the JS version ES5 or ES6 the apply may have pushed one object data onto myArray, or all the items in data ES5 does not recognise array like objects as arrays for Function.apply while ES6 does. So you must vet myArray, or data to be of the correct type for the current JS version.
Arguments have limits that are dependent on the current JS context, there is also inconsistency between JS context's handling of long argument lists. Some will throw an error, others will simply truncate the arguments.
var myPixelData = [];
myPixelData.push.apply(myPixelData,getSomePixelData()); // what will happen????
This may throw, or it may work, or it may have only pushed 65535 items onto the array, or more, or less. You will have to wrap it in a try catch, and vet the results against the length of the array returned by getPixelData. All the added complexity just to make it easier???
So why use Function.apply on Array.push or use Array.concat when it is so much easier to write a function to do what you want and save you from a long list of problems, ambiguities, and errors.
You should try this:
a= ['a', 'b'];
b= ['c', 'd'];
a.push.apply(a,b);
console.log(a);
you should use variables like so
<script type="text/javascript">
var arr1=['a', 'b'];
var arr2=['c', 'd'];
Array.prototype.push.apply(arr1, arr2);
console.log(arr1);
</script>
I don't know how to word this problem exactly but I found this extremely wired.
Basically I did this test in chrome's developer tool console.
for (var request in [0,1,2]) { console.log(request);}
0
1
2
compare
the last four lines are all outputs from the for loop.
during the for loop, request got the value compare.
I wonder if this is a bug in chrome.
for ... in ... iterates over the enumerable properties of an object, and is not intended for array indices. Array indices are also enumerable properties, but as you've discovered anything unsafely added to Array.prototype will be returned too.
To safely add a (non-enumerable) method to Array.prototype in ES5 browsers you can use Object.defineProperty, e.g.:
Object.defineProperty(Array.prototype, 'compare', {
value: function() {
...
}
});
This will stop for ... in from breaking, but it's still the wrong tool for the job when the variable of interest is an array.
You're best off using an indexed for loop.
For..in also enumerates over inherited properties etc.
var request = [0,1,2];
for (var i = 0; i < request.length; i++) {
console.log(request[i]);
}
The top answer to this question:
stackoverflow previous answer
puts it better than I could:
in your case, the global "object-prototype" as a compare function declared for it, e.g...
object.prototype.compare = function (a,b) {return a === b}
...and so, whenever you iterate an object (an array being one kind of object) you also iterate over the "compare" function of it's prototype... which is a "member" of it.
As others pointed out for .. in is not the best way to iterate thru array. If you insist on using it for some reason - use hasOwnProperty method to determine that property indeed belongs to the array:
var arr = [0,1,2];
for (var request in arr ) {
if (arr.hasOwnProperty(request)) console.log(request);
}
var primes=[2,3,5,7]
primes.sync = function(){this[0]=23;}
primes // => [2, 3, 5, 7]
primes.sync()
primes // => [23, 3, 5, 7]
This seems to work perfectly in Chrome.
Are there any reasons to not use this syntax/"feature"? Also, can I count on primes to be behave as a normal array (e.g. when passing it to a function that expects an array)?
This is why I want to use it:
Say I have a peopleList in my program. Functions all over the app will use it like an array. Then, suddenly, I do a POST to the server. I then want the array to query the server directly, and update itself. This would allow for some very elegant code in my angular.js app.
The only trouble you'll likely have will be if you (incorrectly) try to use for-in to iterate the Array. As long as you use a for statement or one of the Array iterator methods to constrain the enumeration to numeric indices, there shouldn't be any trouble.
The Array will continue to behave like a typical Array.
What you would want to do is to add a function to Array.prototype, rather than adding it to an array instance. See below.
Array.prototype.sync = function(){this[0]=23;};
This way, all array instances, including those that have been initialized before adding the function, will automatically be able to use the function at once.
var a = [];
a.sync(); // TypeError: Object [object Array] has no method 'sync'
Array.prototype.sync = function(){this[0]=23;};
a.sync();
a // [23]
var b = [1,2,3];
b.sync();
b // [23, 2, 3]
However, only add those functions that are useful/meaningful/reusable to Array.prototype because it is going to be available for all array instances ever created and will be created.
If your function is going to be used by only few instances. You are better of adding them to each instance like you did above.
Please explain usage of _.identity(value) of underscore.js. Not able to understand it from the documentation ( http://underscorejs.org/#identity ).
Can you provide some example of its usage?
A JavaScript code pattern involving identity is filtering values based on truthiness, e.g.
var a = [null, null, [1,2,3], null, [10, 12], null];
a.filter(_.identity)
yields [Array[3], Array[2]].
Using
_.compact(a)
is clearer, but one may not use lodash or underscore at all, e.g.
function identity(x) {
return x;
}
a.filter(identity)
Whether it is a good code pattern is questionable for several reasons, but it's being used in the wild.
It is not a NOOP at all. A NOOP is an imperative construct in e.g. assembly, whereas in functional programming, it is like other functions in that it returns a value. If identity were a NOOP, then all pure functions could also be considered noop, and it would not be a sensible thing.
It's essentially a no-operation function. It returns the value of whatever was passed into it.
The part about it being used as a "default iterator" within the library itself means that in other functions which may have an optional "iterator" parameter (which is likely used as a function to apply to each element of an array of some kind), if no iterator parameter is passed, the library will use this "no-op" iterator instead and the elements of the array will remain unchanged.
A specific example:
Underscore.js defines _.each and as like this.
_.each = function(obj, iterator, context) {
...
}
This iterator shows el value. You maybe have used this idiom.
_.each([1, 2, 3], function(el){
console.log(el);
});
This iterator returns el value without change.
_.each([1, 2, 3], function(el){
return el;
});
The function that returns a value without change occur frequently. So Underscore.js wants to define the function. Underscore.js names the function _.identity.
_.identity = function(value) {
return value;
};
If Underscore.js wants to use a default iterator, all Underscore.js need is call _.identity.
_.each([1, 2, 3], _.identity);
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")