JavaScript Variable of the Week (JS VOW)

Teaching JavaScript through vocabulary...

or vocabulary through JavaScript...

(or maybe neither)

Week of January 3, 2020

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 and const, 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.