Django templates also do this, which causes all sorts of debugging problems.
Django templates also do this, which causes all sorts of debugging problems.
I've run into a lot of cases in node where I passed something not quite right to a crypt library but didn't find out until like 2 pages later. Usually for things that in python would throw an exception immediately.
I disagree; I do a lot of work in both dynamic and strongly typed languages. Most often, when I find a bug "not where the error occurs," it's because, for example, I'm accidentally computing a minimum and later assuming it to be a maximum. Unit tests catch most of this, so such debugging puzzles usually happen to me in fresh new code with unstable interfaces...
As pointed out, {}.foo will not cause an error. In Python and any good dynamic language, that will generate an error.
Another problem is all the implicit (silent) type conversions. JavaScript will happily add an Object and an integer, then multiply that by a string. Any sensible type system would not allow that, but JavaScript silently produces a NaN.
The problem isn't that its a dynamic type system, but that the type system ignores things which are clearly problems.
Failing silently makes sense in a language like C, where performance is a high priority and you can avoid adding assertions for performance. But JavaScript has to add an assertion to return an undefined value anyway, so you're not even getting a performance benefit from it. It's purely bad design with no benefit.
Maybe people who are used to js take advantage of this and do it on purpose, but from my perspective all it's done is take mistakes and move the errors farther downstream so that you can't trivially find where the problem started.
If I wanted a function to accept a variable number of parameters or have default values for a parameter that can be omitted, I would much rather have to have to define that behavior per function.