A previous poster asked Function.bind vs Closure in Javascript : how to choose?
and received this answer in part, which seems to indicate bind should be faster than a closure:
Scope traversal means, when you are reaching to grab a value
(variable,object) that exists in a different scope, therefore
additional overhead is added (code becomes slower to execute).
Using bind, you 're calling a function with an existing scope, so that
scope traversal does not take place.
Two jsperfs suggest that bind is actually much, much slower than a closure.
This was posted as a comment to the above
And, I decided to write my own jsperf
So why is bind so much slower (70+% on chromium)?
Since it is not faster and closures can serve the same purpose, should bind be avoided?
Chrome 59 update: As I predicted in the answer below bind is no longer slower with the new optimizing compiler. Here's the code with details: https://codereview.chromium.org/2916063002/
Most of the time it does not matter.
Unless you're creating an application where .bind is the bottleneck I wouldn't bother. Readability is much more important than sheer performance in most cases. I think that using native .bind usually provides for more readable and maintainable code - which is a big plus.
However yes, when it matters - .bind is slower
Yes, .bind is considerably slower than a closure - at least in Chrome, at least in the current way it's implemented in v8. I've personally had to switch in Node.JS for performance issues some times (more generally, closures are kind of slow in performance intensive situations).
Why? Because the .bind algorithm is a lot more complicated than wrapping a function with another function and using .call or .apply. (Fun fact, it also returns a function with toString set to [native function]).
There are two ways to look at this, from the specification point of view, and from the implementation point of view. Let's observe both.
First, let's look at the bind algorithm defined in the specification:
Let Target be the this value.
If IsCallable(Target) is false, throw a TypeError exception.
Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.
...
(21. Call the [[DefineOwnProperty]] internal method of F with arguments "arguments", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false.
(22. Return F.
Seems pretty complicated, a lot more than just a wrap.
Second , let's see how it's implemented in Chrome.
Let's check FunctionBind in the v8 (chrome JavaScript engine) source code:
function FunctionBind(this_arg) { // Length is 1.
if (!IS_SPEC_FUNCTION(this)) {
throw new $TypeError('Bind must be called on a function');
}
var boundFunction = function () {
// Poison .arguments and .caller, but is otherwise not detectable.
"use strict";
// This function must not use any object literals (Object, Array, RegExp),
// since the literals-array is being used to store the bound data.
if (%_IsConstructCall()) {
return %NewObjectFromBound(boundFunction);
}
var bindings = %BoundFunctionGetBindings(boundFunction);
var argc = %_ArgumentsLength();
if (argc == 0) {
return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
}
if (bindings.length === 2) {
return %Apply(bindings[0], bindings[1], arguments, 0, argc);
}
var bound_argc = bindings.length - 2;
var argv = new InternalArray(bound_argc + argc);
for (var i = 0; i < bound_argc; i++) {
argv[i] = bindings[i + 2];
}
for (var j = 0; j < argc; j++) {
argv[i++] = %_Arguments(j);
}
return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
};
%FunctionRemovePrototype(boundFunction);
var new_length = 0;
if (%_ClassOf(this) == "Function") {
// Function or FunctionProxy.
var old_length = this.length;
// FunctionProxies might provide a non-UInt32 value. If so, ignore it.
if ((typeof old_length === "number") &&
((old_length >>> 0) === old_length)) {
var argc = %_ArgumentsLength();
if (argc > 0) argc--; // Don't count the thisArg as parameter.
new_length = old_length - argc;
if (new_length < 0) new_length = 0;
}
}
// This runtime function finds any remaining arguments on the stack,
// so we don't pass the arguments object.
var result = %FunctionBindArguments(boundFunction, this,
this_arg, new_length);
// We already have caller and arguments properties on functions,
// which are non-configurable. It therefore makes no sence to
// try to redefine these as defined by the spec. The spec says
// that bind should make these throw a TypeError if get or set
// is called and make them non-enumerable and non-configurable.
// To be consistent with our normal functions we leave this as it is.
// TODO(lrn): Do set these to be thrower.
return result;
We can see a bunch of expensive things here in the implementation. Namely %_IsConstructCall(). This is of course needed to abide to the specification - but it also makes it slower than a simple wrap in many cases.
On another note, calling .bind is also slightly different, the spec notes "Function objects created using Function.prototype.bind do not have a prototype property or the [[Code]], [[FormalParameters]], and [[Scope]] internal properties"
I just want to give a little bit of perspective here:
Note that while bind()ing is slow, calling the functions once bound is not!
My test code in Firefox 76.0 on Linux:
//Set it up.
q = function(r, s) {
};
r = {};
s = {};
a = [];
for (let n = 0; n < 1000000; ++n) {
//Tried all 3 of these.
//a.push(q);
//a.push(q.bind(r));
a.push(q.bind(r, s));
}
//Performance-testing.
s = performance.now();
for (let x of a) {
x();
}
e = performance.now();
document.body.innerHTML = (e - s);
So while it is true that .bind()ing can be some ~2X slower than not binding (I tested that too), the above code takes the same amount of time for all 3 cases (binding 0, 1, or 2 variables).
Personally, I don't care if the .bind()ing is slow in my current use case, I care about the performance of the code being called once those variables are already bound to the functions.
In my application,I need to do some iteration with the array-like object.
So I write a custom util method:
Util.forEach=function(iterator,callback,context){
if(iterator.length){
for(var i=0;i<iterator.length;i++){
var val=iterator[i];
callback && callback.call(context||null,val,i);
}
}
}
Then I meet some problems:
Suppose I have an array: var ary=[1,2,3,4,5];
1. how to break the loop?
For example, if I want to find if value '2' is included in the array,I may try this:
Util.forEach(ary,function(value,index){
if(value==2){
//find mached value,now I should break and return this value.
//but I can not use 'break' in this context.
}
});
2. remove value of the array when iterator
If I want to remove value '2' of the array,I may try this:
Util.forEach(ary,function(value,index){
if(value==2){
//delete it.
ary.splice(i,1);
// I wonder if this is the safe way?
}
});
Since in java we can not do this when iterate an array,it will cause the concurrency exception.
Though I run the above code without any error,but I am not sure if it is the best practice?
Generally, you can break out from a forEach-like method by using try-catch and throw.
var value = 'Not Found';
try {
Util.forEach(ary, function(value, index) {
if(value == 2) {
throw value; //<-- Throw the found result: Terminates current forEach
}
});
} catch (found) { // Catch the thrown result
value = found;
}
The first issue can be solved by checking the return value from the callback and stopping the iteration if it returns false. Then you can stop the iteration by returning false from the callback. Returning anything other than false (including returning nothing) will continue the iteration. jQuery uses this return value technique to cancel the iteration in their .each() iterator. Adding that into your code, it would look like this:
Util.forEach=function(iterator,callback,context){
if (iterator.length && callback) {
for(var i = 0; i < iterator.length; i++){
var val=iterator[i];
if (callback.call(context||window,val,i) === false) {
break;
}
}
}
}
In the MDN documentation for forEach, you can see a sample implementation.
On the second issue, this type of implementaation does not permit insertion or deletion of elements at or before the iteration point because that will cause some elements to get skipped in the iteration or some objects to get iterated multiple times. The obvious way around that would involve making a copy of the object before iterating which is not efficient when not needed.
how to break the loop?
You're not supposed to break from forEach. That's why it's called "for each", and not "for some". "Breakable" JS iterators are every() (stops when the callback returns false) and some() (stops when the callback returns true).
Looking at your code once again it makes me think you actually want an indexOf kind of method, and not an iterator.
remove value of the array when iterator
Iterators shouldn't make any changes of the underlying array. You have to implement filter() and use it to generate a new array.
See js iteration methods for more details.
I have a JavaScript function that takes two required parameters and then arbitrarily many optional parameters.
function myFunction(required1, required2) {
var more = [];
for (var i = 2; i < arguments.length; ++i)
more.push(arguments[i]);
// ...
}
Now, I like enforcing a consistent style through all my code. Since my site uses jQuery, and jQuery favors using $.each and $.map over explicit loops, I want to get rid of the explicit loop in myFunction. However, I cannot use either $.each or $.map because I don't want to copy the whole argument list, lest I do the following:
var more = $.map(arguments, function(argument, index) {
return (index < 2) ? null : [argument];
});
Which is, of course, a very bad idea, because testing whether index < 2 in every iteration is unnecessary.
I would really like to be able to extract a subset of the arguments object into a new array, using a standard function. However, because arguments is not an array, I cannot slice it.
Is there any other way I could extract into an array all arguments but the two first ones, without using an explicit loop, and without losing efficiency?
Using the slice method:
var optional_arguments = Array.prototype.slice.call(arguments, 2);
We have to call it from Array.prototype because, even though arguments is array-like, it doesn't actually have a slice method.
The arguments of a function can be treated like an array with jQuery, for instance the following works perfectly fine:
function something(ar1,ar2){
var args = $(arguments).slice(2);
$(args).each(function(i){
$('#stuff').append(args[i]+'<br />');
});
}
$(function(){
something('one','two','three','four');
});
And to tailor it to your function above it would look like this:
function myFunction(required1, required2) {
var more = [];
var args = $(arguments).slice(2);
$(args).each(function(i){
more.push(args[i]);
});
}
https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Object/watch
The .watch() method does this in short: "Watches for a property to be assigned a value and runs a function when that occurs."
Long descriptive form: "Watches for assignment to a property named prop in this object, calling handler(prop, oldval, newval) whenever prop is set and storing the return value in that property. A watchpoint can filter (or nullify) the value assignment, by returning a modified newval (or by returning oldval)."
There is a question for getting it to work in all browsers here: Object.watch() for all browsers?
I am looking for something similar to that. What I'm looking for is a method I can use to fit this specification: "Watches for assignment to any property in this object and runs a function when that occurs." The main difference is that it is any property, and just any specific property.
Can somebody create such a method or if they know such a method is already in existence, link to it? It'd be useful to have it work in all browsers (minus IE, or minus IE8 if IE9 conforms)
Edit: For an example of what I mean, I'll show what I need it for.
var DiscreteLine = function (leftBound, length){
this.positive = [];
this.negative = [];
this.length = length;
this.leftBound = leftBound;
this.rightBound = leftBound + length
if (this.leftBound < 0){
this.negative.length = (leftBound * -1) + 1;
} else {
this.negative.length = 0;
}
if (this.rightBound >= 0){
this.positive.length = rightBound + 1;
} else {
this.positive.length = 0;
}
this.watchObject = new ObjectWatcher(handler(prop, oldval, newval){ /* some stuff */ });
}
Then, when for example, if somebody did the following:
theLine = new DiscreteLine(-2, 4);
theLine[-8] = 10;
The handler would call, with the arguments ("-8", undefined, 10). (What would end up happening is, is that the script would recalculate leftBound and length properties automatically (like how Arrays automatically update the length property).
This would basically require overriding the setter for a property of an already defined object. As far as I know, this is only possible in ECMAScript 5 (via Object.defineProperty) and at the moment, I'm not sure which browsers support this, if at all, so it wouldn't be "cross-browser" as you had asked.
Edit: Your example makes your requirement clear now. I'm afraid the language doesn't provide any way to be notified when new properties are added to an object. In your example, you really don't have any choice except to replace the array notation with a function call.
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")