DEV Community

loading...

JavaScript's Forgotten Keyword (with)

Randall
Updated on ・4 min read

Being a JavaScript developer can be an exciting job. Almost every day you will find something mysterious and otherworldly. Sometimes that's a magical experience, other times it's downright frightening.

In this article we will take a look at the "with" keyword. It's one of those dark corners of the language that even veteran developers often are not aware of.

Usage

Let's use the with keyword to help us log a message to the console:

with (console) {
  log('I dont need the "console." part anymore!');
}
Enter fullscreen mode Exit fullscreen mode

And let's use it to help us join an array into a string:

with (console) {
  with (['a', 'b', 'c']) {
    log(join('')); // writes "abc" to the console.
  }
}
Enter fullscreen mode Exit fullscreen mode

Yes my friends, believe it or not, this is JavaScript.

What "with" Does

Here is the explanation from MDN:

JavaScript looks up an unqualified name by searching a scope chain associated with the execution context of the script or function containing that unqualified name. The 'with' statement adds the given object to the head of this scope chain during the evaluation of its statement body. If an unqualified name used in the body matches a property in the scope chain, then the name is bound to the property and the object containing the property. Otherwise a ReferenceError is thrown.

To reword that hopefully a little more simply: when you write an identifier in your code (like log or join in the above code snippet) there is a chain of objects that JavaScript looks at, and if one of those objects has a property with the same name as the identifier you wrote in your code, JavaScript uses the value of that property.

The with keyword lets you inject any arbitrary object into the front of that chain. Here's another example that might make that clearer:

with ({ myProperty: 'Hello world!' }) {
  console.log(myProperty); // Logs "Hello world!"
}
Enter fullscreen mode Exit fullscreen mode

Don't Use It

Awesome, right? Yeah, well, maybe not.

In most cases, the same effect can be achieved just by using temporary variables, which is easier than ever since the advent of destructuring.

In addition, MDN lists a number of pitfalls:

It's Forbidden in Strict Mode

You can't use with in strict mode. Considering that ES modules and classes are automatically in strict mode, this limitation kills even the possibility of using with in many modern use cases.

Accidental Shadowing

Consider the following code to average two numbers and round the result to an integer:

function getAverage(min, max) {
  with (Math) {
    return round((min + max) / 2);
  }
}

getAverage(1, 5);
Enter fullscreen mode Exit fullscreen mode

This returns NaN. Why? Because Math.min() and Math.max() shadow the function's arguments, so we end up calculating the sum of two functions, which of course, is NaN.

Basically if you use with, you suddenly have to be more careful about choosing identifiers. You have to go and look at what you are passing into with to make sure it does not have properties that might inadvertently shadow something else in a higher scope.

This behavior can also introduce security vulnerabilities. If an attacker is able to add properties to the object you pass to with, then they can shadow your identifiers and modify the behavior of your code in unexpected ways.

As one example, passing an object that was parsed from an unvalidated JSON HTTP request body to with would be extremely dangerous.

Performance

By adding something to the scope chain, you slow down just about every line of code, because you are increasing the number of objects that need to be searched to resolve your identifiers to values.

Ostracism

If you use the with keyword, everyone will think you are crazy and avoid you in the lunch room. Or maybe they will just look at you funny.

Either way, using magical language features that no one else knows about will make your code harder to maintain, and in this case won't gain you much.

Conclusion

The with keyword adds some interesting capabilities to the language, but ultimately it comes with too many downsides, and too few advantages, for me to be able to recommend using it.

Of course, don't just take it from me. MDN seems to hate it with a passion, and it is forbidden in strict mode for a reason.

I have been writing JavaScript for well over five years, and it amazes me that to this day I'm still learning language keywords that are not even remotely new. What else might be lurking out there?

Whence came with? Who envisioned it? Why? Did they want something like C++ namespaces? Did a Ouija board tell them to do it?

Whatever the case may be, it looks like the long-forgotten with statement will forever be relegated to the dustbin of history.

Though like many dark arts, it is fun to mess with!

Discussion (13)

Collapse
conradsollitt profile image
Conrad Sollitt

An example of the one use case I can think of is for simple templating. For example Underscore uses it on the template() function which can be called from modern JS:

underscorejs.org/docs/underscore-e...

Personally I've used it only 1 time I remember after doing JS for 20+ years and it was to create a templating feature for Web Components.

Collapse
bctnry profile image
Sebastian René Higgins • Edited

Very interesting! Two things come to my mind: with in Python (which is a totally different thing) and send* in Racket (which only does method call to one object). Probably started as some kind of a syntax sugar for multiple method call but ended up as a rather terrible design, especially when using with inside another with is allowed.

Collapse
tadeassoucek profile image
tadeassoucek

Pascal has a with ... do ... statement, which behaves in the same way as in JS.

Collapse
togakangaroo profile image
George Mauer

I've used it on a project where we created an in browser ide for days analysis. You would configure an object with properties for pluggable builtins, then surround the user's code in a with statement and emit it into a sandbox iframe.

Collapse
froxxninethree profile image
Froxx93

Wow, this sounds absolutely horrible from today's point of view 😅 I wonder what the original idea behind it was. I mean what made the devs think something like this would be necessary or improve the language?

Collapse
zevanrosser profile image
Zevan Rosser

I always liked with :D... how about labels? I remember being weirded out the first time I saw them: developer.mozilla.org/en-US/docs/W...

Collapse
kenovienadu profile image
Ovienadu Ken

I saw this in a c# codebase a few days ago.

Funny how it's usage is similar

Collapse
djlazz3 profile image
Bryan Padron

The only time that I've used this is when in the node console where you can run
with(process) { exit() }, but .exit is definitely a better way to exit

Collapse
yw662 profile image
yw662

Or let's make it process?.exit(), then you can use it anywhere :-)

Collapse
zyabxwcd profile image
zyabxwcd

You have a good sense of humour :D. Nicely written article.

Collapse
sangdt profile image
meomeo • Edited

This bring back so much memory when i was young and messing around with vb.net.

Collapse
miketalbot profile image
Mike Talbot

If only JS with worked like the vb.net it would be much more useful and no accidental shadowing :)

Collapse
samuelfaure profile image
Samuel FAURE

"If you use the with keyword, everyone will think you are crazy and avoid you in the lunch room. Or maybe they will just look at you funny."

As they should.