
Making the Most of the JavaScript Language (2016) - RobBollons
http://thenorthcode.net/2016/01/15/making-the-most-of-the-javascript-language/
======
moxious
As someone who works with this every day, I'd say this is pretty solid advice.

The "use a more functional approach" and "take advantage of ES6" are by far
the biggest for me. ES6 added so much good stuff, I wouldn't consider it
optional. It's better than incremental upgrades, feels almost like a different
language to me.

Every language has its quirks, and while I'll keep on hating Javascript's,
I'll never lose sight of the fact that if you're holding out for the perfect
language, you're not going to be doing much coding.

~~~
erikpukinskis
What do you like about ES6? It just looks like syntactic sugar to me, but I'm
always interested in re-evaluating.

Writing [1,2,3].map(function(x) { return x+10 }) really doesn't bother me. I
don't see what the benefit is of an arrow function. Are there other things
that you like?

As the OP mentions, the inheritance stuff is just likely to cause architecture
headaches. I like JavaScript's concurrency model (single threaded with
callbacks) so I don't see any benefit to the async stuff.

It just seems like people added a ton of complexity to give up a few
keystrokes. Transpiling and shimming and adding more control structures make
your application more complicated, so there is a real cost. And keystrokes are
not generally a big problem when I'm programming. I'm not in a race.

~~~
geoelectric
The big deal of an arrow function, brevity aside, is that it inherits the
value of 'this' from the scope that creates it. Regular functions do not, so
to use them as first-class functions you often have to bind before passing,
pass around thisObjs for rebinding, do a 'that = this' type trick, etc.

Same goes for 'arguments', though that comes up less. Basically, they're much
more representative of a simple lambda than a classical function.

~~~
erikpukinskis
What's wrong with explicitly binding the scope? I really like that in
JavaScript you have to be explicit about that kind of thing.

~~~
geoelectric
I actually find it much more clear for this to be set at the place you see the
function defined in code--assuming you know what this is in the wrapping
scope, you know exactly what it will be in this scope. Technically a bind is
more explicit but in practice the bind tends not to happen where the function
is defined so you have to go fishing around the code path for it.

And honestly, the sugar often speaks to readability as well. Compare
myArray.every(function (x) { return x; }); with myArray.every(x => x).

~~~
erikpukinskis
The first is more readable. It uses more common tokens, and is therefore more
easily recognizable. You're confusing brevity for readability.

I don't understand your scope preference. These seem the same to me:

    
    
      family.findEldestFirst(person => this.isRoyal() && person.name == "Kate")
    

vs

    
    
      family.findEldestFirst(isPrincess.bind(family))
    
      function isPrincess(person) {
        return this.isRoyal() && person.name == "Kate"
      }
    

11 tokens vs 16, same order of magnitude. Second one has an explicit return,
which is good for readability. Shorter lines, to which is better for
readability. Also relies on fewer control structures, which is good for
readability. No need to understand the =>/-> distinction, which is very subtle
and beginners won't know about it. To me I'd rather just learn functions and
closures and be done with it.

... And frankly I think using "this" that way in either case is not a win. I'd
rather make family its own argument to isPrincess:

    
    
      family.findEldestFirst(isPrincess.bind(null, family))
    
      function isPrincess(family, person) {
        return family.isRoyal() && person.name == "Kate"
      }
    

Mm. Dat explicitness. Anyway... I think I'm not understanding you. How is this
forcing your hand in terms of where you bind the scope?

Franky, my sense is that the people who like ES6 and promises are people who
are just allergic to writing named functions. Named functions make callback
hell go away, and they solve all the problems these arrow functions do.
Somehow people think it's bad form to define lots of functions. But defining
functions is my job. :) It doesn't bother me.

My sense is it's just Rubyists who miss Ruby and think "more Rubyish" is
better. I sympathize because my path was BASIC -> PHP -> C# -> Ruby ->
JavaScript. But I think it is a mistake to try to bring your old idioms to a
new language.

... and if I wanted to reduce character count above all else, I'd just go use
PERL.

------
whatever_dude
What I can't recommend enough (and hinted at in the article) is for someone to
use a transpiler like Babel (and core-js, babel-preset-env, and etc). There's
no reason not to use many of the new features and new functions of ES2015+,
and you can do that right now even if you're targeting old browsers with
transpilation and a bit of automatic shimming.

~~~
goatlover
How does debugging in the browser console work when you use that approach?

~~~
Zyst
Normally you have mapping files which tell your browser which bits correlate
to the outputted "compiled" code.

Thus in your browser you see the code you write, you put in breakpoints as
desired, and everything generally works.

I don't have much depth as to how it all works behind the scenes though, I'd
love to know more.

~~~
daxelrod
The feature is called "source maps". Here's an MDN article about it
[https://developer.mozilla.org/en-
US/docs/Tools/Debugger/How_...](https://developer.mozilla.org/en-
US/docs/Tools/Debugger/How_to/Use_a_source_map)

