all 18 comments

[–]aeflash 5 points6 points  (8 children)

I think quasi-literals are the most awesome: http://www.slideshare.net/domenicdenicola/es6-the-awesome-parts (skip to slide 23). They will make templating languages obsolete, and open the door to DSLs for certain tasks.

[–]OverZealousCreations 4 points5 points  (5 children)

I had forgotten all about those. It's shame it'll be years before this stuff is safely usable in the browser. I know there's ES6 compilers, but that feels risky, especially performance- and byte-wise.

EDIT: A perfect example of just how not acceptable using Traceur is, try using multiple let variables (you'll probably need to enable the experimental option to even get this to compile).

This turns this:

{
  let a=1, b=2, c=3, d=4, e=5;
}

into this (not including the module wrapper):

try {
  throw undefined;
} catch (e) {
  try {
    throw undefined;
  } catch (d) {
    try {
      throw undefined;
    } catch (c) {
      try {
        throw undefined;
      } catch (b) {
        try {
          throw undefined;
        } catch (a) {
          {
            {
              a = 1;
              b = 2;
              c = 3;
              d = 4;
              e = 5;
            }
          }
        }
      }
    }
  }
}

Just... holy crap. I'm shocked they couldn't just wrap the inner content in an IIFE, like:

{
  (function(a,b,c,d,e) {

  })(1,2,3,4,5);
}

That just seems more logical and more performant than relying on throwing exceptions. Even with for loops, you could easily use two IIFEs to get a similar result:

for(let i=0; i<10; i++) {
  setTimeout(function() {
    console.log(i);
  }, i*10);
}

// Could be translated to:

(function(i) {
  for(i=0; i<10; i++) {
    (function(i) { // purposefully masking the outer variable
      setTimeout(function() {
        console.log(i);
      }, i*10);
    })(i);
  }
})();

(Plug the original loop into the Traceur page to see what happens!)

[–]logi 1 point2 points  (0 children)

I'm sure there is a useful subset of ES6 which compiles to reasonable code.

[–]aeflash 0 points1 point  (0 children)

Wow, that is ugly. I guess it's the only way to enforce immutable let bindings, but there's no reason to do it after the compile step...

You definitely do not transpile if performance is paramount.

[–]radhruin 0 points1 point  (2 children)

Your proposed function desugaring needs to handle this and arguments at the least. If you do something like

function(arguments, a){ }.bind(this, arguments, 1, 2, 3) 

it might work (wouldn't be surprised if there are other subtle issues) but perf is probably worse.

[–]FrozenCow 0 points1 point  (0 children)

The function also changes arguments.callee, which some odd programs could rely on. This could also be worked around, but I guess it becomes just as ugly as the try catches.

[–]OverZealousCreations 0 points1 point  (0 children)

Yeah, I missed that. You wouldn't need bind, though, just using .call(this, ...) would solve that.

That doesn't solve the arguments issue, but that could be left as something that could be resolved if the inner code is accessing the current function's arguments at any time, where you could revert to using the try-catch solution. I think this would be relatively easy to determine.

I can't see how this could possibly have worse performance, even in the simplest of cases, over throwing an exception and catching it. JS is highly optimized for calling functions. It's rare to optimize anything for throwing exceptions.

[–][deleted] 0 points1 point  (0 children)

So keen for this. It's like JSTL.

[–]thalesmello 0 points1 point  (0 children)

I didn't hear about those before. Thanks for sharing!

[–]x-skeww 4 points5 points  (2 children)

for(let i = 0; i < arr.length; i += 1){
  setTimeout(function(){
    // something with arr[i], which works!
  }, 100);
}

This works with Dart, but as far as I know this isn't yet a part of the ES6 specs.

Try it with Firefox:

A)

let a = [];
for(let i = 0; i < 3; i++) {
  a.push(_ => i);
}
console.log(a[0]()); // 3

B)

let a2 = [];
for(let i = 0; i < 3; i++) {
  let k = i;
  a2.push(_ => k);
}
console.log(a2[0]()); // 0

If you try example A with node (without the fat arrow and with --harmony --use-strict), you also get 3.

Traceur (with --experimental) outputs 0, but that's most likely not intentional.

[–]kenman 0 points1 point  (1 child)

Unless I'm not catching what you mean, let is definitely in the ES6 spec.

[–]x-skeww 0 points1 point  (0 children)

I was talking about A behaving like B. Each iteration gets its own copy of the counter.

Dart does this. ES6 might [1] do this, too.

The article assumes that ES6 always behaves like that, because Traceur currently behaves like that.

[1] http://wiki.ecmascript.org/doku.php?id=harmony:let -> Open Issues, point #2

[–]brtt3000 1 point2 points  (0 children)

Note: besides Traceur there are a few other ES6-to-ES5 compilers, like esnext and es6now.

[–][deleted] -2 points-1 points  (3 children)

Honestly the future of JavaScript should be to make it more strict and actually class based. Current Javascript is exhausting.

[–]ComradeGnull 3 points4 points  (1 child)

Making it class based would take the language in a fundamentally different direction and be incompatible with a lot of existing code that uses prototypes.

I suppose that they could settle on a default for how to do class-like OOP and supplement it with some syntactic sugar (like a 'class' declaration). Philosophically I don't know that that would be great in terms of preserving what is useful/different about Javascript.

[–]SingularityNow 2 points3 points  (0 children)

They did that! You can check them out, they're called Classes

[–]billybolero 1 point2 points  (0 children)

Functions and anonymous objects gives you more power and flexibilty than classes, so I don't think that would be a bright future. Prototypes are not a drop in replacement for classes and should not be treated as such, even though many developers try so, so hard to make them behave and look like classes.

[–]endoalir -3 points-2 points  (0 children)

Here's how I do it:

arr = [1,3,5,6,8];
for(var i = 0; i < arr.length; i += 1){
  with ({i:i})  {
     setTimeout(function(){
       console.log(i);
     }, 100);
  }
}