2

Assume I have a legacy file called module.js which is like this:

a=1;

This by default attaches to the window object polluting the global (actually window) scope when you execute it in the browser.

Is it possible for me to attach it to a different object instead without changing the contents of the source code?

Since the only real problem is the execution context and nothing else, an ideal solution would be something like this:

change execution context from window to module object;
execute the code;
change execution context from module to window object;

If this is not possible, adding wrappers (like IIFE) to the source code is fine as long as the inner contents are not changed. Changing the inner contents needs a full scan of the code which is expensive.

I can, for example, wrap it into a function like this (✓):

function module()
{
    a=1;
}

If it is executed in strict mode, I can avoid global scope pollution. However, I can't get hold of the object.

I don't want to do something like this (✗):

module = function module()
{
    return a=1;
}

because we need to add return wherever there is an assignment and that means scanning the entire code.

I am just trying to see ways to improve legacy code meant for the browser with minimal effort.

Nishant
  • 20,354
  • 18
  • 69
  • 101
  • How do you load the code? How do you execute the module function? – Luca Rainone May 05 '18 at 09:18
  • @Luca Rainone, Using the `script` tag since it is for browser usage. – Nishant May 05 '18 at 09:28
  • 1
    How big is your legacy code? And what kind of changes you want to do? Have you considered refactoring tools such [jscodeshift](https://github.com/facebook/jscodeshift) or [graspjs](https://github.com/gkz/grasp) they are a bit complex but very powerfull allowing you to write transforms and apply to the whole code base. – Moti Korets May 05 '18 at 09:50
  • Thanks for the recs @MotiKorets. It is a theoretical question, I don't have an immediate use case, but I just wanted to understand how to tackle this problem. – Nishant May 05 '18 at 10:06
  • 1
    There's no a clean way. You should change the function at runtime (with i.e. module.toString().replace(/*somethingofmagic*/) and put it inside an eval. Dirty and dangerous. So the better way will be a refactor with the help of some tool, as suggested – Luca Rainone May 05 '18 at 10:14
  • 1
    Web workers would do it, and realms might one day fill this role. But no, you really should write clean code in the first place. – Bergi May 05 '18 at 12:56
  • 1
    Alternatively, use strict mode so that you at least get an exception, and the global scope is not polluted by accidental assignments – Bergi May 05 '18 at 13:00

1 Answers1

1

The answer to the first question, no it is not possible to change the default execution context in the browser. window is a special variable and assigning anything else to it will not change default execution context. See Global Object in MDN. And here is an illustration

(function() {
  window = {}
  a = 5 // leaking declaration
  var b = 10
})()

console.log(a) // a is on global scope
//console.log(b) // exception b is not defined in this scope
var b = 5
window = new Object()
window.c = 5
console.log(window.b) // 5 
console.log(c)  // 5

The answer to the second part about how to work with legacy code, there are many tools which do AST transformation and depending on your goal you should probably use one or more of them.

  • jscodeshift allows you to write codemods which are functions that receive code and apply transformations to it. This is probably the most powerful tool in this category.
  • ESLint allows you to set rules (for example no global vars) and have a --fix option which will apply automatic fixes in some cases like changing from single quote to double quotes (this is mostly for style related rules).
  • prettier is a code formatter only concerned with code appearance: indentation, spaces etc.
  • AST Explorer an online tool that lets you see the internals of all the above tools very useful to understand how it works and try code on small examples.
Nishant
  • 20,354
  • 18
  • 69
  • 101
Moti Korets
  • 3,738
  • 2
  • 26
  • 35