JavaScript Variable of the Week (JS VOW)
Teaching JavaScript through vocabulary...
or vocabulary through JavaScript...
(or maybe neither)
foist [ foist ]
// Foist [ foist ]:
const foist = (obj, upon = globalThis) => {
Object.entries(obj).forEach(
([key, value]) =>
Object.defineProperty(upon, key, {
value,
writable: false, // :D
})
);
};
Usage:
foist({ jsvow: 'great' });
console.log('jsvow is', jsvow);
// logs "jsvow is great"
Abusage:
// Browser
foist({ jQuery: 'http://youmightnotneedjquery.com/' });
window.jQuery = actualJQuery;
// throws an error in strict mode :D
foist({ random: () => 0.5 }, Math);
Math.random();
// always returns 0.5! (not so random...)
// Node
foist({ setTimeout: "don't actually do this!" });
setTimeout(doSomething, 100);
// throws an error (in ANY mode)
Try it out!
You can play around with foist
if you open the JavaScript console on this page. You’ll see a friendly message and you can run something like the following:
> JSVOW.foist({ foisting: 'awesome' })
// undefined
> foisting
// 'awesome'
Don’t speak JavaScript? Here is the actual definition of foist.
Thoughts
I wanted to start this series off with foist
because I think foist
has the potential to become part of the officially recognized JavaScript vernacular. I mean, it rhymes with another established JavaScript term (hoist) and foisting is a concept that already exists in JavaScript. Consider the following code:
function logSomeThings(a, b) {
var thingA = "here is thingA: " + a;
thingB = "here is thingB: " + b;
console.log(thingA, thingB);
}
If you run logSomeThings
anywhere in the browser, you will be able to access window.thingB
anywhere else in the browser. Basically, if you forget to declare a variable in a function, it gets foist
upon the window object. Many would argue that this “feature” belongs in JavaScript: The Bad Parts.
DISCLAIMER: 🤔 Ok, so maybe don’t actually use this foist function.
Nowadays, we can use let
and const
to be more explicit about the scope of our variables.
FUN FACT: with
let
andconst
, your variables are neither foisted nor hoisted!
So the next time you are doing a code review and you come across an example like logSomeThings
above, you can make a comment like, “Looks like you are foisting thingB
. Consider revising.”
Maybe it will catch on?
* globalThis
* <- What’s that?
It’s a shiny new feature!
One goal of the JSVOW series is to try to introduce new features in a fun way. Without globalThis
, it can get pretty messy to find the global object in different JavaScript environments. The global object is called window
in the browser, global
in node, self
in workers and kind of doesn’t exist in modules. globalThis
lets us assign things globally in an environment-agnostic way.
We can do this:
globalThis.value = 'my cool value';
Instead of this:
const getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
const oneGlobalToRuleThemAll = getGlobal();
oneGlobalToRuleThemAll.value = 'my cool value';
Why?
It’s nice to be able to write an incredibly useful utility (like foist
) and have some confidence it will run in all JavaScript environments. This is called Isomorphic JavaScript. There are a lot of other things to consider when writing Isomorphic JavaScript, but globalThis
provides an elegant solution to the consideration accessing the global object.
Install
You can foist (with caution) in your own projects by installing foist
from npm:
npm install foist
And in your code:
import foist from 'foist';
foist({ window: 'not the window' });
// fortunately this doesn't work :D
NOTE:
foist
is only compatible with new versions of Chrome and Firefox and Node >=12 or so.