I personally avoid it as much as I can. I prefer functionality that creates a map of the input option to the expected result and use that directly:
function strUtil(str) { return str + ', etc.'; }
function processString(str) { switch (str) { case 'abc': return 'some value'; case 'def': return 'something else'; default: return strUtil(str); }
Instead of this, I prefer:
var STR_MAP = { abc: 'some value', def: 'something else', default: function strUtil(str) { return str + ', etc.'; } };
function processString(str) { _.result(STR_MAP, str, STR_MAP.default(str)); }
where I use _.result
Ok, so I've had a quick flick through the javascript. A few pointers...
jQuery callbacks with logic in them, are in my opinion, are a bit of an anti-pattern - it produces code that's hard to maintain because you have to infer what the meaning is by naming the code. Prefer writing good named methods like doesASpecificThing() and use your jQuery callbacks to invoke the named methods. This'll split the "what you're doing" from the "how you're invoking it" making the code easier to maintain in the future.
Use closures as namespaces to organise your code. http://addyosmani.com/blog/essential-js-namespacing/ Namespacing in javascript helps scope down global variables and organise and structure your code - again, this'll help you when you want to modify the code later - it'll make your code more readable - and it'll stop you accidentally having conflicting global variables.
Use Lo-Dash to make some of the element selection neater and more readable, exposing intent. http://lodash.com/ - Lo-Dash will help tidy up many of the loops and searching for objects in your code - again, all about intent.
Performance tuning this kind of stuff is pretty difficult, and I'd probably have to have a good long look to work out where bottlenecks are there but I'd recommend "make it work, make it readable, make it fast" - you can make readable code fast, but fast illegible code is ruined forever.
Hope that helps.
Currying is really cool, and pretty simple -- read up about it. It's mostly useful when dealing higher order functions, like map()
in the example here -- making sure that the arguments will line up to how map()
invokes the function.
depending on your browser requirements, this means debounce or RequestAnimationFrame or a requestAnimationFrame setTimeout fallback.
depending on your page and how often people are scrolling this way or that, requestAnimationFrame or debounce may be faster. The debounce method is usually better when you don't need a live-update type functionality; it ensures the event is ignored if it's within a certain timeframe of the event previously firing. This will save you some processing time if you're only worried about figuring the scroll percentage after they're done scrolling.
RequestAnimationFrame is optimized in browsers that support it, so it's called every render cycle. If you need something to be dependent on each change to an element or value, this is going to be your best option. For example, if you need to continuously update the scroll percentage to do some parallaxy type stuff, requestAnimationFrame and it's fallbacks are going to be your most performant options.
[EDIT]: Clarify some things.
Generally JavaScript compares objects (and therefore arrays) by reference. That means if you try to equate two different objects (i.e different instances) the answer is false. So {} === {} is false. What you are doing is populating liveCells[0] with an array, and asking indexOf to find a different array (albeit with the same value).
There's no simple way to do this in JS (though it's trivial to achieve if you know how). You can either write a custom function to compare the arrays deeply, or borrow a third party one, for example lodash's isEqual: http://lodash.com/docs#isEqual
I believe JSLINQ has all the stuff you would want, but if you don't like it for whatever reason, a similar JS library you can use is http://lodash.com/
anyways, in lodash you could use _.map() to join your tables however you like. In JSLINQ, I believe the equivalent function would be Select().
//trips and stopTimes initialized elsewhere
var tripsWithStopTimes = _.map(trips, function(trip){ return { //select trip_id, trip_short_name and filtered stopTimes in the results trip_id: trip.trip_id, trip_short_name: trip.trip_short_name, stopTimes: _.filter(stopTimes, function(stopTime){ return stopTime.trip_id === trip.trip_id }) }
});
hehe. One does not simply 'finish learning JS'.
jQuery is a toolkit, not a framework... in the vein of lodash or async. It's just another tool in your toolbelt. I typically use it any time I need events attached in a framework-less browser setup.
I said 'for brevity' because it's less typing... the reason I used jquery is because it's shorter, easier to wrap one's mind around. And maybe I don't like a lot of typing.
A framework is something like angular or react -- these will inform on how your code should be structured.
Then that's easy, vanilla javascript has Object.keys, for in and you can use some functions from a library like lodash
EDIT: Also see /u/freshtodev reply, there is some good info in there.
That makes sense.
You might be able to debounce the $digest
calls. Lo-dash has a good method, which would be easy to port to your application. There's also an existing Angular module for a simple function, which also might work (although, it looks like it only fires after the time limit, rather than at the beginning).
Then you could try to trigger a digest every time, but make sure it doesn't update more than n
times per second, without the messiness of using intervals or timers. This should be cleaner, code-wise, with the same functionality.
Something like this:
// The debounce module linked above var startDigest = debounce(250, function(){ // This doesn't have to do anything, because it triggers the digest automatically via $timeout(); });
// Using lo-dash var startDigest = _.debounce(function(){ // Something like this should work... $rootScope.$digest(); }, 250);
function onStuffHappened() { // ... // never called more than 4 times per second startDigest(); }
I was basing that assumption off of Lo-Dash's <code>_.curry()</code> function which says:
> Creates a function which accepts one or more arguments of func
that when invoked either executes func
returning its result, if all func
arguments have been provided, or returns a function that accepts one or more of the remaining func
arguments, and so on. The arity of func
can be specified if func.length
is not sufficient.
They run their own benchmarks in the browser so you can see for yourself.
Lazy.js is another similar library with impressive benchmarks.