"use strict"; seems awesome, and we'd really like to use it at our shop. However, we just want it so that we (the developers) can find strictness-issues; we very much DO NOT want to make our site break for our actual customers when it was working fine before.
Now, we could just use some server-side logic to achieve this:
{% if debug %}<script>"use strict";</script>{% endif %}
... except that "use strict" operates on a file-by-file basis, so that won't actually work (well, unless we start server-side processing all of our JS files).
So, my question is: do all the things "use strict" checks for get checked when the page loads, or is it possible for "use strict" to find errors after the page has loaded? If it's the former, we can just use "use strict" and stop worrying, because we'll load our site in development before loading it on live. However, if it's the latter we seem to be out of luck, as we can't test every possible runtime condition (and again, we don't want to make errors for our users when there were no errors before).
It's the latter. While beeing in strict mode, an Javascript interpreter may throw error messages at runtime, which would not get thrown in non-strict mode.
On the other hand, most of these errors are "good errors", which means, they will actually help not breaking your code.
For instance
function foo() {
"use strict";
bar = true;
}
foo();
This will throw
"ReferenceError: assignment to undeclared variable bar"
in strict mode, which is a good thing. In non strict mode, we would just have created a global variable called bar, which is probably not what we wanted. There are plenty of other situations where strict mode prevents the programmer from doing something stupid/bad/unwanted and throws error messages. But again, you want to have those errors instead of some wierd bugs.
Have a further read on MDN
If I understand you correctly, yes, it's definitely possible for strict mode to catch errors after the page has loaded. For example:
'use strict';
setTimeout(function() {
undefined = 42; // Causes a TypeError
}, 1000);
// Click here for a demo.
What you can do is pretty simple: you should be minifying your JavaScript when you move to production anyway. Just make sure that the 'use strict' gets removed during that minification process.
Failing that, just try to make sure your code is strict-error-free. Strict mode usually comes into play with regards to semantics, not because of something odd the user input or even because of syntax. It shouldn't be too terribly difficult to catch all the cases. (But minifying and removing 'use strict' is a much better solution.)
Related
So, this was quite an interesting problem I have been running into.
I am currently building a backbone.js - Rails app. Generally just building this for learning purposes. I am (like any good rails dev) doing my best at TDD/BDD and I ran into a problem with capybara.
I have an integration spec that merely tests root_path works (Backbone history starts, displays initial information, etc...).
require 'spec_helper'
describe "RentalProperties", js: true do
describe "GET /" do
it "should show a list of properties" do
visit root_path
eventually{page.should have_content("Something")}
end
end
end
I am running tests with jasmine, sinon, and capybara/rspec/webkit. I am loosely following both the "Rspec on Rails" book by thoughtbot (awesome book by the way), and this tutorial: http://tinnedfruit.com/2011/03/03/testing-backbone-apps-with-jasmine-sinon.html.
When running the above spec, I came across this error:
undefined|0|ReferenceError: Strict mode forbids implicit creation of global property 'csrf_token'
I took a long time sorting this out because there's really nothing google-able for this error.
Eventually I stumbled across using "use strict-mode" in JS. Essentially this will use some new EMCA5 script conventions. It will catch more coding bloopers, and keep you from accessing global variables. All good things.
So I check, and in my sinon.js file, I see:
"use strict";
on line 36 of the file. Lo and behold I comment out the line, and my tests work just fine.
Here is my question: Why did use strict mess up csrf? I am assuming this has something to do with csrf_meta_tags in my rails layout. If possible I would like to put this line back in sinon js as I assume its the "right thing to do"
Does anyone have more information on this? I appreciate any details in advance!!
It is telling you that a value is being assigned to a variable called csrf_token that has not been declared, e.g.
csrf_token = 'foo';
In non–strict mode, that will create a property of the global object (usually called a global variable) called csrf_token when that line of code is executed.
In strict mode, it will throw the error you see because strict mode prevents the implicit creation of global variables. You could also fix it by including:
var csrf_token;
anywhere in a global context in the same script element as the code the error comes from, or a previous script element.
I know that I can type into Chrome or FF the following command:
Object.keys(window);
but this displays DHTMLX stuff and also function names in which I'm not interested in. And it doesn't display variables in functions that have not been executed yet. We have more than 20,000 lines of JavaScript codebase, so I would prefer static code analyis. I found JavsScript Lint. It is a great tool but I don't know how to use it for displaying global vars.
So I'm searching for memory leaks, forgotten var keywords, and so on...
To do [only] what you're asking, I think you're looking for this:
for each (obj in window) {
if (window.hasOwnProperty(obj)) {
console.log(obj);
}
}
I haven't linted that code, which is unlike me, but you get the idea. Try setting something first (var spam = "spam";) and you'll see it reported on your console, and not the cruft you asked about avoiding.
That said, JLRishe is right; JSLint executes JavaScript in your browser without "phoning home", so feel free to run it. There are also many offline tools for JSLinting your code. I use a plugin for Sublime Text, for instance.
If you'd like some simplest-case html/JavaScript code to "wrap" JSLint, I've got an example here. Just download the latest jslint.js file from Crockford's repository into the same directory, and poof, you're linting with a local copy of JSLint.js. Edit: Added code in a new answer here.
Though understand that you're linting locally with that wrapper or when you visit JSLint.com. Honestly, I can say with some confidence, Crockford would rather not see our code. ;^) You download JSLint.js (actually webjslint, a minified compilation of a few files) from JSLint.com, but you execute in the browser.
(Admittedly, you're technically right -- you never know when that site could be compromised, and to be completely on the up and up, you sh/c/ould vet jslint.js each time you grab a fresh copy. It is safer to run locally, but as of this writing, you appear safe to use JSLint.com. Just eyeball your favorite browser's Net tab while running some test, non-proprietary code, and see if any phoning happens. Or unplug your box's network cable!)
Rick's answer to use "use strict"; is another great suggestion.
A great way to catch undeclared variables is to add 'use strict' to your code.
The errors will appear in the console, or you could display them in a try ... catch block:
'use strict';
try {
var i= 15;
u= 25;
} catch(ee) {
alert(ee.message);
}
I found a very good solution to list all the global variables with the jsl command line tool:
Here is the documentation
I just have to put /*jsl:option explicit*/ into each file that I want to check. Then it is enough to run ./jsl -process <someFile> | grep 'undeclared identifier'
It is also possible to use referenceFile that contains some intentional global variables /*jsl:import <referenceFile>*/ so these variables will not be listed.
I'm writing a lot more JavaScript these days than I used to. I'm writing a bunch of JavaScript libraries for our product. Wanting to be as careful as possible I'm doing full jsdoc comments, etc. I also have 'use strict'; in all of my libraries and functions.
We're using jQuery and Kendo UI (no comments about whether these are good, bad, or indifferent, that ship has sailed). Both of these libraries have globals that they create, at the least "$" and "kendo" for each respectively. I'm using Visual Studio with Resharper so I get lots of help writing the JavaScript.
Now, here's my confusion. In my libraries, which are in files like LibraryName.js, I have to use both jQuery functions and kendo functions, so I'm doing things like $.ready(...) and kendo.keys.SPACEBAR. Visual studio gives me grief over "kendo" not being defined in strict mode, and it gives me grief about $.ready not being defined, but it doesn't give me grief over $ not being defined? Why is it special?
I know, this is a small thing, but I really want to understand what strict mode means and what the limitations are.
Thanks for reading!
Addition: Apparently I'm not being clear, so I'll try to expand. In strict mode, "...you can not, for example, use undeclared variables." Well, I don't see how one library file (say, mySuperLibrary.js) can use global values from another library file (jQuery or Kendo UI) without using "undeclared variables" as $ is a variable containing a function and kendo is as well. Neither of these are declared in my script, obviously.
What then confuses me is that Resharper complains that for $.ready, it flags "ready" as being undeclared but doesn't say $ is undeclared. It also flags kendo as being undeclared. The warning it gives me is "Using a variable (property or object) without declaring it is not allowed in 'strict mode'".
Now, my library works fine. It goes ahead and uses these "undeclared variables" to solve the problems it needs to solve. By the time my library loads these variables are declared.
In any other language I would somehow document in the file what external globals I require to be defined. I don't see any way to do that in JavaScript. There isn't any kind of "import" or "external requirements". I guess I'm wondering if I'm just missing something. There is no way to stop it from bugging me (so maybe the problem is my ocd, not wanting my libraries to have "fake" errors).
I've anecdotally noticed that use strict appears to be more common like this:
(function() {
'use strict';
...
Than this:
'use strict';
(function() {
...
The vanilla JS implementation of TodoMVC does this, for example.
Is there a reason for this?
Edit: I'm aware of the whole-file versus function-block distinction. TodoMVC is a good example to demonstrate why this placement is strange to me, because it doesn't rely on any external libraries, so the whole "play nice with non-strict third parties" doesn't apply here.
Declaring it in local scope will enforce function block to be considered under strict-mode by browser.
You can have non-strict observation for other code outside of the IIFE
Inside IIFE:
(function() {
"use strict";
a = 100;
})();
b = 200;
For entire script:
"use strict";
(function() {
try {
a = 100;
} catch (e) {
console.log(e + '');
}
})();
b = 200;
As highlighted in docs,
If you are using strict mode for entire script, it isn't possible to blindly concatenate non-conflicting scripts. Consider concatenating a strict mode script with a non-strict mode script: the entire concatenation looks strict! The inverse is also true: non-strict plus strict looks non-strict. Concatenation of strict mode scripts with each other is fine, and concatenation of non-strict mode scripts is fine. Only concatenating strict and non-strict scripts is problematic. It is thus recommended that you enable strict mode on a function-by-function basis (at least during the transition period).
You can also take the approach of wrapping the entire contents of a script in a function and having that outer function use strict mode. This eliminates the concatenation problem but it means that you have to explicitly export any global variables out of the function scope.
I’m guessing it’s because that placement is sure to enable strict mode even if multiple JS files are concatenated together as a build step (to allow organizing of code without the performance penalty of multiple HTTP requests). With placement of "use strict" at the beginning of the file, there could be a problem with these files:
foo.js
function doThing() {
console.log("done");
}
main.js
"use strict";
(function() {
document.getElementById('thingy').addEventListener("click", doThing);
})();
If the above files were concatenated with foo.js first, the "use strict" inside main.js would have no effect. This possibility could be avoided by putting the "use strict" inside the function.
I don’t know how common concatenation of JS is any more, and I don’t know whether the newer require method or import keyword lets you place "use strict" anywhere you want, but maybe the placement of "use strict" inside the function caught on while simple concatenation was popular, and people saw no reason to change the convention after using it for so long.
If you using:
'use strict';
(function() {
...
It will apply use strict mode to all file.
Opposite, when you using use strict in function like this:
// Non-strict code...
(function(){
"use strict";
...
// Define your library strictly...
})();
// Non-strict code...
That might be helpful if you have to mix old and new code.
Why Strict Mode At All
Strict mode eliminates certain permissive language parsing and execution characteristics deemed less desirable from a language design point of view. These non-strict mode language characteristics were deemed prudent as default behavior for backward compatibility. The synopsis and details appear here.
ECMA-262 7.0 Strict Mode Code
ECMA-262 7.0 Strict Mode in detail
It is not unambiguously defined when and if these older language characteristics from the early Netscape days will be deprecated or whether strict mode will become default behavior across browsers at some point, but the stricter model is likely to produce less ambiguous and risky source. If you wish to improving maintainability, portability, and extensibility in coding practice and code bases, then strict mode is a good option.
Syntax
"use strict";
Scope of Declaration
The scope of is dependent on whether you place the declaration inside or outside a function and applies to all statements following the declaration within the closure's scope.
Use of the declaration inside the function is the wrong way to do it if all of the file or stream is already compatible with the stricter mode or can be made so with ease. The redundancy is unnecessary, so placing the declaration on the top of the file or beginning of the stream is the recommended use.
Sometimes only some of the functions comply with the stricter rules. In such cases the less desirable function scope of the declaration can be used to encourage finer coding practices at least in the functions that already comply.
NOTE For those coming here from "What's the benefit of using "function() 'use strict'” in every file?"
You can place
"use strict";
on the top of the code sequence or inside the function, so it is only one line of code per file or per function.
The other lines of code have other purposes in the code here.
Self-invoking function
Factory invocation
At work I have to deal with a lot of (sometimes awful) JavaScript that vendors expect us to drop into our websites. Some of them add arbitrary, un-namespaced, names to the global scope. I've been toying with different ideas about sandboxing these programs so they don't have direct access to the global scope, but I haven't been able to think of anything that might actually work. (I thought of evalling the fetched code, but I'm convinced that's a bad idea.)
What solutions are there to keep the global scope clean while still using arbitrary 3rd party JavaScript?
Edit: #kirilloid's comment tells me I haven't been clear about how this code is delivered. I'm not usually given code to put into our website. Most of the time, I'm just given a URL and asked to create a script tag that points to it.
Your options are pretty limited. If the code is presented to you in the form of a <script> tag you can't modify, you can stop trying now.
If you can modify the script, you can wrap the code in a closure; this will stop any variables they declare with var being published in the global scope (but you'll still get problems with implicit globals).
(function () {
var aGlobalVariableThatUsedToCauseACollision = 4; // no longer collides!
anotherGlobalVariableThatUsedToCauseACollision = 4; // Mmmmm.
}());
Probably an infeasible option; you could use "use strict" which prevents them using implicit globals, but if the code is as awful as it seems, this won't help you.
An additional change (and prehaps the best) you could make could be to wrap your own code in a closure, and keep local copies of the important window properties (undefined) etc in there; this way you prevent other scripts affecting yours (this is what libraries such as jQuery do).
(function (jQuery, $, undefined) {
alert(undefined == 4); // false!
}(jQuery, $));
undefined = 4;