------
gonzofish
JS has some seriously rough edges, but I love it because I adhere to a lot of
what the article preaches. I never end up with any gotchas because I use the
"right" parts of the language.

------
fenwick67
Classical inheritance is useful in JS sometimes, but I agree with the
sentiment of "don't use it unless you have a reason to".

~~~
jonny_eh
Ya, that part I don't agree with. Especially since he also says to use ES6
features, which includes the new class syntax, making it a lot more
straightforward to use classes + inheritance (even if it's still prototypical
under the hood).

~~~
mercer
I suppose it could be considered more 'general' programming advice, not
specific to JS. At least here on HN there seems to be a consensus that
classical inheritance more than 1 layer deep is a bad idea (correct me if I'm
wrong though, dear HN readers and writers!).

Personally I'm a huge functional programming weenie for no reason I can
coherently defend, so I prefer to avoid ES6 classes. But quite often they end
up being the most reasonable solution to my problem, and having syntax for it
is great. I just avoid them by default.

------
romanovcode
While I use `const` for a lot of my variables that I don't want to change it
feels super-super wrong.

~~~
savanaly
What feels wrong about it?

~~~
aaron-lebo
It's an incredibly verbose way to do what you'd prefer to be the default.

val or con would have been better.

~~~
WorldMaker
Going way back to ancient Lisps `let` has been the const declaration in a lot
of programming languages. It's too bad ES2015 decided to use `let` for
`var`/`val`, because `let` should have been const.

That said, I've come to terms with const, even if I find I accidentally use
let sometimes from time spent in Lisp and F#.

~~~
kazinator
_let_ is not a "const declaration" in most major dialects of Lisp, current and
historic. In Scheme, Common Lisp, ISLisp, Emacs Lisp and others, it introduces
mutable bindings.

~~~
WorldMaker
Apologies, my Common Lisp is getting rusty.

------
luord
I disagree on "avoiding classical inheritance", though I didn't drink the
functional programming kool-aid so what do I know. That aside, I like the
article, JS is my second favorite language and I'v never gotten the hate for
it. I'm glad it's improving so much.

------
Stratoscope
> Closures are a great way to maintain private variables in JavaScript but
> also seem to be a source of great misunderstanding.

Very true on both counts, but unfortunately the article perpetuates some of
this misunderstanding.

> Where it gets interesting is when you return a function from an outer
> function...

Abbreviated example from the article:

    
    
      var outer = function () {
        var a = 1;
        return function inner() {
          return a;
        };
      };
    

...and that's the only example. No mention of where closures are actually most
useful, and not a peep that you _don 't need_ a function that returns a
function to get one. Any function call can get you a closure.

I deal with this frequently on Stack Overflow. Someone asks a question where a
closure is a great solution, and then someone answers with a complicated
example involving a function that returns a function.

It seems to come up a lot in Google Maps API code:

    
    
      var places = [
        { name:"Test", lat:10, lng:10 },
        ...
      ];
    
      function initMap()
        var map = new google.maps.Map(...);
        for( var i = 0;  i < places.length;  ++i ) {
          var marker = new google.maps.Marker(...);
          // This is the complicated part:
          marker.addListener( 'click', (function( marker ) {
            return function() {
              // This works because of the closure:
              infowindow.open( map, marker );
            }
          })( marker ) );
        }
      }
    

It doesn't have to be done that way! You'll get a closure that works just as
well if you simply _call a function_ in the loop:

    
    
      function initMap()
        var map = new google.maps.Map(...);
        for( var i = 0;  i < places.length;  ++i ) {
          addMarker( places[i] );
        }
    
        function addMarker( place ) {
          var marker = new google.maps.Marker(...);
          marker.addListener( 'click', function() {
            // We have a closure here too:
            infowindow.open( map, marker );
          });
        }
      }
    

There are other ways to do this in modern JavaScript (such as using let inside
the loop). I'm using old-school JavaScript here just to show that it could be
done this simply even in the oldest browsers.

Of course, the same thing can be done with forEach():

    
    
      function initMap()
        var map = new google.maps.Map(...);
        places.forEach( addMarker );
    
        function addMarker( place ) {
          var marker = new google.maps.Marker(...);
          marker.addListener( 'click', function() {
            // We have a closure here too:
            infowindow.open( map, marker );
          });
        }
      }
    

Or with the forEach callback inline:

    
    
      function initMap()
        var map = new google.maps.Map(...);
        places.forEach( function( place ) {
          var marker = new google.maps.Marker(...);
          marker.addListener( 'click', function() {
            // We have a closure here too:
            infowindow.open( map, marker );
          });
        });
      }
    

The point in each of these cases is that you don't need a function that
_returns_ a function to get a closure, but people who answer SO questions
perpetuate this myth day after day.

------
whipoodle
Closures are so nice. Working without them makes everything so much more
difficult and inelegant.

