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 or type coercion in JS is not the ugliest thing ever in the history of Programming languages
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).
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.
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"?
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.
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.
Try python. Python's handling of this/self makes javasacript look like the most amazing thing ever.
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?
# 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.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.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.
This so not true. "this" is much wider paradigm in JS.
{} 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.
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. 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])) 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);
}