# Detect Strict Mode

**URL:** <https://es.discourse.group/t/detect-strict-mode/1549>\
**Category:** 💡 Ideas\
**Created:** [December 10, 2022, 4:24pm UTC](https://es.discourse.group/t/detect-strict-mode/1549 "2022-12-10T16:24:04Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![0X-JonMichaelGalindo](https://avatars.discourse-cdn.com/v4/letter/0/4af34b/32.png) [@0X-JonMichaelGalindo](https://es.discourse.group/u/0X-JonMichaelGalindo)\
**Post date:** [December 10, 2022, 4:24pm UTC](https://es.discourse.group/t/detect-strict-mode/1549/1 "2022-12-10T16:24:04Z")

</div>

Can we have a way to detect if code is running in strict mode?

See the issue and work-around hacks here:

[https://stackoverflow.com/questions/10480108/is-there-any-way-to-check-if-strict-mode-is-enforced](https://stackoverflow.com/questions/10480108/is-there-any-way-to-check-if-strict-mode-is-enforced)

I just spent an hour trying to figure out how to detect whether a variable had been declared, and whether or not it had a particular type, but accessing a non-declared variable is an error only in strict mode. Depending on what place and mode my code was running in, it would or would not work.

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [December 10, 2022, 8:49pm UTC](https://es.discourse.group/t/detect-strict-mode/1549/2 "2022-12-10T20:49:25Z")

</div>

> [@0X-JonMichaelGalindo](#):
>
> I just spent an hour trying to figure out how to detect whether a variable had been declared,

`typeof variable !== undefined` will check that a variable is both declared and not set to `undefined`.

Would you be able to expand on why you needed to check if a variable had been defined?

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [December 10, 2022, 9:21pm UTC](https://es.discourse.group/t/detect-strict-mode/1549/3 "2022-12-10T21:21:07Z")

</div>

[https://npmjs.com/has-strict-mode](https://npmjs.com/has-strict-mode) detects if the environment _supports_ strict mode; the same code can be used to detect if the current function is in strict mode or not.

However, it seems bizarre to be writing a function and not know what mode it's in, and indeed using `typeof` as described is the way it's always been done in JS, since long before strict mode existed.

---

<div class="post-metadata">

**Author:** ![0X-JonMichaelGalindo](https://avatars.discourse-cdn.com/v4/letter/0/4af34b/32.png) [@0X-JonMichaelGalindo](https://es.discourse.group/u/0X-JonMichaelGalindo)\
**Post date:** [December 11, 2022, 12:43am UTC](https://es.discourse.group/t/detect-strict-mode/1549/4 "2022-12-11T00:43:23Z")

</div>

Yep. My code that was problematic:

```javascript
if( insecureImport && typeof insecureImport === "function" ) {
   ...
}

```

Ran fine in most cases, then suddenly failed with `ReferenceError` in strict mode.  
The solution was to truncate it to:

```javascript
if( typeof insecureImport === "function" )

```

`typeof` is apparently a completely undocumented and unique means of bypassing undeclared access `ReferenceError` in strict mode.

I've checked the MDN docs for `typeof` and `ReferenceError` and strict mode, as well as the 262 spec for all three. (The spec claims that `ReferenceError` only throws on unresolvable assignation, which is not the case at all. [https://262.ecma-international.org/13.0/#sec-strict-mode-of-ecmascript](https://262.ecma-international.org/13.0/#sec-strict-mode-of-ecmascript))

* * *

The reason you need to check if a variable has been defined, if you really want to know:

When you're loading modules dynamically in insecure contexts (e.g. web tools that cannot be exposed to Internet traffic, served over workplace intranet to BYOD phones / tablets), you can't use import, so you just have to append a `<script>` element and wait for it to load. There's no way to check if a script element has finished executing, so you just have to keep checking if its global-variable exports have been defined.

---

<div class="post-metadata">

**Author:** ![0X-JonMichaelGalindo](https://avatars.discourse-cdn.com/v4/letter/0/4af34b/32.png) [@0X-JonMichaelGalindo](https://es.discourse.group/u/0X-JonMichaelGalindo)\
**Post date:** [December 11, 2022, 12:57am UTC](https://es.discourse.group/t/detect-strict-mode/1549/5 "2022-12-11T00:57:43Z")

</div>

Global `!this` detects if the environment supports strict mode, but for any function with `this` already bound, it's useless. (So, generally useless.)

`typeof` has an undocumented ability to bypass strict mode's unresolvable access `ReferenceError`, which can, in turn, also be used to detect strict mode (but any of strict mode's errors can be used this way), which is a hackish solution. There's no official way to detect it.  
It's a minor headache when compiling inline pieces of JS. (I say minor because I've never wasted so much time tracking down this bug before today.)

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [December 11, 2022, 2:40am UTC](https://es.discourse.group/t/detect-strict-mode/1549/6 "2022-12-11T02:40:15Z")

</div>

> [@0X-JonMichaelGalindo](#):
>
> `typeof` is apparently a completely undocumented and unique means of bypassing undeclared access `ReferenceError` in strict mode.

Perhaps you just missed it?

It's right here: [typeof - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof#interaction_with_undeclared_and_uninitialized_variables) (under "Interaction with undeclared and uninitialized variables")

> [@0X-JonMichaelGalindo](#):
>
> When you're loading modules dynamically in insecure contexts (e.g. web tools that cannot be exposed to Internet traffic, served over workplace intranet to BYOD phones / tablets), you can't use import, so you just have to append a `<script>` element and wait for it to load. There's no way to check if a script element has finished executing, so you just have to keep checking if its global-variable exports have been defined.

If we're talking about global variables, there's another option.

```javascript
'myGlobalVar' in globalThis;

```

I personally would use the above pattern whenever you want to check for the existence of a global variable - I feel like it does a better job at conveying intent. But, the `typeof` check works there too. Really, the only value I see in this `typeof` check is to check if a local variable has been declared or not, but there's no practical reason for such a feature, because one can always know if a local variable will be declared or not just by looking at their code. Because of this, I personally never use `typeof` to check for the existance of something undeclared.

---

<div class="post-metadata">

**Author:** ![0X-JonMichaelGalindo](https://avatars.discourse-cdn.com/v4/letter/0/4af34b/32.png) [@0X-JonMichaelGalindo](https://es.discourse.group/u/0X-JonMichaelGalindo)\
**Post date:** [December 11, 2022, 3:07am UTC](https://es.discourse.group/t/detect-strict-mode/1549/7 "2022-12-11T03:07:36Z")

</div>

I definitely missed it. I really _really_ want to delete this whole post. It feels like a naive stackoverflow question, not an idea at all.

`'insecureImport' in globalThis` returns `false` for me, but from the top-level, global context, `typeof insecureImport === "function"`. Is that really how global variables work? (I mean, it probably is and I'm just doing something else wrong. Thanks for all your patient help, feel free to drop this thread.)

![in globalThis](https://global.discourse-cdn.com/free1/uploads/es/original/2X/6/65881c2ba6b25870b92ca599aa31c3f338bd34b5.png)

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/senocular/32/642_2.png) [@senocular](https://es.discourse.group/u/senocular)\
**Post date:** [December 11, 2022, 2:02pm UTC](https://es.discourse.group/t/detect-strict-mode/1549/8 "2022-12-11T14:02:03Z")

</div>

Lexical declarations in the global scope will not go in the global object

```typescript
// global scope
var myVar = 1
console.log("myVar" in globalThis) // true

let myLet = 2
console.log("myLet" in globalThis) // false

```

`typeof` can be used to detect these globals.

```typescript
let myLet = 2
console.log(typeof myLet) // number

```

Assuming you do so outside the TDZ of the declaration since `typeof` will not save you there.

```typescript
console.log(typeof myLet) // Error
let myLet = 2

```

But I think the only way you could get yourself into this situation is if you're working with generated/injected code that you have no control or knowledge of... you know, like "when compiling inline pieces of JS". I think at that point you'd have to account for the possibility of the error with a `try..catch`.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [December 11, 2022, 2:40pm UTC](https://es.discourse.group/t/detect-strict-mode/1549/9 "2022-12-11T14:40:36Z")

</div>

> [@0X-JonMichaelGalindo](#):
>
> `'insecureImport' in globalThis` returns `false` for me, but from the top-level, global context, `typeof insecureImport === "function"`.

You said "insecureImport" is coming from something loaded via a script tag? How exactly is this piece of code registering this global?

If it's truly global, then it should be on globalThis. If it's not, then it should be local to that script tag, and the other script tag shouldn't see it - this scenario would be the "Lexical declarations in the global scope" that @senocular mentioned.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [December 11, 2022, 3:08pm UTC](https://es.discourse.group/t/detect-strict-mode/1549/10 "2022-12-11T15:08:11Z")

</div>

To elaborate, these are the ways I know of to declare a global.

1. Explicitly attach it to `globalThis` or `window`

```html
<script>
  globalThis.myExport = 'Hello World!';
</script>
<script>
  console.log('myExport' in globalThis); // true
</script>

```

1. Declare a variables in sloppy mode without using let/var/const.

```html
<script>
  myExport = 'Hello World!';
</script>
<script>
  console.log('myExport' in globalThis); // true
</script>

```

1. Declare a variable using "var", in the global scope

```html
<script>
  var myExport = 'Hello World!';
</script>
<script>
  console.log('myExport' in globalThis); // true
</script>

```

If any other scenario, the variable should end up local to the script tag, and another script tag will not be able to see it.

```html
<script>
  let myExport = 'Hello World!';
</script>
<script>
  console.log('myExport' in globalThis);
  const x = myExports; // ReferenceError
</script>

```

* * *

To test your setup, I wouldn't rely on the dev-tools REPL - those are sometimes enhanced with ease-of-use features. For example, I noticed that even though I was unable to view the "myExport" variable in another script tag in this last example, I could still put "\> myExport" in the dev-tools and get back out its value. It seems the dev-tools were allowing me to access variables local to individual scripts.

---

<div class="post-metadata">

**Author:** ![bergus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bergus/32/152_2.png) [@bergus](https://es.discourse.group/u/bergus)\
**Post date:** [December 11, 2022, 3:43pm UTC](https://es.discourse.group/t/detect-strict-mode/1549/11 "2022-12-11T15:43:32Z")

</div>

> [@theScottyJam](#):
>
> If any other scenario, the variable should end up local to the script tag, and another script tag will not be able to see it.
> 
> ```javascript
> <script>
> let myExport = 'Hello World!';
> </script>
> <script>
> console.log('myExport' in globalThis);
> const x = myExports; // ReferenceError
> </script>
> 
> ```

Not quite - a lexical declaration (`let`, `const`, `class`) still may declare a global variable that will be available in subsequent scripts, despite [not creating a property on the global object](https://stackoverflow.com/q/28776079/1048572). It will cause an error if you attempt to declare it a second time (unlike `var`).  
The `ReferenceError` in your example occurs only because of the typo `myExport`\<\>`myExports`.

---

<div class="post-metadata">

**Author:** ![bergus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bergus/32/152_2.png) [@bergus](https://es.discourse.group/u/bergus)\
**Post date:** [December 11, 2022, 3:49pm UTC](https://es.discourse.group/t/detect-strict-mode/1549/12 "2022-12-11T15:49:31Z")

</div>

> [@0X-JonMichaelGalindo](#):
>
> You can't use import, so you just have to append a `<script>` element and wait for it to load. There's no way to check if a script element has finished executing, so you just have to keep checking if its global-variable exports have been defined.

You could use the `script.onload` event for that, but really this whole issue appears to be a solved problem. Use [Asynchronous Module Definition](https://github.com/amdjs/amdjs-api) instead of rolling your own! It's supported by tooling (bundlers, transpilers) since years, you can just use standard module syntax in your source code.

---

<div class="post-metadata">

**Author:** ![0X-JonMichaelGalindo](https://avatars.discourse-cdn.com/v4/letter/0/4af34b/32.png) [@0X-JonMichaelGalindo](https://es.discourse.group/u/0X-JonMichaelGalindo)\
**Post date:** [December 11, 2022, 5:42pm UTC](https://es.discourse.group/t/detect-strict-mode/1549/13 "2022-12-11T17:42:45Z")

</div>

`script.onload` fires before a script executes; it's always been useless. (A script is not guaranteed to "finish" executing anyway; the halting problem.) The process I'm describing is exactly how you would implement AMD. You just have to wait and hope.

But I was unaware of the global distinction between lexical declarations vs. variables. That is definitely a quirk I needed to be aware of, so thank you for clarifying it.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [December 11, 2022, 7:31pm UTC](https://es.discourse.group/t/detect-strict-mode/1549/14 "2022-12-11T19:31:58Z")

</div>

> [@bergus](#):
>
> Not quite - a lexical declaration (`let`, `const`, `class`) still may declare a global variable that will be available in subsequent scripts, despite [not creating a property on the global object](https://stackoverflow.com/q/28776079/1048572). It will cause an error if you attempt to declare it a second time (unlike `var`).

Huh, learned something new today. Thanks for catching my type-o.

I guess that is one use for `typeof possiblyDeclaredVariable` then that nothing else can properly substitute.

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [December 11, 2022, 8:35pm UTC](https://es.discourse.group/t/detect-strict-mode/1549/15 "2022-12-11T20:35:19Z")

</div>

> [@0X-JonMichaelGalindo](#):
>
> `script.onload` fires before a script executes

Uh? Afaik the HTML spec guarantees exactly the opposite. I haven't used that technique in years, but onload firing after execution is also what I recall of the behavior.

> [@0X-JonMichaelGalindo](#):
>
> A script is not guaranteed to "finish" executing anyway; the halting problem

If you have a synchronous infinite loop, no mechanism would be able to preempt it. If you have some kind of asynchronous loop or events triggering further execution, the load event will trigger right after the synchronous execution of the script is complete.

---

<div class="post-metadata">

**Author:** ![0X-JonMichaelGalindo](https://avatars.discourse-cdn.com/v4/letter/0/4af34b/32.png) [@0X-JonMichaelGalindo](https://es.discourse.group/u/0X-JonMichaelGalindo)\
**Post date:** [December 12, 2022, 10:29am UTC](https://es.discourse.group/t/detect-strict-mode/1549/16 "2022-12-12T10:29:57Z")

</div>

Oh! You are correct about that event order. I just checked the spec, then tested it. Learned another new thing on this thread. :-)

You can't predict whether a script will need asynchronous events before its exports are ready, so the event is probably still not usable.

Also, Firefox (and Chrome?) allows the user to preempt infinite loops while still keeping the page's DOM and other scripts alive. (You get a prompt asking if you want to stop a script.) The halting problem _does_ apply. But in general, `onload` is not guaranteed to fire because `onerror` can fire instead; I stand by that part of my original statement: a script is never guaranteed to finish executing. (But as long as you listen to both events... maybe you can guarantee one or the other will fire? Maybe???)

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [December 12, 2022, 1:41pm UTC](https://es.discourse.group/t/detect-strict-mode/1549/17 "2022-12-12T13:41:45Z")

</div>

> [@0X-JonMichaelGalindo](#):
>
> You can't predict whether a script will need asynchronous events before its exports are ready, so the event is probably still not usable.

If a script requires asynchronous init, it's that script's duty to synchronously install a mechanism that the loader can use to get a callback once the script is ready.

Regarding load failures, I believe onerror is guaranteed to trigger, which means you can rely on either onload or onerror to trigger. That's a question for the html spec.

Regarding host pre-emption mechanisms, I'm not sure how they're implemented. If I had to guess, it's an exception raised during the infinite loop? I am actually not aware of a case where a script doesn't run to completion but further execution in the same agent is allowed. I am actually curious about this because our team considered at some point using an infinite loop to "shim" uncatchable errors.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [December 12, 2022, 3:02pm UTC](https://es.discourse.group/t/detect-strict-mode/1549/18 "2022-12-12T15:02:50Z")

</div>

> [@0X-JonMichaelGalindo](#):
>
> The halting problem _does_ apply. But in general, `onload` is not guaranteed to fire because `onerror` can fire instead; I stand by that part of my original statement: a script is never guaranteed to finish executing. (But as long as you listen to both events... maybe you can guarantee one or the other will fire? Maybe???)

While it's true that we can't predict whether or not a script will stop executing, it's also true that if a script takes longer than a couple of eye blinks to load, then it's got a major bug, and it's perfectly valid to treat that as a timeout error if you wish - even if you don't, as you mentioned, the browser could treat it like a bug and present the end-user with a kill-switch prompt. Script-loading time is the wrong time to try and run fancy algorithms that could take an unknowable amount of time to execute. That kind of stuff should go into a function and be exported by the script. Script-loading time should be reserved for loading resources over the internet, and if wanted, performing some trivial initialization tasks, and that's it.

So, you should be able to listen to both onload and onerror, and if you wish, you can also set a timeout.

And, as @mhofman mentioned, if the script really does need to perform some async logic during load-time (I have yet to see a library that needed this - I know it can happen, but it's not common), it should export some sort of event function that will notify you when it's done loading.

Finally, I wonder if script-based loading is actually necessary. If you're allowed to do your loading from modules, then all of these problems will be solved for you.

Here's a normal load example, where you need to make sure that the first module finishes loading before the second.

```javascript
import 'someModuleThatRegistersAGlobal';
import 'yourLibraryThatExpectsTheGlobal';

```

And, if you suspect that the module requires async logic as it loads, you can just do this.

```javascript
await import 'someModuleThatRegistersAGlobal';
import 'yourLibraryThatExpectsTheGlobal';

```

---

<div class="post-metadata">

**Author:** ![0X-JonMichaelGalindo](https://avatars.discourse-cdn.com/v4/letter/0/4af34b/32.png) [@0X-JonMichaelGalindo](https://es.discourse.group/u/0X-JonMichaelGalindo)\
**Post date:** [December 12, 2022, 9:18pm UTC](https://es.discourse.group/t/detect-strict-mode/1549/19 "2022-12-12T21:18:29Z")

</div>

Modules require secure contexts, which are not possible in the scenario I described. Because management reject basic security concepts and insist their vague Internet security ideas from the 90s are better. (Otherwise this wouldn't have been an issue in the first place.) I'm using both events, and logging a recurring load-timeout warning (which usually means a script didn't initialize something the way it's API said it was supposed to).

---

<div class="post-metadata">

**Author:** ![0X-JonMichaelGalindo](https://avatars.discourse-cdn.com/v4/letter/0/4af34b/32.png) [@0X-JonMichaelGalindo](https://es.discourse.group/u/0X-JonMichaelGalindo)\
**Post date:** [December 14, 2022, 11:39am UTC](https://es.discourse.group/t/detect-strict-mode/1549/20 "2022-12-14T11:39:49Z")

</div>

@mhofman since you said you were "not aware of a case" like this, here is an example of a script that (may) not run to completion. When (if) it is preempted, further execution on the page remains possible.

Warning, do not click this link! It is a long, memory-heavy loop!  
[https://rawcdn.githack.com/0X-JonMichaelGalindo/LinkedMobyThesaurus/14cfc060d4032741600fb63b9557713762ee5371/index.html](https://rawcdn.githack.com/0X-JonMichaelGalindo/LinkedMobyThesaurus/14cfc060d4032741600fb63b9557713762ee5371/index.html)  
You have been warned.

The example I've linked here is a searchable thesaurus I created that proved far too resource-intensive to use. I have uploaded it to GitHub and disabled the limiters / segmenters to force it into a single, long, memory-heavy loop.

Depending on how many other tabs I have open, whether I have run this page before in this browser session, whether I am using Firefox or Chrome, whether or not I have dev tools open, and perhaps other factors, I will get different behavior: including repeated prompts asking me if I would like to stop the script, a crashed tab, an out-of-memory-error, or a paused-before-potential-out-of-memory event. Sometimes, it simply runs to completion and becomes searchable (after a few minutes).

To execute in the agent after preemption (if it occurs), use the console. You can run a search despite the thesaurus being unprepared using `executeSearch()`, or trigger a download of a partially linked state via `downloadParsedThesaurus()`.

* * *

The webapp loads the Moby thesaurus (~24MB), and links words:

- If A \> is a synonym of B \> is a synonym of C,
- Then A \> is a synonym of C

Word links are weighted by frequency of found links.

The linked thesaurus is searchable or downloadable as JSON (~1.3GB)  
It is not a practical tool for use, due to the long time necessary to build the links before searching, and due to the large memory requirements.

[Next page](https://es.discourse.group/t/detect-strict-mode/1549.md?page=2)
