Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

You sound like a complete novice, funboy or the one who knows only JS. There are many issues, it is possible not to touch or to work around them, TS and flow helps. JS solved just a few — 'use strict', strict comparison, arrow functions, string literals. Core problems still there — implicit types, prototype declarations, number is float, toString/inspect division, typeof null. Every javascript programmer has to walk that way of embarrassment.


Lol.

I've been programming for a decade in many languages including assembly, C#, Rust, Lisp, Prolog, F# and more, focusing on JS in the last 5 years.

Virtually no one writes plain JavaScript, most people including me write TypeScript, but Babel with extensions is normally used. Your reply exhibits your ignorance of the JS world.


I occasionally write JavaScript since 2007, experiment a lot last 5 years, red through ES5 specification several times. I've worked as C++, PHP, Python, Ruby developer. Experimented with a few languages.

"JS" instead of "TypeScript" brings confusion. TS solves some issues and I've mentioned it, still

    typeof null
    //"object"
Template literals interpolation helps but if string (not literal string) slips by it is a mess

    1 - "2"
    //-1
    1 + "2"
    //"12"
Check out another comment [1], Object, Function, etc defined as constructor. It is not solved by "class", it is still a function with a bit of sugar:

    class Foo {}
    Foo instanceof Function
    //true
Globals with a few exceptions defined as constructors, DOM elements defined as constructors, inheritance defined as constructors

    class Bar extends Foo {}
You can internalize how it works and there are some good explanations [2] but design is error prone and terrible.

[1] https://news.ycombinator.com/item?id=24815922

[2] https://yehudakatz.com/2011/08/12/understanding-prototypes-i...


