7 ms·
Is JavaScript getting worse?
- robinduckett 12y agoI like `let`. It means you have to be implicit and actually be aware of what you're doing.
- ajanuary 12y agoThat part of the article isn't particularly clear. The intended behavior of let is great. The unintended behavior - that it can cause typeof to fail - is bad.
- taf2 12y agoIt seems to me typeof in the described case should return undefined.
- ajanuary 12y agotypeof is never being invoked, so it can't return anything. The rules of let are that any reference to the variable before the let declaration (the "temporal dead zone"), it's a reference error. So the reference error is being thrown before typeof is invoked.
- arcatek 12y agoI'm sorry, but I really see no point in this article. Do you realize that if the optional arguments were not included in Function#length, you'd just be saying "They are not reflected in the function’s length property. C'mon, man" instead ? Also, I don't understand Whoop-dee-freakin’-doo.
- quarterto 12y ago"They are not reflected in the function’s length property" is exactly what the article does say. Whoop-dee-freakin’-doo http://en.wiktionary.org/wiki/whoop-de-doo http://en.wiktionary.org/wiki/whoop-de-doo http://en.wikipedia.org/wiki/Tmesis http://en.wikipedia.org/wiki/Tmesis
- arcatek 12y agoMy bad, I misread. However, my point is still the same: there was two equally valid choices. Should the other path had been prefered, the author would now be complaining about it too. I don't find it very constructive. As for Whoop-dee-freakin’-doo, no, it don't think it means anything in the context. That's not an argument, and the following sentence isn't either. Maybe I don't understand because english isn't my native language, tho.
- quarterto 12y agoAs a native speaker (granted, it's an American English idiom and I'm British), I understood it semantically as "so what?", i.e. "I don't care about this feature's existence".
- chriswarbo 12y agoFrom my understanding, the author was complaining about the way default arguments mess up implementations of currying. If default arguments were included in the .length, then all existing currying implementations would carry on working with no modifications, they would just ignore the default values and require that we pass in values explicitly. Let's say we have these functions: function getElem(arr, index=0) { return arr[index]; } var curried = curry(getElem); In a hypothetical world where default arguments are included in the length, we would have to supply them explicitly. That's no big deal though, it's just a potential inconvenience: // Hypothetical, "better" semantics var arr = ["a", "b", "c"]; console.log(curried(arr)); // partially-applied function, *not* "a" console.log(curried(arr, 0)); // "a" console.log(curried(arr, 1)); // "b" The ES6 semantics is worse because we cannot provide a non-default argument to a curried function: // Actual, "worse" semantics console.log(curried(arr)); // "a" console.log(curried(arr, 0)); // Error: attempts to run `"a"(0)`, but "a" is not a function console.log(curried(arr, 1)); // Error: attempts to run `"a"(1)`, but "a" is not a function The reason this is particularly unfortunate is that one major use-case of currying is to provide default arguments! In other words, by adding default arguments to the language in this way, ES6 is breaking an existing mechanism for default arguments! I would argue that currying is actually more general than default arguments, so if it's a choice between one or the other, they should have added currying to the language instead of default arguments. They're not quite comparable, but you can think of currying as supplying default arguments "dynamically" (at the call site), whereas regular default arguments are supplied "statically" (at the definition site). For example: // Give "y" a default value for everyone var defaultMultiply = function (x, y=2) { return x * y; }; console.log(defaultMultiply(5, 7)); // 35 console.log(defaultMultiply(5)); // 10 // Don't commit to any defaults yet var curryMultiply = curry(function(x, y) { return x * y; }); console.log(curryMultiply(5, 7)); // 35 // Give "x" a default value, to act like defaultMultiply var double = curryMultiply(2); console.log(double(5)); // 10 // Give "x" a different default, which we can't do with defaultMultiply var triple = curryMultiply(3); console.log(triple(5)); // 15 I've implemented and used currying in JS, PHP and Python, and I found JS the most pleasant, specifically because it didn't have default values.
- gamesbrainiac 12y agoThis is one of the few posts about javascript that I've encountered that sees hoisting as a good thing. I like `let`.
- quarterto 12y agoHave you read the linked article about typeof? Normally, it's safe to do typeof possiblyUndeclaredVariable, but if later in the function you do let possiblyUndeclaredVariable it starts the scope defined as "uninitialized", which causes typeof to throw.
- umurkontaci 12y agoWell that's perfectly normal in a properly scoped language.
- virmundi 12y agoWhat you have to keep in mind is that JavaScript is not "a properly scoped language". Pretending that it is will cause you to miss key aspects of how the tool works. This helps no one, including you. Please, for as crappy as the language might feel, approach the language on its own terms.
- umurkontaci 12y agoFunction scopes and variable hoisting was not the best parts of JS anyway. let brings lexical scope into the game, which I think is a great progress. And you cannot expect a variable to be defined outside of its lexical scope. That's not any different that trying to access a variable outside of a function that is defined in. If people were abusing variable hoisting in some way, they can continue to do so, by not using `let`.
- makomk 12y agoIf I'm following the blog post correctly, let does have effects outside of its lexical scope: it effectively makes the variable even more undefined than a totally non-existent variable. That is, the following code will not throw anything: // x has not been defined or initialized anywhere console.log(typeof x) However, if you add a let statement after it like so: // x has not been defined or initialized here console.log(typeof x) let x = "foo"; typeof will fail with an exception, because the let statement changes x from an undefined variable to a new state that isn't even undefined anymore.
- jerryluc 12y agoBetteridge's law[1] strikes again. [1] http://en.wikipedia.org/wiki/Betteridge%27s_law_of_headlines http://en.wikipedia.org/wiki/Betteridge%27s_law_of_headlines
- Kiro 12y agoI don't understand the benefit of fat arrow. I actually think it decreases the readability. What does lexical "this" binding mean?
- brazzy 12y agoFat arrow notation massively increases readibility by reducing the boilerplate verbosity of function definitions. Lexical "this" binding means that the "this" of the enclosing scope is reused; Arrow-defined functions do not get their own "this" when they are called.
- Kiro 12y agoThanks but massively? function() {} vs () => {}?
- secoif 12y agoAlso removes return statement for 1 liners. Reduces clutter of anon functions, especially when you're chaining a bunch together e.g. ES5 users.map(function(user) { return user.name }).filter(function(name) { return name.length < 30 }).sort(function(a, b) { return a.length - b.length }) vs ES6 users .map(user => user.name) .filter(name => name.length < 30) .sort((a, b) => a.length - b.length) Contrived, but typical example.
- umurkontaci 12y agoMore like: var _this = this; call(function (){ return _this.value; }); versus call(() => this.value); So yeah, much more readable, and less issues with this binding to some other caller or window.
- pornel 12y agoIt's more like function(){}.bind(this) vs () => {} And for a single expression the `{}` are optional and a `return` is implied, which is pretty nice for .map()/.sort(), etc. Automatically bound `this` is super important. It's very easy to forget one `.bind(this)` (or `that` alias) somewhere, especially when you have several levels of callback nesting.
- ajanuary 12y ago> This means that typeof can now throw >>> def f(): ... type(x) ... x = 10 ... >>> f() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in f UnboundLocalError: local variable 'x' referenced before assignment irb(main):010:0> def f() irb(main):011:1> x.class irb(main):012:1> x = 10 irb(main):013:1> end => nil irb(main):014:0> f() NameError: undefined local variable or method `x' for main:Object from (irb):11:in `f' from (irb):14:in `evaluate' from org/jruby/RubyKernel.java:1101:in `eval' from org/jruby/RubyKernel.java:1501:in `loop' from org/jruby/RubyKernel.java:1264:in `catch' from org/jruby/RubyKernel.java:1264:in `catch' from C:/jruby-1.7.12/bin/jirb_swing:53:in `(root)' public class Test { public void f() { boolean isInt = x instanceof Integer; Integer x = 10; } } >javac Test.java Test.java:3: error: cannot find symbol boolean isInt = x instanceof Integer; ^ symbol: variable x location: class Test 1 error Oh no, it's now in line with just about every other lexically scoped language.
- hasenj 12y ago`typeof a` right now returns the string value "undefined" (assuming `a` was not defined anywhere) If it can either return "undefined" or throw an exception, can you see why that would be a problem?
- arcatek 12y agoNo, because it can only throw if there's a flaw in the code. Not randomly according to the argument passed to the function. Unless I'm missing something, it will either always throw, or never throw.
- svisser 12y agoIf a statement didn't throw before and might start throwing now, that would be a problem for existing code wouldn't it?
- phpnode 12y agoES6 is fantastic and usable today using the excellent 6to5 [0]. I disagree with all of the author's points, I think these are great features. [0] https://github.com/6to5/6to5 https://github.com/6to5/6to5
- mmahemoff 12y agoWhoop-dee-freakin’-doo??? Sure there's a zillion frameworks and patterns for shoehorning OO into JavaScript. But the point is, ES6, is standardising it. That means libraries going forward will assume this is the way it's done and build on top of it. It gives them more expressive power and better inter-op. Also, default params are long overdue but I'm not sure that makes them "so what". I'd rather avoid mangling the arguments array in some awkward if statements. Bottom line, there's a lot of things about JS that aren't great, but it's what all the browsers actually run so we're kind of stuck with it and any improvements are welcome. (Even if you use something like ClojureScript or CoffeeScript, JS is still the target language and the runtime. Improvements and standardisation matter.)
- JackMorgan 12y agoI think he means OO adds unnecessary complexity, hence the "bad bet".
- phpnode 12y agough, really sick of this meme. OO is a tool in the box, it's useful a lot of the time, sometimes it isn't. The reason ES6 introduces the `class` keyword is that people are doing that already.
- chriswarbo 12y agoI somewhat agree, but "adding tools" at the language level doesn't come for free: it causes an explosion in the number of interactions to keep track of. How do classes interact with prototypes? How do they interact with lexical scope? How do they interact with exceptions? etc. The egregious part is that, by turning something into a language feature, those who don't use it are often forced to take it into account in their code; especially library authors.
- phpnode 12y ago> those who don't use it are often forced to take it into account in their code; especially library authors. No, `class` is syntactic sugar for the most common way of doing classes in ES3 and ES5. There is no semantic difference between: function Thing () {} Thing.prototype.greet = function () { alert("hello"); }; and class Thing { greet () { alert("hello"); } } They are the same, so it introduces no new traps for library authors.
- collyw 12y agoWhats his problem with classes? I find them a whole lot easier to reason about than prototype based inheritance. (But then I have more experience with class based languages).
- toolz 12y agoI imagine it has something to do with the 'new' functional movement that is gaining mind-share outside of academia.
- vim-guru 12y agoClasses adds complexity and reduces composability. With OO you end up with a soup of inheritence and patterns. Functions are way easier to compose and reason about.
- collyw 12y agoThey don't necessarily introduce complexity. Its a case of using thing s in the appropriate place. I use Python Django. Class based inheritance is useful, though it probably not overdone like it is in the Java world. I also use functions - I find these tend to be better for smaller units of computation and classes for overall organization.
- jerf 12y agoYou might be interested in trying Go's OO out, which privileges composition above inheritance. It's not often talked about on HN under the low-signal furor about generics, but it is a case of a small change that has a surprisingly profound effect on the language. I am becoming convinced that the current backlash against OO should really be against inheritance, not OO. Inheritance is a thing that is occasionally useful and often painful; composition is occasionally painful and often useful. The latter should be the syntactically-privileged default.
- tel 12y agoBy Go's OO you mean the interface-driven mechanics? I think those are quite nice.
- cronin101 12y ago> let considered harmful Did people actually use the side-effect var-hoisting intentionally within their code? Pretty much any JS style-guide worth its salt suggests manually moving var declarations to the top of scope since it's nice to know ahead-of-time which indicators of state you should be keeping an eye on. The idea of inspecting a variable that is later-on defined with let seems baffling to me. I can't think of any reason why you would want to do this.
- kosinus 12y agoI tend to declare vars with their context. Especially in functions that are (unfortunately) longer than usual, having all vars at the top makes for a mess. But I don't think the `let` syntax is going to be a problem for people who write plain JavaScript. It's more likely to it might become a problem for languages that compile to JavaScript. (For example, soak operators in CoffeeScript.)
- basicallydan 12y ago> let considered harmful: The problem with let is that it is not “hoisted” to the top of its block, as var is with its containing function. Interesting point, but I disagree. I think that the lack of hoisting is one of the benefits of `let`. It works in a different way, which is more in line with other languages. Sometimes, you don't want a bunch of variables at the top of your function. Many functions do not need to be executed in the way that hoisting makes easier. By the way, quoting Betteridge’s law of headlines at the beginning of your article whose headline is a question does not mean you get a free pass of using such a headline ;)
- Mithaldu 12y agoWhy didn't they call "spread" by the same name it's called virtually everywhere else, "flatten"?
- forthefuture 12y agoI'm more interested by how many people still seem to be using typeof instead of toString. What are you doing for array checking since typeof array === "object", !!x[0]?
- noiv 12y agoThere is also Array.isArray()
- JacobEdelman 12y agoEh, a lot of the additions are improvements, a few are not, a very small few introduce some annoying features. It's an improvement, maybe not perfect, but still a big improvement. Disclaimer: I like JavaScript.
- Hypx 12y agoJavaScript is definitely getting better. The only question is whether they are changing too much too fast. There'll be a lot of headscratchers when running into unfamiliar ES6 code.
- ahoge 12y ago>Classes. Whoop-dee-freakin’-doo. There are dozens of ways to do classes/inheritance. Standardizing this means better tooling, documentation, and interoperability. >Default parameters. By itself, this is another “so what” feature. It's extremely useful in conjunction with named parameters. Named parameters are so much better than "option" objects. If it's right in the function's signature, you can see right away how this thing is supposed to be used. Since it's declarative, it can be also picked up by your editor, too. >let considered harmful No, it's not. It makes variable declaration work like everywhere else. Function scope is the super weird anomaly.
- filipncs 12y agoBest of all, proper tail calls When are proper tail calls expected to show up? Looks pretty bleak. http://kangax.github.io/compat-table/es6/ http://kangax.github.io/compat-table/es6/
- cwmma 12y agoSo classes in ES6 are something I have very mixed feelings about, on one hand all that is being added is syntactic sugar for what is already being done, I'd like to repeat that ES6 classes add NOTHING that isn't already being done and all it really does is pave the cowpath that is being used in places like node Currently: JSONParseStream.prototype = Object.create(Transform.prototype); function JSONParseStream(options) { Transform.call(this, options); ... } JSONParseStream.prototype = Object.create(Transform.prototype); Object.defineProperty(JSONParseStream.prototype, 'constructor', { value: JSONParseStream, enumerable: false, writable: true, configurable: true } JSONParseStream.prototype._transform = function(chunk, encoding, cb) { ... } With ES6: class JSONParseStream extends Transform { constructor(options) { super(options); ... }, _transform(chunk, encoding, cb) { ... } } That being said, the fact that previously you could not simply use the word class meant that despite efforts of people unused to the language (let me tell you how many half assed class libraries i've seen in code written by people who mainly code in python or java but have some web code as well), unnecessary inheritance tends to be avoided. The lack of a class keyword tends to get javascript writers to avoid inheritance for things best served by mix-ins or object literals, or whatever. I predict that adding the class keyword, while saving me some time will also cause an uptick to unnecessarily convoluted inheritance patterns as new users find they can implement all of their design patterns verbatim without thinking if they really need the ajax method, the json parser, and the url builder to all be in objects that inherit from each other.