jquery idiomatic early return from loop - javascript

I find myself writing this on multiple occasions:
{ someJQueryCallback: ->
keepGoing = true
$(someSelector).each ->
unless someCondition($(#))
keepGoing = false
return false
return false unless keepGoing
moreStuff()
}
Of course, the first time, I made the rookie mistake everyone makes:
{ someJQueryCallback: ->
$(someSelector).each -> return false unless someCondition($(#))
moreStuff()
}
Ah, the perils of pretty syntax for functions. As a rookie, I forgot that in that scope, return would exit from each and not from someJQueryCallback. But really, even though I'm "enlightened" now, this is still the code I want to write. I want to somehow specify "pop up the stack until you've returned from someJQueryCallback." It's annoying to initialize and set and check a bool flag. It adds cruft. Is there an idiomatic way to return higher up the call stack in this way?

I don't use coffeescript so this may not be perfect, but hopefully it gives you an idea:
{ someJQueryCallback: ->
try
$(someSelector).each ->
throw new Error("STOP!") unless someCondition($(#))
moreStuff()
catch error
return false;
}

Related

Does JavaScript automatically skip empty/bodiless functions?

"tl;dr" included
When trying to disable Logging so as to avoid spam once deploying, I used to do something like
if (isDebug)
console.log(...);
but I felt like (or read online) this would slow the code overall because the condition would be evaluated each time (and I usually include a lot of these, and the functions are called often, either via loops, setIntervals or w/e).
As such, I now switched to simply "emptying" the functions using a custom logger like
function LOGGER_MODULE_FACTORY() {
let current_log_level = "log";
return {
log: console.log,
info: console.info,
warn: console.warn,
error: console.error,
setDebug: function(logLevel) {
current_log_level = logLevel;
this.log = (logLevel === true || logLevel === "log") ? console.log : function () {};
this.info = (logLevel === true || logLevel === "log" || logLevel === "info") ? console.info : function () {};
this.warn = (logLevel === true || logLevel === "log" || logLevel === "info" || logLevel === "warn") ? console.warn : function () {};
this.error = (!logLevel) ? function () {} : console.error;
return logLevel;
},
getCurrent_log_level: function () { return current_log_level; }
}
}
Thinking that it would probably be quicker to run an empty function than evaluating an expression and it felt cleaner to write.
I tried creating a fiddle to test my theory and compare performance but the values are often pretty random...
Edit: jsperf test
Interesting results. "Chrome 64" 's results are from running in on Edge.
My reasoning relied on the fact that I read few things about CPUs and, apparently, they do things on their own in order to optimize the general run-time like, for instance, skipping useless operations: Say we have :
a = x
b = y
c = a + 3
The CPU would actually ignore the second line (or something... I am far from being an expert ahah, I just curiously read that fact).
Now, since we, on our browser, may access any globally declared variable at some point using the console, this cannot happen and so I felt I should simply ask online :
tl;dr:
Is calling an empty/bodiless function repeatedly (the pages I create basically run 24/7 on a dashboard) better, performance-wise than placing a condition in front of the original function (console.log / info / warn / error) ?
Basically, you are asking which is faster f = () => {}; f() or flag = false; if (flag) f()
isDebug won't be evaluated at every execution, but the stored variable will just be read.
It would be different if it was if (isDebug()), in this case, every time the parser meets the statement, the function will be evaluated.
Obviously, reading the isDebug boolean variable will add some overhead, but this is not perceptible since reading and handling variable is the main purpose of a programming language, so the time required for reading a boolean will always be lower than any other statement in the code.
Reassigning the console.log function is not a bad idea, it could be useful for enabling or disabling the logs all in one point. But this is a solution for a different problem

Should I return a method call like console.log()?

Good day everyone. I haven't found any research or articles regarding this. Maybe I was using the wrong search terms. but my question was lets say for example that I am writing a small utility library in JavaScript for myself and I want to include 2 small functions out(arg) and outln(arg). My question is should i simply call console.log() or return console.log().
I've seen it done both ways but never saw a reason to return a method call. I was wondering which way is better or does it make a difference at all?
EX.
// This way:
var lib = {
out: function(args){
console.log(args);
},
outln: function(args){
console.log(args + "\n");
}
};
// Or this way?
var lib = {
out: function(args){
return console.log(args);
},
outln: function(args){
return console.log(args + "\n");
}
};
Do you have any use for the return value from console.log (which is always undefined anyway iirc ) ? You might plan to override log or create your own console object, though (not recommended).
More important, check for the presence of the console object and the log method, as some user agents have been known not to provide them:
var lib = {
out: function(args) {
if (console && console.log) {
console.log(args);
}
},
outln: function(args) {
if (console && console.log) {
console.log(args+"\n");
}
}
}
Promoting robustness, test this way instead of once during your lib's initialization and setting a global ( you might even consider to add the test to your lib if you have a use case, eg. users/code tampering with the console object ).

How to Test an optional member of an object?

What is the best technique to test an optional object member. Right now we are prefacing the expect statements with an if:
if(object.member) expect(object).to.have.a.property('member').that.is.a('string');
but there must be a method that is more inline stylistically. E.g.
expect(object).to.have.an.optional.property('member').that.is.a('string');
or (adding would as an empty chain, for readability):
expect(object).to.have.an.optional.property('member').that.would.be.a('string');
or (moving the optional to provide an alternative version of expect):
optionally.expect(object).to.have.a.property('member').that.is.a('string');
update - I started to write this code (new to chai) to see if I could accomplish what I was targeting, so I added a small plugin:
module.exports = function(chai, utils) {
var Assertion = chai.Assertion
, i = utils.inspect
, flag = utils.flag;
var OPTIONAL_FLAG = 'chai-optional/option'
Assertion.addProperty('optional', function() {
flag(this, OPTIONAL_FLAG, true)
return this;
})
Assertion.overwriteMethod('property', function (_super) {
return function assertProperty (propertyName) {
if (flag(this, OPTIONAL_FLAG)) {
flag(this, OPTIONAL_FLAG, false) ;
var obj = this._obj;
var isPropertyPresent = (obj[propertyName]) ? true : false ;
if(isPropertyPresent) {
return _super.apply(this, arguments);
}
} else {
_super.apply(this, arguments);
}
};
});
Assertion.addProperty('would', function () {
return this;
});
};
WIth usage:
it('could be null or have a value', function(done){
var objWithout = {}
var objWith = {}
objWith.someProperty = 'blah'
expect(objWith).to.have.optional.property('someProperty').that.would.be.a('string');
expect(objWithout).to.have.optional.property('someProperty').that.would.be.a('string');
return done();
})
The current problem even when the property isn't present, the control of the function ends - but the evaluation chain continues. I need to end the evaluation with out a failing assertion - is this possible?
update either solution (simplistic solution):
var either = function(firstCondition){
var returnObject = {}
try{
firstCondition()
returnObject.or = function(secondCondition){ return }
} catch(e) {
returnObject.or = function(secondCondition){ return secondCondition() }
}
return returnObject ;
}
module.exports = either
I think the implementation is a little clunky - but fat arrow functions will hap thin out some of the syntax. So here is waiting on that!
The current problem even when the property isn't present, the control of the function ends - but the evaluation chain continues. I need to end the evaluation with out a failing assertion - is this possible?
After having read about chai's plugin guide I would have used a similar approach with a flag. However, I have reached the same conclusion - you cannot simply stop a chain.
A possibility I though of would be not only to implement new properties and a new flag, but to overwrite the assert method itself - to not throw when the OPTIONAL_FLAG flag on the current Assertion object is set. However, the chance to destroy everything or to miss an edge case is too hight.
After all, I don't think it's a good idea. Citing from this "confusing syntax" issue:
I think the misunderstanding comes from your expectation that Chai
follows most/all English grammar rules. Unfortunately, English grammar
has way too many rules (and exceptions to those rules) for it to be a
reasonable undertaking to implement.
The challenge with designing Chai's chain-able assertions is finding
the balance between being expressive and concise. Even if full grammar
wasn't a daunting task to implement and document, it would make the
API less concise, which is not good for a testing environment.
RULE: Any "flag" which modifies the behavior of an assertion (negation
not or inclusion include/contain , etc...), once set to true
should remain true until the end of the chain.
This means it is impossible to implement something like an .or operator as well.
What is possible though would be to implement something like
either(function(){
expect(object).not.to.have.a.property('member');
}).or(function(){
expect(object).to.have.a.property('member').that.is.a('string');
});
Maybe one can build a more appealing syntax on that.

Understanding JS try and catch statements (for adding a custom Modernizr test)

I'm currently using two Modernizr tests combined to provide a convenience feature fork. The two Modernizr tests I'm employing are 'blob' and 'SMIL'.
However, as I'm only using these two tests in my Modernizr build for this convenience I want to combine the tests into a single custom test that has a more meaningful name. For example:
;(function enhancedTest() {
Modernizr.addTest('enhanced', function () {
try {
return !!new Blob();
return !!document.createElementNS &&
/SVGAnimate/.test(toStringFn.call(document.createElementNS('http://www.w3.org/2000/svg', 'animate')));
} catch (e) {
return false;
}
}, {
aliases: ['enhanced']
});
})();
I basically want the test to fail if the device does not support either of the return parts inside the try . If the device supports both, it should pass.
I've never written anything with try and catch before and I wondered whether this will work as I expect?
My concern is that currently, if it succeeds on the first return !!new Blob() it will pass the test (even though it may fail on the second part).
Is this the case? Or how should I refactor the code to achieve my goal?
My concern is that currently, if it succeeds on the first return !!new Blob() it will pass the test (even though it may fail on the second part).
You are right.
Try:
Modernizr.addTest(
'enhanced',
function() {
try {
new Blob(); // this line can throw an exception.
return !!document.createElementNS && /SVGAnimate/.test( toStringFn.call( document.createElementNS('http://www.w3.org/2000/svg', 'animate') ) );
} catch(e) {
return false;
}
}
);

coffeescript always returns

So I have what's probably a stupid question to ask about Coffee Script. I'm giving it a second chance but why does it return everything?
Is it anything to do with being the last statement/line of the function? and how do I disable this? Putting a comment or something as the final "expression", I know it's a "documented" feature but no; no it's not really, how do I not have returns everywhere? and save download/execution times?
Surely this behaviour kind of screws the jit over?
(locate =
getPosition: () ->
# Check we support geolocation
throw Exception 'Your browser doesn\'t support location based services!' if !navigator.geolocation
navigator.geolocation.getCurrentPosition (pos) ->
console.log pos
)
Compiles to
(function() {
var locate;
locate = {
getPosition: function() {
if (!navigator.geolocation) {
throw Exception('Your browser doesn\'t support location based services!');
}
return navigator.geolocation.getCurrentPosition(function(pos) {
return console.log(pos);
});
}
};
}).call(this);
[Edit]
The reason I care is this is just one of a very large library for an app I've built, if we say there's 500 functions and 200 of those do something to the dom instead of return something like a number or object, that extra 200 returns is an extra 1.2k of data I don't want or need.
Also, a function with no return, returns undefined and a function that returns null well, no need to explain that. If I was stupid enough to check this, it'd be wrong across the board.
I'm sure there would be some perf differences but I don't know about that and right now I don't have time to do some jsperfs but I'd be interested.
Yes coffeescript will always return the last line of the function. It can do this since everything in coffeescript is an expression.
From the docs:
Everything is an Expression (at least, as much as possible)
You might have noticed how even though we don't add return statements to CoffeeScript functions, they nonetheless return their final value. The CoffeeScript compiler tries to make sure that all statements in the language can be used as expressions. Watch how the return gets pushed down into each possible branch of execution in the function below.
Their example can be seen here
You can still do short-circuit returns with the return statement
Even though functions will always return their final value, it's both possible and encouraged to return early from a function body writing out the explicit return (return value), when you know that you're done.
It is because it's the last statement/line of the function, yes. By default, functions in CoffeeScript always return a value. This isn't normally a bad thing, but you can just add a return line if you really don't want to return anything.
If you want to return something specific, you can just make that the last line of your function:
(locate =
getPosition: () ->
# Check we support geolocation
throw Exception 'Your browser doesn\'t support location based services!' if !navigator.geolocation
navigator.geolocation.getCurrentPosition (pos) ->
console.log pos
'Return this string'
return
)
JS:
var locate;
locate = {
getPosition: function() {
if (!navigator.geolocation) {
throw Exception('Your browser doesn\'t support location based services!');
}
navigator.geolocation.getCurrentPosition(function(pos) {
console.log(pos);
return 'Return this string';
});
}
};

Categories

Resources