Reputation: 16782
Looking at all the information out there on JSlint (eg. here or here), the discussion goes something like this
Always use strict mode since it catches many more errors. All you have to do is put 'use strict' at the top of your code. That's it! Couldn't be easier... Except when JSlint complains and tells you to put it in function scope, then you have to put all of your code inside a giant function.
I have hundreds of functions written in javascript and at a minimum the <body>
calls a callback function on load so I am trying to wrap my head around how I am supposed to put all my functions inside another function but still ensure that the <body>
element can still pierce the outer function and call my functions with the internal scope.
Can someone tell me how I would implement strict mode for something like so
function foo(){
"use strict"; /* Approach 1: Putting inside every function */
/* Extremely tedious and ugly */
$('#example').text('Hello '+ bar());
}
function bar(){
"use strict"; /* Approach 1: Putting inside every function */
/* Extremely tedious and ugly */
return 'Beautiful';
}
function fooBar (){
"use strict"; /* Approach 2: Putting once at the top of an outer function */
/* But now how does <body> call this function? */
function foo(){
"use strict";
$('#example').text('Hello '+ bar());
}
function bar(){
"use strict";
return 'Beautiful';
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body onload="foo();">
<p id='example'>
</p>
</body>
Upvotes: 1
Views: 1194
Reputation: 16782
Although CertainPerformance's answer is IMO the best one here, I still wanted to respond to my own question within the context of what I meant, perhaps not how I worded it exactly.
Some programming languages don't seem to care much about scoping (I'm looking at you Python), but most mature ones, with C++ being the strongest, provide some form of scoping like so
/* Begin Pseudocode */
include <a>; /* Include some external library */
external var external_a; /* Indicate that it is defined externally */
var global_a; /* Create global scope variable */
function xyz (p_1, p_2); /* Declare global scope function */
function xyz (p_1, p_2){ /* Define function */
return p_1 * external_a + p_2 * global_a; /* Example calculation */
}
Javascript doesn't really export so you have to put all of this inside a function and return an object within a class and hack that to get a sense of private vs public, somewhat like so
(() =>{
var global_a; /* Global function scope */
let xyz; /* Declare function */
xyz = function (p_1, p_2){ /* Define function */
return p_1 * p_2; /* Example calculation */
};
return { /* Finally, we have to manually return the function */
/* designating it as public in the process */
xyz: xyz
};
}(external_a); /* passed externally, essentially making it a global */
Having to refactor your codebase in such a bizzare way is usually a red flag of a poor programming language where you are essentially hacking the syntax to get the functionality that you want, turning yourself into a quasi compiler in the process, but I have another problem with this approach: it leads to bad programming practices like variables being defined but never used. If you run the above javascript code through JSHint it will complain that xyz is defined but never used
. Technically it's right but that's the whole essence of all APIs: write once, use later...maybe. Then that leads to a whole down the rabbit hole expedition of trying to suppress some JSHint errors (like xyz
being defined but never used) while not suppressing others (like a
being defined but never used). There might be a way to configure JSHint to recognize this special case, but my point is that that there should be a single clean way to achieve this outcome and JSHint should be configured for that approach only.
Now Javascript technically does have an export function and it could be used like so, but to me a strong language should create a module based on a file, not based on a heavily modified version of that file, and that furthermore that module should be imported not exported
var module_a = (() =>{
var global_a; /* function scope */
let xyz; /* Declare function */
xyz = function (p_1, p_2){ /* Define function */
return p_1 * p_2; /* Example calculation */
};
return {
xyz: xyz
};
}(external_a); /* passed externally */
export module_a;
I guess what I am trying to say, and I feel like I am going to get a great deal of push back on this from this community, is that Javascript wants to be an OO language with advanced features but hacking it to do one thing reveals a weakness which then has to be hacked again. The failure of the Javascript online community to deal with these shortcomings leads to detatched-from-reality online tutorials like this one (source)
[A] Module [a] is self-contained and reusable chunk of JavaScript code written in a modular way. Until ES6 JavaScript did not define any language construct for working with modules. So writing modular JavaScript involves the use of some coding convention.
Now this is one of the more honest tutorials out there, but coding convention seems a little watered down and neutered for my taste. Essentially what the author is saying is that there is no clean way to do it, so you unfortunately have to hack it.
So, my long winded answer to my original question is this: You have to take your entire codebase, which was all global scope and an easy to use API, and put it inside an anonymous function and then stick a "use strict";
at the top so JSHint works, then whatever API endpoints you need to make publicly available you return in a giant object, and then when JSHint complains about variables being declared but not used you stick a /* jshint line: ignore */
comment there, then remove that comment if and when it turns out not to work (most likely deprecated) so switch that out with surrounding the unused variables portion with (/* jshint unused: false */
... /*jshint unused: true */
) and then at the end of your page export your returned object and import it somewhere else and use it.
Upvotes: 0
Reputation: 370789
In modern JavaScript, inline handlers should be avoided whenever possible since they require global pollution, require ugly quote escaping with some arguments, and have absurd scope chain rules. So, try removing the inline handlers and put your JavaScript into an IIFE, which can be made strict:
(() => {
"use strict";
function foo() {
$('#example').text('Hello ' + bar());
}
function bar() {
return 'Beautiful';
}
window.addEventListener('DOMContentLoaded', foo);
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<p id='example'>
</p>
</body>
If you have any other inline handlers similar to <body onload="foo();">
, I'd highly recommend refactoring them out.
Upvotes: 2