Skip to content

Instantly share code, notes, and snippets.

@peter-leonov
Created April 20, 2020 18:18
Show Gist options
  • Save peter-leonov/55c3f6cc8083e31d071f90812000e1dd to your computer and use it in GitHub Desktop.
Save peter-leonov/55c3f6cc8083e31d071f90812000e1dd to your computer and use it in GitHub Desktop.
Primitive closure implementation in JS to illustrate that closure is "just" an object
class RootScope {
constructor() {
this.map = new Map();
}
add(name, value) {
return this.map.set(name, value);
}
set(name, value) {
return this.map.set(name, value);
}
get(name) {
if (this.map.has(name)) {
return this.map.get(name);
}
throw new Error(`ReferenceError: ${name} is not defined`);
}
}
class Scope {
constructor(parentScope) {
this.parent = parentScope;
this.map = new Map();
}
add(name, value) {
this.map.set(name, value);
}
set(name, value) {
if (this.map.has(name)) {
return this.map.set(name, value);
}
return this.parent.set(name, value);
}
get(name) {
if (this.map.has(name)) {
return this.map.get(name);
}
return this.parent.get(name);
}
}
class Closure {
constructor(parentScope, fn) {
this.scope = new Scope(parentScope);
this.fn = fn;
}
call(...args) {
return this.fn.call(null, this.scope, ...args);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function _inner(scope) {
return scope.get("x") + scope.get("y");
}
function _main(scope) {
scope.add("y", 5);
const inner = new Closure(scope, _inner);
return inner;
}
const globalScope = new RootScope();
globalScope.set("x", 7);
const outer = new Closure(globalScope, _main);
const closure = outer.call();
console.log(closure.call());
globalScope.set("x", 10);
console.log(closure.call());
console.log("done");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment