0.3.0 • Public • Published

    Scototypes (Scoto)

    Nestable, Testable, Isolable Scopes using Prototype chains


    Since ECMAscript 3, scopes are a foundational element of JavaScript. Concepts like closures depend on the automatic creation of severally-nested scopes. Scopes are not without complications. They all chain up to the root object. They shadow variables. They can't be shared directly.

    For most purposes, though, scopes are quite like prototypes.

    Enter Scototypes

    Scototypes provide the nesting and hierarchy of scopes using JavaScript prototypes. You can walk the hierarchy of a scototype, isolate the current, attach it to a different chain, or even flatten the hierarchy into a new object.

    Scototypes can mimic regular scopes by starting with your root object:

    const myScope = Scoto.child(window);
    const nestedScope = Scoto.child(myScope);
    nestedScope.console.log('This works!');

    Or you can make isolated scopes:

    const myIsolatedScope =;
    const nestedScope = Scoto.child(myIsolatedScope);
    // console is undefined.
    nestedScope.console.log('This will error.'); 

    Scototypes use a few simple prototype methods to support nesting scope or data inheritance. Forty lines of code and comments cover most of the examples:

    // isolate ensures no inherited prototype.
    const defaults = Scoto.isolate({
      players: 1,
      gameTime: 60000, // one minute
      maxEnemies: 5
    // rebase puts keys into a new object with a prototype chain
    const appSettings = Scoto.rebase(getAppSettings(), defaults);
    const userSettings = {
      gameTime: 45000,
      maxEnemies: 8
    // rebase again to keep building the hierarchy
    const currentSettings = Scoto.rebase(userSettings, appSettings);
    // flatten merges the properties into a single object.
    // Useful for exporting or saving.
    const exportState = Scoto.flatten(currentSettings);
    // child continues to build on a hierarchy.
    const gameState = Scoto.child(currentSettings);
    // Now we can assign additional keys to our state
    gameState.enemies = [];
    gameState.direction = 0;
    gameState.started = true;
    if (shouldStartDangerMode()) {
      // We don't need to track previous state for the scototype.
      // We just shadow the "older" values. 
      gameState.maxEnemies = 12;
    if (shouldEndDangerMode()) {
      // Deleting variables eliminates shadowing.
      delete gameState.maxEnemies;

    All methods in Scoto are non-mutating.

    Scototype Context

    Since scototypes provide nested scopes, we can optionally bind them as contexts.

    function submitNewScore(score) {
      // Clear variable name for nesting.
      const scoto = this;
      if (undefined === scoto.scores) {
          .then(function(scores) {
            // Push scores onto the current scoto
            scoto.scores = scores;
            // Call this function again with the current scoto
  , score);
  `${scoto.baseURL}/score`, {score})
      .then(receiveScoreResponse.bind(scoto), handleError.bind(scoto));
    function receiveAddScoreResponse(data) {
      const scoto = this;
      scoto.scores = data.scores;
      scoto.lastGameRank = data.gameRank;

    Because scototypes are standard objects, you can bind them as a context with the native Function.prototype.bind and with convenience tools like Lo-dash _.bindAll.

    Scoto includes bind and binder as well. These provide the ability to create a new nested context instead of binding the current Scoto. binder provides a sort of partial applicaiton to allow easy reuse of a particular bind behavior.

    function getMethodsWithContext(context, nest) {
      return, nest));


    npm i scoto

    DownloadsWeekly Downloads






    Last publish


    • oculus42