C++ has WAY more spec footguns than JS (and that's without counting all the C undefined behaviors which alone outweight all the warts of JS combined). PHP also beats out JS for warts (and outright bad implementation like left-to-right association of ternaries). Ruby has more than it's fair share of weirdness too (try explaining eigenclass interactions to a new ruby dev). Even python has weirdness like loops having an `else` clause that is actually closer to a `finally` clause.

`typeof null === "object"` is a mistake (like with most of the big ones, blame MS for refusing to ratify any spec that actually fixed them).

If you're having issues accidentally replacing `+` with `-` then you have bigger issues (eg, not unit testing). I'd also note that almost all the other languages you list allow you to overload operators which means they could also silently fail as well. In any case, garbage in, garbage out.

Foo being an instance of function is MUCH more honest than it being an instance of a class because the constructor in all languages is actually a function. This is even more true because you are looking at the primitive rather than the function object which contains the primitive.


I have not claimed JS is the weirdest. But I have not claimed "Normally C++/PHP/Ruby/Python devs don't really encounter these notorious problems, for many years now" either.

Eigenclass (singleton_class) explained in another thread. I have not encountered Pythons for/else [1] yet.

Right, typeof null exposed by Microsoft IE 2 (?). Web is many times bigger now yet even such a small mistake is not fixed.

I have issue + of being concatenator, I prefer string interpolation, separate operators. Implicit type conversion often does not make sense spoils a lot

    [] * 2
    //0
    foo = {}
    bar = {}
    foo[bar] = 1  // just throw please
    Object.keys(foo)
    //["[object Object]"]
> they could also silently fail as well.

But they don't. If only these rules were defined as library. I am sure it would be ditched long ago. Actually this may be argument in favor of operator overloading in JavaScript, the way to fix it.

> Foo being an instance of function is MUCH more honest

    class Foo
    end

    Foo.send(:initialize)
    TypeError (already initialized class)
    # wrong one
 
    Foo.instance_method(:initialize).call
    NoMethodError (undefined method `call' for #<UnboundMethod: Foo(BasicObject)#initialize()>)
    # does not allow unbound

    Foo.new
new constructs an object and calls initialize. Same in JavaScript

    function Foo () {
      console.log(this)
    }
    new Foo
    // Foo {}
    Foo()
    // Window
It kind of make sense — new creates an object of constructor.prototype and calls constructor. I can't see how it is MUCH more honest than if new creates an object of prototype and calls prototype.constructor. By that logic Object.create is not honest

    Object.create(Object.prototype) // expects [[Prototype]] not constructor
    Object.create(null)
And even if it was

    foo = {}
    bar = Object.create(foo)
    bar.__proto__ === foo 
    //true
    bar.__proto__.__proto__ === Object.prototype
    //true
    bar.__proto__.__proto__.__proto__ === null 
    //true

    class Foo {}
    class Bar extends Foo {}
    bar = new Bar 
    bar.__proto__ === Bar.prototype 
    bar.__proto__.__proto__ === Foo.prototype
    bar.__proto__.__proto__.__proto__ === Object.prototype
    bar.__proto__.__proto__.__proto__.__proto__  === null
I don't need constructor except in new, otherwise I use it only to access prototype. Absence of languages adopting this approach confirms its usability issues.

> This is even more true because you are looking at the primitive rather than the function object which contains the primitive.

Could you please expand this part? "Primitive" has specific meaning in JavaScript.

[1] https://book.pythontips.com/en/latest/for_-_else.html


`__proto__` doesn't necessarily equal `.prototype`.

    var foo = Object.create(null)
    //now foo.prototype and foo.__proto__ are both undefined
    foo.prototype = {abc:123}
    //foo.__proto__ is still undefined. Need to use Object.setPrototypeOf()
In older JS code, I've seen people trying to abuse prototypes. One result in this kind of thing is often retaining references to those hidden `__proto__` leading to memory leaks.

Also, `__proto__` is deprecated. If you're writing JS, you should be using `.getPrototypeOf()` instead.

> Could you please expand this part? "Primitive" has specific meaning in JavaScript.

    var fn = function () {}
    fn.bar = "abc"

    Object.keys(fn) //=> ["bar"]

    //likewise
    (1).__proto__ === Number.prototype //=> true
JS is torn on the idea of whether something is primitive or an object. You see this (for example) in Typescript with the primitive number being different from the Number type which represents a number object. To get at the primitive, you must actually call `.valueOf()` which returns the primitive in question. Meanwhile, you can attach your own properties to the function object -- a fact exploited by many, many libraries including modern ones like React. You can also add your own `.valueOf()` to allow your code to better interact with JS operators, but I believe that to pretty much always be a bad practice.


Yes, I know about null [[Prototype]] and who is owner of prototype and __proto__. I like how it is not real property

    var foo = {
      __proto__: null
    }
    foo.__proto__
    undefined
As you can see I do not store it and do not modify it, it is assertion, kind of instanceof.

> Also, `__proto__` is deprecated

Object.getPrototypeOf would be too verbose in this example. I could have defined

    Object.defineProperty(Object.prototype, "proto", {
      get() { Object.getPrototypeOf(this) }
    })
but why bother? We both know that I meant [[Prototype]].

> Primitive

> fn.bar = "abc"

is syntactic sugar for

fn["bar"] = "abc"

do not follow.

> (1).__proto__ === Number.prototype

number is primitive

    typeof 1
    "number"
    1 instanceof Number
    false
number is wrapped in Number when we access property

    Number.prototype.foo = function () { return this }
    1..foo()
    //Number {1}
    typeof 1..foo()
    //"object"
    1..foo() instanceof Number 
    //true
Function is not primitive

    typeof Math.max
    "function"
    Math.max instanceof Function
    true
    Math.max instanceof Object 
    true
it is an object, we can attach properties to object.

As I remember valueOf is complicated by hints, exposed in JavaScript [1]. I've played with removal

    delete Array.prototype.toString
    delete Object.prototype.toString
    Uncaught TypeError: Cannot convert object to primitive value
Unfortunately it converts to string and than converts string to number.

    delete Array.prototype.valueOf 
    delete Object.prototype.valueOf 
    +[]
    //0
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


The same thing. I work in the JS world, and interact with it nonstop.


Oh, JS has no issues, solved by ClojureScript, PureScript, Elm.


These languages are not used by virtually all JS programmers. Babel and TS is.

The other issues you mention are solved by using ESLint which flags code like this.

I do not encounter these issues in my life as a professional JS programmer, neither do my colleagues; and I'm not on my first project, don't worry. For all practical purposes they are non-existent.

anyways, we are all happy for wasm, it's not that we love JS so much.


I actually like JavaScript, with a few changes it can become a good language, safe for a novice programmer.


Agreed. Check out AssemblyScript, you might like that. It's early, though.


> Virtually no one writes plain JavaScript

Which is because plain Javascript is objectively terrible, as I pointed out.


That's like pointing out that C++ after template transformations are applied is terrible. Yeah, so what? Nobody writes it like that.


"C++ is C because nobody writes C", you can't be serious.


That's not what I said.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: