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

Saying "it's not the most elegant language" is quite (mis)leading. While I would not claim that it is the most elegant language, I would most definitely claim that it is elegant.

Two things that many people get wrong about JavaScript: (1.) Most of the ugly parts involve interacting with the DOM, and the DOM is NOT JavaScript, and (2.) Just because some people write ugly code with it does not mean that the language itself is ugly.

ES6 and ES7 have done wonders for the language syntax, and the flexibility of the language allows you to write in any combination of procedural, functional, prototypical, object-oriented programming styles. I mix them together as needed to make programs more intuitive and easier to follow. Programming is an art, and JavaScript is a powerful and versatile tool.

You are also wrong in that it being the only language supported by browsers. That may be the case now, but in the past many, many, many websites used flash and java applets. Quite frankly, the reason that JavaScript is what we have now is because it really is that good that it replaced all the other options.

All of the other questions are all over the board... It sounds like you are trying to get us to write a homework assignment for you.



I haven't looked at ES6/7, and its true that any language in the wrong hands can be ugly. But there's a lot wrong with JS besides how it interfaces with the DOM[1]. Which is funny because it was originally conceived as a browser scripting language[2].

And JS beating flash and java applets may be more a result of market forces (Apple) and the lack of better alternatives.

Brendan Eich designed JS in 10 days for the early era of the web, which is very different today. Its both a testament to the language and the hacks on top of it that its stayed in use this long. But maybe its time to move on?

[1] https://medium.com/javascript-non-grata/javascript-is-a-dysf...

[2] https://en.wikipedia.org/wiki/JavaScript#Beginnings_at_Netsc...


Why do you believe the language is dysfunctional?


>>Most of the ugly parts involve interacting with the DOM, and the DOM is NOT JavaScript, and

Yeah, like dealing with "this" keyword or type coercion in JS is not the ugliest thing ever in the history of Programming languages


> Yeah, like dealing with "this" keyword

This can get a little confusing until you understand how context works. Then it makes sense but you know what? You don't always need to use this. In fact you can build entire applications in different ways without ever using this. And no writing without using this doesn't make your code ugly or unmanageable. There are just many ways to get the same or similar things done in JavaScript.

> type coercion in JS

Type coercion is ugly in any programming language. It's best to avoid it, even in JavaScript (which you can do, btw).


The problem with type coercion is when it happens without you noticing it. You cannot "avoid" it...


Sure but this problem is inherent to any dynamic language. I find other issues far worse than simple type coercion. What about calling a function? Most dynamic languages will let you pass in any number of parameters regardless of its definition and you may not even notice.

You can avoid type coercion if you understand how the language works (aka strict equality in JavaScript) but this isn't something only in JavaScript land either.


There are two separate issues in play here. You're conflating the static/dynamic dimension of language classification with the strongly-/loosely-typed dimension of languages which is what the poster you are responding to was talking about [1]. These two dimensions are orthogonal: languages may be static, but weakly typed (like C), or dynamic but strongly typed (like Python).

I'll allow that there's inevitably some degree of opinion involved here, but I tend to agree with the parent poster that implicit conversion in languages like Javascript, PHP, and Perl is just another vector for bugs, and outweighs any of the advantages you get from having your language coerce everything for you. But then again, i'm one of those people that likes my language to force me to be very explicit about what I mean, so YMMV.

Regardless, the strict equality operator is not at all sufficient to avoid the dangers of JavaScript's implicit conversions. Pretty much _all_ the operators are going to coerce types for you, whether you meant for them to or not. For example, this function:

function increment(i) { return i + 1; }

Adds one to number right? But let’s say you’ve neglected to convert some user input in a form to a number as you should have done elsewhere in your code, and you end up calling increment("1"). This will return "11". So now you potentially have introduced a serious math error into your code you may not notice right away. Conversely, if you did this in Python, the function would have raised a TypeError immediately, because you can’t apply the arithmetic operator to two different types. You can’t just “avoid” type coercion in these loosely-typed languages by understanding the specifics of how it works, because you may not even know it’s happening until you start seeing unexpected results somewhere.

[1] https://en.m.wikipedia.org/wiki/Strong_and_weak_typing


> Most dynamic languages will let you pass in any number of parameters regardless of its definition and you may not even notice.

Python will throw an error. Ruby will throw an error. Tcl will throw an error. Erlang will throw an error. I believe most of the Lisps will throw an error.

What was it about "most dynamic languages"?


> What was it about "most dynamic languages"?

I should have changed my text to not say "regardless of definition" because you can do that in Python, Ruby, PHP, JavaScript, etc.

Python and Ruby support it through (star)args or default parameters

JavaScript supports it regardless

PHP supports it regardless

We can argue semantics or the fact that some of those types of errors can be caught with some subset of dynamic languages but I don't think that's useful.

My only point was when comparing a dynamic language with a static language I find variable function parameters to be one of the bigger issues over type coercion. But that's just, like, my opinion.


Those aren't particular to dynamic languages, though. You can add C, C++, Java, and C# to your list of languages that support it. Being able to explicitly make a parameter optional, or to have a 0-or-more rest argument is different from how function application works in Javascript or Perl because you have explicitly made that part of your function's signature, and the language still checks calls against that signature.


Most Lisp compilers will warn about wrong number of parameters at compile-time. Lisp typically warns at runtime, too.


> Yeah, like dealing with "this" keyword or type coercion in JS is not the ugliest thing ever in the history of Programming languages

Try python. Python's handling of this/self makes javasacript look like the most amazing thing ever.


Could you please explain? It's always very clear in Python what `self` refers to. Self is always an instance of the parent object of a method. Some classes can also have static class methods that can be called from the class itself instead of one of it's instances. Maybe that is where your confusion is arising?


It's not that it's confusing, rather it's unnecesarrely cumbersome because it's explicit and because you have to put it as an argument. Looking at the "most used words" [1] list of python, self is the #1 used word by far, occuring three times as often as the second most common word, "if". At this point, it's just a filler that bloats code and makes it less readable in many cases

    # so much text for such a little task
    def length(self):
        return math.sqrt(self.x*self.x + self.y*self.y + self.z*self.z)
        
    # better, but not quite there yet
    def length(self):
        return math.sqrt(self.x**2 + self.y**2 + self.z**2)
        
    # this would be perfect, but it's not allowed by python
    def length():
        return math.sqrt(x*x + y*y + z*z)
To be fair, javascript also forces you to explicitly specify "this" so there is no difference in that regard. What I find worse than that is that you have to specify self in the parameter list. Calling a function with 2 parameters but having to declare 3 doesn't make sense. The usuall reasoning is that "explit is always better than implicit" but I do not agree. We could take this philosophy all the way to explicitly defining all the global variables that may be used by the function in the parameter list, maybe even all the packages that this function is going to use. We don't do that for a good reason.

[1] https://anvaka.github.io/common-words/#?lang=py


Saying it's unnecessary is incorrect, and I don't agree about it being cumbersome either. On the first point, how would you disambiguate between reading from an attribute and reading from a global (or non-local) variable? How would you disambiguate between assigning to a variable and assigning to an attribute? You'd have to explicitly declare all your variables (making other things cumbersome instead) or accept that the semantics of your program could change during run time, depending on the contents of outer scopes (which I doubt you'd find an acceptable option). This is the main reason the 'with' statement is deprecated in JS. C++ can get away with implicit 'this' because it has static dispatch and all variables are explicitly declared anyway. But truth be told, I'd remove it from C++ too if I could. I like the clarity of knowing at call site whether something is a function or a method call without having to look it up. Paying for it the price of having type a few more characters has never bothered me.

And I somewhat like that I can name my 'self' argument whatever I like instead of having to resort to obtuse workarounds like 'var that = this;'. Not that I've ever had the need to take advantage of that possibility in Python, but it's comforting to know it's there.


In a short function that makes a lot of references to self, yeah I agree in can be a bit cumbersome. But as the functions get longer, I much prefer the explicit use of self. It makes the code far more readable as you can tell at a glance where a variable comes from.


> It's not that it's confusing, rather it's unnecesarrely cumbersome because it's explicit and because you have to put it as an argument.

I don't feel the same way. To each their own I guess.

Regarding your example, I don't see anything wrong with the second version. Anyone who reads the code will easily be able to tell what it does and where the variables come from. In your third example, how is anyone supposed to know whether or not `x`, `y`, and `z` are class variables or global variables? Kind of defeats the purpose of namespacing, I think.

> What I find worse than that is that you have to specify self in the parameter list.

This is really one of Python's implementation details. Methods can be bound or unbound. Without going into to much detail, just know that a bound method can be used as a regular function. Here is some code to illustrate what I mean:

    >>> class A():
    ...     def a(self):
    ...         print('hello')
    ... 
    >>> A
    <class '__main__.A'>
    >>> A.a
    <function A.a at 0x7fc4009381e0>
    >>> A.a()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: a() missing 1 required positional argument: 'self'
    >>> A().a()
    hello
    >>> b = A()
    >>> A.a(b)
    hello
    >>> class B():  
    ...     pass
    ... 
    >>> b = B()
    >>> A.a(b)
    hello
    >>> class B():
    ...     def a(self):
    ...       print('goodbye')       
    ... 
    >>> b = B()
    >>> A.a(b)
    hello
    >>> c = A()
    >>> B.a(c)
    goodbye


Self does not have to be the same class it's called on. It can be any class. However, if you try to access a class attribute that doesn't exist, you get an attribute error.

    >>> class C():
    ...     x = 10
    ...     def a(self):
    ...         print(self.x)
    ...
    >>> C.a()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: a() missing 1 required positional argument: 'self'
    >>> C().a()
    10
    >>> a = A()
    >>> a.a()
    hello
    >>> C.a(a)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 4, in a
    AttributeError: 'A' object has no attribute 'x'
Since bound methods need to behave like regular functions, it is improper to not pass the object instance to the function.


Class methods don't accept a "self" argument, though. In those cases, you call it cls.


I'm aware. The `self` vs `cls` thing is convention. You can call either argument whatever you want.


What do you mean? Could you give an example? I always regarded python self to be one of the cleanest ways to show that we have another parameter in a method.


are you joking, right? in javascript you cannot ever KNOW what this refers to (is the instance of a new Thing()? is null? is "window"? is something set with .bind()? is just "the left thing before the dot before the function"? is something else?


Does "this" work differently in JS as it does from Python or even C++?

Is it not always the object that owns the function currently being executed?

If the "this" is implicit, then how can you possibly know where the variable comes from?


Eh. Python and JavaScript are very similar at the language level. They each have warts and are more expressive in certain areas, but at a high level they have the same semantics and the exact same advantages and disadvantages.


this is only used with the new keyword. You can however program JS avoiding both new, prototype and this, by using "factory functions". Or avoid OOP structures altogether using a more functional paradigm.


>>this is only used with the new keyword

This so not true. "this" is much wider paradigm in JS.


If the new keyword is not used, "this" will point to the global scope. You do not however have to use the new keyword when creating the built in JS objects.

{} is new Object();

If you find "this" confusing you can and should avoid using it. JavaScript has many bad parts that some programmers love to use because it makes their code "elegant". It is however possible to write simple and easy to understand code by only using the good parts.


>>If the new keyword is not used, "this" will point to the global scope

This is entirely incorrect information, consider a simple example:

    function f(){console.log(this.a);}
    var o={a:"c"}
    f.call(o)

there is no "new" keyword involved, and "this" is not pointing to the global scope and there is a huge amount of other samples which I can show, but I won't. I don't have any problems with understanding "this" in JS. I just firmly believe that this is superb ugly stuff.


That is indeed ugly stuff. Thankfully you never have to use f.call(o)


I bet you never developed anything realistic with JS! The close neighbor of "call" called "apply" is a widely used tool.


Show me some code and I will refactor it for you.


Just for fun, why not..Let's take a look at the classic one:

    Math.hypot.apply(null, [1,1,3,3,4])
Try to refactor without using ES6's "spread" feature(Math.hypot(...[1,1,3,3,4]))


You've got an array, and want to "hypotenuse" it. Your code is fine, as it's pretty clear what it does. But for the sake of refactoring:

  const hypot = arrNum => Math.sqrt(arrNum.reduce((sum,n) => sum + n*n))

  hypot([1,1,3,3,4])
Although I would prefer:

  function hypot(arrNum) {
    for(var i=0, sum=0; i<arrNum.length; i++) sum += arrNum[i] * arrNum[i];
    return Math.sqrt(sum);
  }


I don't think it's a good solution because it performs the operation manually instead of calling the built-in Math.hypot method. This is the point - "apply" is a widely used technique, at least it used to be on pre-ES6 times.


Try C++ template metaprogramming or Java collections before generics.


use ES6, Babel, and ===


ES6's arrow function might help to avoid "this" problem in some scenarios, but it does make it any better. Type coercion is a lot more than == vs ===.


[] + [] === ""

Elegant... hmmmmm


[1,2,3].toString() === "1,2,3"

[].toString() === ""

It's only confusing to people who really don't know anything about the language.



Are you arguing that this is confusing to you and therefore not elegant, or are you arguing that this code compiles and that means it is not elegant?

Would you write that in production?


JavaScript is as elegant as a cat scratching his nails on a blackboard. it's a mongrel language without any whatsoever elegance. Taking your art metaphor further is like comparing the ceiling of the "cappella sistina" to a cut in a canvas.


3) Maybe a language don't need to be that "elegant", it's not required in all situations. I think I would prefer a "practical" language over "elegance" but like the appearance.




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

Search: