Perhaps I missed something, but is there a better/more concise way of writing something like this:
var a=1,
b=2,
c=3;
if(a===1 && b===1 && c===1){ do something };
or
if(a===1 || b===1 || c===1){ do something };
I'm trying to keep the code small, so am not looking for iterating through arrays, etc like proposed in pages I've come across. I would think that there would be something (at least for the first example where they are all the same) that would look like
if(a=b=c===1){ do something? };
Thanks!
You can take a functional approach, and create a simple comparison function generator:
function eq(val) {
return function(x) {
return x === val
}
}
And then use .every for the &&:
if ([a,b,c].every(eq(1))) {
// all were equal
}
Or use .some for the ||:
if ([a,b,c].some(eq(1))) {
// at least one was equal
}
You could also create a function that receives the result of a condition and a function to invoke when the condition was true:
function when(cond, fn) {
if (cond)
fn.call.apply(fn, [].slice.call(arguments, 2))
}
And encapsulate your if body into a function...
function doIt(arg1, arg2) {
console.log("doing it!")
console.log(this, arg1, arg2)
}
Then use it like this:
when([a,b,c].every(eq(1)), doIt, null, "foo", "bar")
The third argument to when sets the this value of the callback, and subsequent arguments are passed as arguments to the callback.
No, there isn't. You have to check them individually. JavaScript just doesn't have an operator for what you're trying to do.
Your if(a=b=c===1){ ... (which I realize was just an example) would set a and b to be true (if c===1) or false (if it didn't) and then branch based only on c===1.
I mean, for that specific case, there are a couple of math approaches, but in the general case, no.
Depending on how much you want to invest, that would be a possible solution:
var slice=Function.call.bind([].slice)
var checkCondition=function(condition){
return function(){
return slice(arguments).reduce(function(o,n){
return o && o == condition(n);
},true);
}
}
greater5=checkCondition(function(x){ return x>5; });
console.log(greater5(4,7));
If you only have one or two times in your code where you have to check multiple variables it would be absolutely overkill. But if you have multiple places with varying arguments, it might help.
You could easily define new checks by definition of another function and add as many variables as you want.
Related
Let's have a function call
function doSomethingAndInvokeCallback(callback){
// do something
callback();
}
I can check if given argument is function if(typeof callback == 'function')
How can I discover, if given callback function is function and isn't empty?
like
doSomethingAndInvokeCallback(function(){
//nothing here
})
There is no totally reliable way to know if a function is empty because there are multiple kinds of functions in JS, some implemented with JS and some implemented with native code and you can't know for sure whether the function passed in does anything or not. If you want to limit the passed in function to only very simple JS functions, you could use the mechanisms outlined by other answers here (examining the source of the function). But, I would not recommend doing that in anything but a tightly controlled situation because there are lots of legal javascript ways to break that.
I would suggest that you should change the contract of your function arguments and have the caller pass null or not pass anything (which will make the argument undefined) rather than an empty function. Then, it will be very clear whether they intend to have a function called or not. If they then pass an empty function instead of null or undefined, they are getting the behavior that the interface of the function specifies. The caller can choose the desired behavior and you can implement your function in a more failsafe manner.
Also, one of your main suppositions in your question is not quite right. You cannot safely use typeof x == "function" to determine if something is a function as that will not work reliably in some older versions of IE for some types of functions. If you want to learn how to detect if something is a function at all, you can learn from jQuery here (even if you're not using it). jQuery has a function it uses internally all the time called jQuery.isFunction() that returns a bool. It uses that mostly for testing arguments to see if a function was passed.
Internally, it calls:
Object.prototype.toString.call(o)
and then examines the result. If the result has "Function" in it, then test test parameter is a function.
So, using the same technique used in jQuery, you could build your own simple little isFunction routine like this:
function isFunction(test) {
return(Object.prototype.toString.call(test).indexOf("Function") > -1);
}
Of course, if you have jQuery available, you could just use it's own version:
jQuery.isFunction(o)
When there are questions with potential cross browser compatibility issues, I find it instructional to look at how one of the big libraries solves the issue, even if you aren't going to be using that library. You can be sure that the libraries have been vetted against many browsers so a technique they are using is safe. You sometimes have to unwrap all their own internal routines they may use to figure out what they're really doing (which was the case for this function), but you can save yourself a lot of legwork.
You can see a working test bed for this here: http://jsfiddle.net/jfriend00/PKcsM/
In modern browsers typeof fn === "function", but in older versions of IE, some functions give a typeof === "object" which is probably why jQuery uses this other method which does work in those older versions of IE.
It seems that you can define a function to retrieve the body of a function(1). I wrote a small (non-definitive) test of this:
http://jsfiddle.net/6qn5P/
Function.prototype.getBody =
function() {
// Get content between first { and last }
var m = this.toString().match(/\{([\s\S]*)\}/m)[1];
// Strip comments
return m.replace(/^\s*\/\/.*$/mg,'');
};
function foo() {
var a = 1, b = "bar";
alert(b + a);
return null;
}
console.log(foo.getBody());
console.log(foo.getBody().length);
One possibility is matching the .toString result against a regexp to get the function body, and then trim to check whether it has become an empty string:
var f = function foo() {
};
/^function [^(]*\(\)[ ]*{(.*)}$/.exec(
f.toString().replace(/\n/g, "")
)[1].trim() === ""; // true
That ugly regexp does take care of spaces aroung named functions as well as extraneous spaces before the name and the opening brace. Spaces like in foo () do seem to be removed, so there is no reason to check for those.
You might be able to get this from .toString():
var blank = function(){};
var f = function(){};
var f2 = function() { return 1; };
f.toString() == blank.toString(); // true
f2.toString() == blank.toString(); // false
but this is really prone to error:
var blank = function(){};
var f = function(){ }; // extra space!
f.toString() == blank.toString(); // false
You could munge the strings a bit to try to overcome this, but I suspect this is very browser-dependent. I wouldn't actually try to do this in a production environment if I were you. Even if you normalize the whitespace, it still won't catch other no-op lines, including comments, useless var statements, etc. To actually address these issues, you'd probably need a whole tokenizer system (or a crazy regex).
You can't do it for a host function, but for others, you can fairly reliably do
function isEmpty(f) {
return typeof f === "function" &&
/^function[^{]*[{]\s*[}]\s*$/.test(
Function.prototype.toString.call(f));
}
This isn't efficient, but major interpreters implement toString for functions in such a way that it works, though it will not work on some interpreters for some empty-ish functions
function () { /* nothing here */ }
function () { ; }
function () { return; }
In some implementation you can just do a toString() on the function and get it's content. Though it contains comments etcetera.
var foo = function(){ /* Comment */ };
alert(foo.toString());
If I have a simple lodash chain that maps then filters an array:
lodash.chain(myarray)
.map(item=>{
if (item === 'some-condition') return [item];
})
.filter(item=>!!item)
.value();
Obviously, this is a made-up example but it relates to something simple I do all the time. Basically, a array map where some maps are not possible so 'undefined' is returned. I then filter-out all the undefined values.
Since, it is used quite lot, it makes sense to mixin it into my lodash.
So:
const lodash = _.runInContext();
function mapFilter(ary, iterator) {
return lodash.chain(ary)
.map(iterator)
.filter(item=>!!item)
.value()
}
lodash.mixin(lodash, mapFilter, {chain:true});
Obviously, we could just do the whole thing without lodash but normally, it might be part of a bigger chain. In theory, the lazy-evaluation makes it quicker.
What I really want is to tap into the current chain (if there is one) in my mixed-in method. Otherwise, I am losing the lazy-evaluation by calling value() twice.
So, if I had a longer chain:
lodash.chain(myarray)
.mapFilter( // do something) // my bespoke chainable method
.map( // do something else )
.sort()
.value();
I'd like to use the current chain (when there is one) in my bespoke method. Something like this:
// This is made-up and does not work!
const lodash = _.runInContext();
function mapFilter(ary, iterator) {
if (!!this.__currentChain) {
return this.__currentChain.map(iterator).filter(item=>!!item);
}
return lodash.chain(ary)
.map(iterator)
.filter(item=>!!item)
.value()
}
lodash.mixin(lodash, mapFilter, {chain:true});
Obviously, the above is made-up, but hopefully, it makes it clear what I am trying to achieve. I could of course, just not have my function and do a map() then a filter() but since I am doing it a lot, I'd like to have less typing. Also, the example could be longer, doing much more but still wanting to tap into the current chain.
Is this possible? That is my question. Obviously, I can think of a million and one alternative solutions but I am fine with those. Just looking for a lodash expert to say, "no not possible",or "yes, you do this".
I posted this as a comment but I feel that is what you would want either as a drop in or as something you need to check the source of how it is done and then code your own method or take pieces from it as part of your mixin etc.
The lodash _.tap method is there with the purpose of tap into" a method chain sequence in order to modify intermediate results so that you do not have to call value etc. You can use this as a starting point.
Hope this helps.
One of the ways to check if a function is called in a chain is to check whether this is LodashWrapper object or not. Then, use the first argument as an iterator when it's in a chain.
const _ = require('lodash');
const lodash = _.runInContext();
function mapFilter(array, iterator) {
if (this.constructor.name === 'LodashWrapper') {
return this.map(array).filter(item => !!item);
}
else {
return lodash.chain(array).map(iterator).filter(item => !!item).value();
}
}
lodash.mixin({ mapFilter }, { chain: true });
const filter = x => x == 2 ? [x] : null;
console.log(lodash.mapFilter([1, 2, 3], filter));
console.log(lodash.chain([1, 2, 3]).mapFilter(filter).head().value());
console.log(lodash([1, 2, 3]).mapFilter(filter).head());
By the way, when you use explicit _.chain, lodash doesn't apply shortcut fusion as you might expect. So you may want to use an implicit chaining. See Explicit chaining with lodash doesn't apply shortcut fusion for details.
I'm looking for a way to do the following:
$("#a" || "#b").val() === ""
as opposed to:
$("#a").val() === "" || $("#b").val() === ""
Any ideas?
Thanks in advance!
For two elements, I believe your example is about as short as you can make it and its meaning is clear. However, if you wish to repeat such logic or evaluate more elements, you might be able to improve upon it by creating a simple function to evaluate if any items in a set match a condition.
Extending jQuery
$.fn.any = function (evaluator) {
var items = $(this);
for (var i = 0; i < items.length; i++) {
if (evaluator(items[i]) === true) {
return true;
}
}
return false;
};
Demo: http://jsfiddle.net/xE76y/1/
This is similar to the Any() method implemented in the .Net LINQ library* (and I'm sure is implemented in other libraries, especially those geared towards functional programming). In c#, you would call such a method:
enumerable.Any( o => o.Value == "" );
JavaScript's syntax (sadly) isn't as concise; you end up with something like:
array.any( function(o){ return o.value === ""; } );
So far, this hasn't saved you anything. However, if you want to iterate over a large number of elements, it becomes much more elegant.
// there could be zero inputs or 100 inputs; it doesn't matter
var result = $("input").any(function (o) {
return o.value === "";
});
Native Solution
Note that we aren't relying on jQuery in our any() method. You could also consider a native JavaScript solution such as the Array.some() method.
some() executes the callback function once for each element present in
the array until it finds one where callback returns a true value. If
such an element is found, some immediately returns true.
Demo: http://jsfiddle.net/xE76y/2/
var result = jQuery.makeArray($("input")).some(function (o) {
return o.value === "";
});
Since this is an array method, it only works on an array. This unfortunately means that document.getElementsByTagName("input").some(...) will not work since getElementsByTagName() returns a NodeList.
Of course, you could push whatever you wanted into an array and call some() on that array. The call to jQuery.makeArray() in the example is just for convenience.
Abstracting the Evaluation Functions
Demo: http://jsfiddle.net/xE76y/3/
Perhaps the evaluation functions (such as testing for an empty string) will be reused. These can be abstracted further.
// ideally, this should NOT be left in global scope
function isEmpty(input) {
return input.value === "";
}
// the check now fits nicely in one line.
if ($("input").any(isEmpty)) {
alert("At least one input is empty.");
}
The resulting method calls are quite clean: $("#a, #b").any(isEmpty) and $("input").any(isEmpty)
* Also worth noting that LINQ has been recreated for JavaScript.
Try like this instead:
if ($('#a,#b').is(':empty'))
{
alert("Either a or b is Empty!");
}
Try my demo
Edit:
If it is an input type like a textbox then it would be a little bit bulky but will achieve the same effect:
if ($.inArray("",[ $("#a").val(), $("#b").val() ])>=0)
{
alert("Either a or b is Empty!");
}
See another Demo
If you want to avoid duplication of the empty string "", you could do this:
if ($.inArray([ $("#a").val(), $("#b").val() ], ""))
Or if you only want to select once with jQuery:
if ($.inArray($("#a, #b").map(function() { return this.value; }), ""))
But I wouldn't use either of these myself. They are arguably both less efficient, more contrived, and certainly less readable than the "easy" way!
I'm not an expert in javaScript, but have you cross checked with :
http://api.jquery.com/multiple-selector/
jQuery selector regular expressions
Also, one way would be using the .each function as in
jQuery Multiple ID selectors
Scenario: I'm searching for a specific object in a deep object. I'm using a recursive function that goes through the children and asks them if I'm searching for them or if I'm searching for their children or grandchildren and so on. When found, the found obj will be returned, else false. Basically this:
obj.find = function (match_id) {
if (this.id == match_id) return this;
for (var i = 0; i < this.length; i++) {
var result = this[i].find(match_id);
if (result !== false) return result;
};
return false;
}
i'm wondering, is there something simpler than this?:
var result = this[i].find(match_id);
if (result) return result;
It annoys me to store the result in a variable (on each level!), i just want to check if it's not false and return the result. I also considered the following, but dislike it even more for obvious reasons.
if (this[i].find(match_id)) return this[i].find(match_id);
Btw I'm also wondering, is this approach even "recursive"? it isn't really calling itself that much...
Thank you very much.
[edit]
There is another possibility by using another function check_find (which just returns only true if found) in the if statement. In some really complicated cases (e.g. where you don't just find the object, but also alter it) this might be the best approach. Or am I wrong? D:
Although the solution you have is probably "best" as far as search algorithms go, and I wouldn't necessarily suggest changing it (or I would change it to use a map instead of an algorithm), the question is interesting to me, especially relating to the functional properties of the JavaScript language, and I would like to provide some thoughts.
Method 1
The following should work without having to explicitly declare variables within a function, although they are used as function arguments instead. It's also quite succinct, although a little terse.
var map = Function.prototype.call.bind(Array.prototype.map);
obj.find = function find(match_id) {
return this.id == match_id ? this : map(this, function(u) {
return find.call(u, match_id);
}).filter(function(u) { return u; })[0];
};
How it works:
We test to see if this.id == match_id, if so, return this.
We use map (via Array.prototype.map) to convert this to an array of "found items", which are found using the recursive call to the find method. (Supposedly, one of these recursive calls will return our answer. The ones which don't result in an answer will return undefined.)
We filter the "found items" array so that any undefined results in the array are removed.
We return the first item in the array, and call it quits.
If there is no first item in the array, undefined will be returned.
Method 2
Another attempt to solve this problem could look like this:
var concat = Function.prototype.call.bind(Array.prototype.concat),
map = Function.prototype.call.bind(Array.prototype.map);
obj.find = function find(match_id) {
return (function buildObjArray(o) {
return concat([ o ], map(o, buildObjArray));
})(this).filter(function(u) { return u.id == match_id })[0];
};
How it works:
buildObjArray builds a single, big, 1-dimensional array containing obj and all of obj's children.
Then we filter based on the criteria that an object in the array must have an id of match_id.
We return the first match.
Both Method 1 and Method 2, while interesting, have the performance disadvantage that they will continue to search even after they've found a matching id. They don't realize they have what they need until the end of the search, and this is not very efficient.
Method 3
It is certainly possible to improve the efficiency, and now I think this one really gets close to what you were interested in.
var forEach = Function.prototype.call.bind(Array.prototype.forEach);
obj.find = function(match_id) {
try {
(function find(obj) {
if(obj.id == match_id) throw this;
forEach(obj, find);
})(obj);
} catch(found) {
return found;
}
};
How it works:
We wrap the whole find function in a try/catch block so that once an item is found, we can throw and stop execution.
We create an internal find function (IIFE) inside the try which we reference to make recursive calls.
If this.id == match_id, we throw this, stopping our search algorithm.
If it doesn't match, we recursively call find on each child.
If it did match, the throw is caught by our catch block, and the found object is returned.
Since this algorithm is able to stop execution once the object is found, it would be close in performance to yours, although it still has the overhead of the try/catch block (which on old browsers can be expensive) and forEach is slower than a typical for loop. Still these are very small performance losses.
Method 4
Finally, although this method does not fit the confines of your request, it is much, much better performance if possible in your application, and something to think about. We rely on a map of ids which maps to objects. It would look something like this:
// Declare a map object.
var map = { };
// ...
// Whenever you add a child to an object...
obj[0] = new MyObject();
// .. also store it in the map.
map[obj[0].id] = obj[0];
// ...
// Whenever you want to find the object with a specific id, refer to the map:
console.log(map[match_id]); // <- This is the "found" object.
This way, no find method is needed at all!
The performance gains in your application by using this method will be HUGE. Please seriously consider it, if at all possible.
However, be careful to remove the object from the map whenever you will no longer be referencing that object.
delete map[obj.id];
This is necessary to prevent memory leaks.
No there is no other clear way, storing the result in a variable isn't that much trouble, actually this is what variables are used for.
Yes, that approach is recursive:
you have the base case if (this.id==match_id) return this
you have the recursive step which call itself obj.find(match_id) { ... var result = this[i].find(match_id); }
I don't see any reason, why storing the variable would be bad. It's not a copy, but a reference, so it's efficient. Plus the temporary variable is the only way, that I can see right now (I may be wrong, though).
With that in mind, I don't think, that a method check_find would make very much sense (it's most probably basically the same implementation), so if you really need this check_find method, I'd implement it as
return this.find(match_id) !== false;
Whether the method is recursive is hard to say.
Basically, I'd say yes, as the implementations of 'find' are all the same for every object, so it's pretty much the same as
function find(obj, match_id) {
if (obj.id == match_id) return obj;
for (var i = 0; i < obj.length; ++i) {
var result = find(obj[i], match_id);
if (result !== false) return result;
}
}
which is definitely recursive (the function calls itself).
However, if you'd do
onesingleobjectinmydeepobject.find = function(x) { return this; }
I'm not quite sure, if you still would call this recursive.
In Javascript, I sometimes want to return a value from a scope that isn't the current function. It might be a block of code within the function, or it might be an enclosing function as in the following example, which uses a local function to recursively search for something. As soon as it finds a solution, the search is done and the outer function should just exit. Unfortunately, I can't think of a simpler way to do this than by hacking try/catch for the purpose:
function solve(searchSpace) {
var search = function (stuff) {
var solution = isItSolved(stuff);
if (solution) {
throw solution;
} else {
search(narrowThisWay(stuff));
search(narrowThatWay(stuff));
};
};
try {
return search(searchSpace);
} catch (solution) {
return solution;
};
};
I realize one could assign the solution to a local variable and then check it before making another recursive call, but my question is specifically about transfer of control. Is there a better way than the above? Perhaps involving label/break?
Edit: since the answers to date are variations of "ew that's bad
you're not supposed to do that", let me add some necessary
context. I'm hacking on an open-source compiler that targets
Javascript. No one is going to write this code by hand, so please
don't tell me "this is a bad programming technique". What I want is a
better code generation technique. The question is whether anyone has
any clever hack for exploiting Javascript to get more flexible control
transfer.
The reason assigning the result to a local variable and checking it is
ruled out is because that requires understanding the code in a way
that is hard for a compiler to do.
It seems I stand corrected on the intent of the question. If statements are are a useful and readable way to structure code and make it flow however you want to. There's a reason goto was taken out of so many languages, because you don't need it. And it seems like, based on your example code, you're using a try-catch block as a form of goto. If you don't want certain things to run then use if statements or equivalents:
function solve(searchSpace) {
function search = function (stuff) {
//|| will only return the first value if that value is truthy, subsequent values will be ignored
return isItSolved(stuff) || (search(narrowThisWay(stuff)) || search(narrowThatWay(stuff)));
};
return search(searchSpace);
};
I know of no way to break out of function calls like you want. You can break out of loops using labels, but it doesn't seem that's much help to your situation. Other than that, I don't think JavaScript has any such ability beyond your use of exceptions
function solve(stuff) {
return isItSolved(stuff) || solve(narrowThisWay(stuff)) || solve(narrowThatWay(stuff));
}
Bob's way is good... exept that he uses twice the function statement (and that he uses ; after a function delaration without an assignment)... and that as we can do it that way, function solve actually is function search.
PS : This code will epically fail if the isItSolved, narrowThisWay or narrowThatWay functions can return a value evaluated to false as a positive result. In this cas, you would have to use ? : statement in order to check if all responses are !== undefined.
PS2: And of ourse, if these function can send an error, you have to catch it...
It looks like you're doing a fairly straightforward recursive search in your example. Why not just use "return"?
function solve(searchSpace) {
var search = function (stuff) {
var solution = isItSolved(stuff);
if (solution) {
return solution;
} else {
solution = search(narrowThisWay(stuff));
if (solution) {
return solution;
}
return search(narrowThatWay(stuff));
};
};
return search(searchSpace);
};
I suppose it could be that there are other constraints you haven't mentioned, but it's in general possible to turn any control flow into a set of nested (or recursive) functions, with appropriate return values.
The cleanest way would be to use a continuation, but you don't have that efficiently in JS (a few JS engines support continuations, but for the rest there's only CPS, which cries out for tail calls). In C, you could use setjmp/longjmp. In Common Lisp, you could use conditions (which include the functionality of exceptions plus much more). In JS, exceptions are the only non-local control flow option you have available.
You can programmatically transform a program into another that uses CPS.
function solve(searchSpace, isItSolved, isBase, narrowThisWay, narrowThatWay) {
function search(stuff, k) {
solution = isItSolved(stuff);
if (solution) {
return solution;
} else if (isBase(stuff)) {
return k();
} else {
return search(narrowThisWay(stuff), function() {
return search(narrowThatWay(stuff), k);
});
};
};
return search(searchSpace, function(val) {return val});
};
var arr=[1, 2,9,72,0,34,5,33,24,62,89,90,30,54,590,23,59,62,73];
solve(arr, function(a) {return (a.length==1 && a[0] == 5) ? a[0] : false;},
function (a) {return a.length < 2; },
function (a) {return a.slice(0, a.length / 2);},
function (a) {return a.slice(a.length / 2);}
);