IE users are probably used to getting a horrible user experience anyway. I'm sure they can cope with a few browser freezes/crashes every once in a while - They know how to take a beating :p
The article has gotten updates since then (check the history), but not many and not to the extent it probably needs. Not sure why it keeps getting linked.
Indeed IE's users are having terrible experience anyway, but let's just don't push FF and Chrome to their memory limits, just because we don't care with our code.
One of the best parts when I develop client-side web-apps is the debugging and looking close what the garbage collector is doing. For example : I usually don't use `delete` keyword, since I know it might create a node that GC's can't clear.
In the end a lot of people using the application would either have to restart during the day, use portable Firefox, which many actually did. Of course, there are/where many worse things in practice dealing with supporting IE<9 for relatively modern web applications. I'd still rather deal with that, than the v4 browser days.
Javascript is not a toy; toys are fun.
I just wanted to say that the behaviour of this 'nicer' idiom may not be what's expected - it stops iterating once it hits the first falsy value. I was quite excited actually when I first saw them idiom, until I quickly realized its limitations
Not to mention the suggestion you're talking about, which I bet would bite programmers for the reason you mention. Seems like a bad idiom, I've personally never seen it in the wild.
In fact, even `for` is likely an over-optimization. In nearly all JS code you can get away with just using `forEach` (or its friends).
Caching the array length still gives you a small speed boost in most browsers, but it's probably an over optimisation unless you're doing something really intensive.
Can't wait for ES6 to no longer be 'experimental', as I'd much prefer to use 'for..of' loops
On the server-side async/await are worth their weight in gold... and using lambdas is very nice. I still don't like the ES6 module syntax over node/commonjs require statements though.
The only thing to be really mindful of is when you browserify for the client that you don't accidentally include, for example the entire crypto library, buffer or similar shims because they can get very big, very quickly.
I think there are still places where you need to do this (please correct me if wrong, or mention some other cases):
- when iterating over DOM nodelists in JS (why doesn't the browser cache this as well?)
- if using strlen in C/C++ (for the latter, you should use string.length() instead).
(Sure, IE<9 is a caveat, but all the Array iteration methods are the easiest things to shim and if you're targeting below IE9 chances are pretty good it's not the first shim you'd be using.)
“A nicer-looking but limited idiom is:”
MDN documentation is on a wiki. You can just edit the page.
It's the most confusing part about Javascript. This context, var foo scope, what? Why is this value not updating? undefined? What???
>>> class foo():
... def test(this, x):
... print this, x
...
>>> x = foo()
>>> x
<__main__.foo instance at 0xb71928ac>
>>> x.test(1)
<__main__.foo instance at 0xb71928ac> 1
>>> y = foo.test
>>> y(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method test() must be called with foo instance as first argument (got int instance instead)
>>> y(x,1)
<__main__.foo instance at 0xb71928ac> 1
In Python, the reference to the current object is an explicitly declared parameter in the method definition, but the parameter is passed implicitly - the value of "this" is whatever is comes before the period when the method is called. If you call it in any other manner, it throws an unbound method error. Javascript is the same way, but instead of throwing an error it will instead pass 'window' implicitly. The equivalent code in Javascript: function foo() { }
foo.prototype.test = function(x) {
console.log(this, x);
}
var x = new foo();
x.test(1); // prints VM1061:4 foo {test: function} 1
var y = x.test;
y(1); // prints VM1061:4 Window {top: Window, window: Window, …} 1 >>> foo.test
<unbound method foo.test>
>>> x.test
<bound method foo.test of <__main__.foo instance at 0xf74d68ac>>
>>> z = x.test
>>> z(123)
<__main__.foo instance at 0xf74d68ac> 123
I really like this behavior in Python. Unfortunately, JavaScript does not behave the same way, as you see in the last couple of lines in your example. You can however get the same result by manually binding the method to the object: z = x.test.bind(x)
// z is: function () { [native code] }
z(123)
// foo {test: function} 123Note that the behaviour of `this` defaulting to `window` (or `global`) is only the legacy behaviour. You should be using strict mode (there's really no justification not to -- except for extremely rare edge cases, e.g. having to delete global variables without having a reliable reference to the global object other than `this`).
In strict mode, `this` would be undefined. As expected, if you consider `x.y()` syntactic sugar for `x.y.call(x)` (and therefore `z()` syntactic sugar for `z.call(undefined)`).
Under the hood, invoking a function translates to a call of the functions `[[Call]]` method, which takes an explicit `this` just like `Function.prototype.call` does.
var foo = {
doSomething:(...argv)=doSomethingMethod(foo, argv)
};
return foo;
In this way, the execution is always predictable, as I avoid the use of this altogether... It's my one niggle with koa, that it uses this (execution context) as the request/response context. I tend to it in practice.It's similar to what Crockford now presents as a preferred approach in dealing with having context for functions... I just like discrete functions that can be tested independently of their execution context... by passing the context as a parameter, this becomes explicit... with binding, the process becomes transparent.
I simply don't ever need to think about it anymore.
And I don't just mean run-of-the-mill blub programmers who dabble in jQuery, I mean some of the best devs I've ever seen in any language. I had a self-proclaimed JS expert tell me that JS has integers and floats as distinct types. Even the people I work with every day who are fantastic did not know that function and array are not types.
Of course, things like `typeof` don't help the situation, so I don't put the blame squarely on programmers' shoulders. And obviously you can get a lot done without knowing that, technically, functions are just objects that can be called. But it still strikes me as kinda crazy.
How can you create an object which can be called like a function, but will respond to 'typeof' with 'object' rather than 'function'?
What happens when you try to call an object - what's the error? Try it, in a few of your favourite javascript interpreters:
({})()
It seems clear to me that functions are more than "just" objects in JS. You can't start out with a random {} and turn it into a function. JS functions are a subtype of JS objects, but they are a distinct type. You can't substitute an object where a function is expected - you get a type error - but you can substitute a function where an object is expected.Good stuff here.
var that = this; + "42"; // 42
> [...] However the "+" operator simply converts the string to NaN if there is any invalid character in it.Being a bit pedantic here, why not recommending the Number function which may be less obscure for beginners?
Number("42"); // 42Number automatically accepts exponent notation and auto-converts to hex (ignoring octal). parseInt() auto-converts hex and octal unless a radix is specified, but it also ignores the remaining non-number characters at the end of the string.
There isn't a single method that does whatever you want.
An other thing that could maybe be covered is this specifity:
typeof "42" === "string"
typeof String(42) === "string"
typeof new String(42) === "object"
Native constructors are ... fun beasts, to say the least. '42' | 0; // 42
NaN | 0; // 0
null | 0; // 0
undefined | 0; // 0
false | 0; // 0
true | 0; // 1The behavior of Number, Boolean, String, and Array is well-defined, it's safe to call them without new. In fact, in the case of String/Boolean/Number, calling them with new will often do something you don't expect. (Calling them with new gives you a Number/String/Boolean object, not primitive, which can cause trouble when you try to compare them with ===, unless you remember to use their `valueOf` method)
Also, as noted below, it's possible for objects to not have a `toString` method, so attempting to call it to get the object's value as a string could blow up. So it's actually safer to coerce to string by adding an empty string or passing to String().
ES6 is packed with weird but well-defined things.
The problem is that calling a constructor function (a PascalCase'd function) without `new` looks like an error because it generally is an error. To make matters worse, without closely examining that function, you cannot tell if it's an error.
I do know that `Number()` happens to be one of those constructor functions which not only work without `new`, it also happens to behave differently when `new` is missing. It does not return an object. It returns a primitive.
Someone who doesn't know about this unusual secondary function will waste some time if they spot this apparent mistake.
Now, to defuse this time-wasting trap, you could either add a comment... or just do the sensible thing and write it in a way which does not require a comment.
el$ = $('#whatever'); el$.click( function() { el$.find("a").css("color", "red"); } );
In general, the only niggle is when you want a discrete integer value, where zero is an acceptable input, or a string that represents a number coerced into a number.. but anything else to be null. You have to single out falsy values that aren't zero in this case.
Other than that one niggle in practice, I've come to truly appreciate the expressive nature that JS actually offers in practice. The additional concepts added in terms of ES6 and ES7 are pretty welcome. Though in practice, I've moved very far away from trying to apply many OO patterns of classes, inheritance, etc in favor of basic object instances, and functions that can be combined/composed.
It's pretty nifty all around.
Consider the following:
.1 + .2 == .3 // false
The way to 'get around' this is to have a value (usually called an epsilon) that is relative in magnitude to the numbers being compared. In this example, a value like .00001 as epsilon should work fine.Anyways, all you have to do is check if the absolute difference of the numbers is less than the epsilon:
var a = .1 + .2, b = .3, epsilon = .00001;
console.log(Math.abs(a-b)<epsilon); // true
In short, try to not put yourself in a situation where you have to compare equality with doubles. var SCALE = 100; // 0.01
var a = 0+1 * SCALE; // e.g. 2.5 would be 2+5 * SCALE
var b = 0+2 * SCALE;
if (a + b == 0+3 * SCALE) {
// this will work...
}
console.log(a / SCALE);Approximate Range -> (-7.9 x 1028 to 7.9 x 1028) / (100 to 28)
Precision -> 28-29 significant digits
Homework: 1) Google for such; 2) see which one doesn't suck.
No it isn't. It has support for OO and you can choose to write code object-oriented if you wish. But equally you can disregard the OO bit quite happily and compose behaviour using closures instead.
None of my favourite JS libs are OO, it's a poor abstraction imho.
Along the same line but more in depth, I really like Cody Lindley's JavaScript Enlightenment:
[1]: 32-bit integers show up under the hood, in expressions such as `5000000000|0`. Both 0 and 5000000000 are precisely represented in JS's Number type, but you cannot (correctly) take a binary OR of the two.
It really isn't unique to JS, and there are several bignum libraries that can/will help.
Keep up the good work Mozilla.
edit: I see MANY people contributed! You can too! https://developer.mozilla.org/en-US/docs/Mozilla/Connect. It still would be cool if Eich could act as an "editor" to JS related articles!