Feel free to skip the first paragraph if you’ve read my previous restrict mode articles.
I’ve created this thing called restrict mode for JavaScript. It’s a definition of a proper subset of the language which I believe is great because I think it increases robustness and makes your program more easy to reason about. It comes with a tool that will check if your program really complies to restrict mode, when you say it does. The tool is called restricter
and is a plugin for JSShaper, an extensible framework for JavaScript syntax tree shaping. Restrict mode makes JS programming more enjoyable since it helps you focus on real programming challenges instead of annoyances/defects/inconsistencies of the JS language.
I’ve written about how I made v8bench and JSLint restrict mode clean and I promised to do the same for jQuery.
I’ve tweaked the restrict mode semantics somewhat since then:
I removed the restrict mode custom versions of ==
and !=
. This shouldn’t come as a big surprise since I hinted that I wasn’t happy with clause 1 in the case for restrict mode. Now all of ==
, !=
, ===
and !==
behave identically in normal and restrict mode and you should strongly consider not using ==
and !=
irrespective of whether you use restrict mode or not.
I relaxed the restrict mode +
operator slightly. It was previously only allowed for str + str
(concatenation) or num + num
(addition), but never a mix. It’s now also allowed for num + str
or str + num
, which happens to be the most common coercing usage of it out there in the wild. I hope that this will lower the barrier of restrict mode adoption.
Restrict mode is still a proper subset of the JavaScript language and will remain so. It will freeze one day but we’re not there yet.
Back to jQuery. I cloned the jQuery repo, ran it through restricter
(with restrict mode forced no matter "use restrict";
directives) and fixed the restrict mode run-time errors until all tests passed again. restricter
ran on everything under src/
excluding the Sizzle dependency, to be precise. It should be easy to try it on Sizzle as well, or on something else for that matter.
The required changes to get jQuery restrict mode clean were few and small. They can be partitioned into three classes:
Most were about fixing the str + nostr_nonum
antipattern
One fixing str < num
One fixing str + undefined
Neither class 1 or 2 are bugs in jQuery. They represent the current mismatch between the restrict mode subset of JavaScript and the subset that the jQuery developers use. The mismatch seems to be very small, further strengthening the case for restrict mode. I only had to change a total of 9 lines of code, all by explicitly converting a primitive or object into a string using String(expr)
. The patched version may be a bit easier to reason about and slightly more robust to future changes, especially so for newcomers to the jQuery codebase. Being explicit makes it slightly more verbose.
The class 3 change is more interesting. str + undefined
is rarely done on purpose. jQuery.fn.hasClass
should guard against missing className properties but doesn’t, and as a consequence element.hasClass("undefined")
may return true
when it shouldn’t. An easy way to demonstrate this is to change test/unit/attributes.js, line 860
. Change ok(!j.hasClass("asdf"),
...)
to ok(!j.hasClass("undefined"), ...)
and watch the assert blow. Talking about assert feel free to check out C-style assertions in JavaScript via JSShaper.
Seems like restrict mode found us a jQuery bug.
Here’s the patch aggregating the changes above including the bugfix. It applies cleanly against d59b0f3e27827d189b8b2595142ec6bbc3941dd9. And here’s the jQuery forum thread, ticket and pull request.
Want to try restrict mode on your own project? Go to restrictmode.org and feel free to stop by the JSShaper mailing list.
Follow me on Twitter
« I made JSLint restrict mode clean. Here's what I found ↑ Home Describing Live programming (again) »