Почему этот код JS работает в большинстве мест, но не на моей машине? - PullRequest
0 голосов
/ 07 июня 2018

Я написал некоторый код, который прекрасно работает в Nov env, предоставленном repl.it (https://repl.it/repls/LimpingCharmingGravity), в фрагменте кода здесь (см. Ниже), и на codepen.io (https://codepen.io/tjfwalker/pen/OERXry?editors=0012#0).).Работая, однако, с Node на моей машине. Попытка запустить в производит следующее сообщение об ошибке:

ReferenceError: Entity is not defined
    at Entity.eval [as addSub] (eval at <anonymous> (/Users/…pathtofile…/app.js:18:69), <anonymous>:3:11)
    at Object.<anonymous> (/Users/…pathtofile…/app.js:60:20)
    at Module._compile (internal/modules/cjs/loader.js:702:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:713:10)
    at Module.load (internal/modules/cjs/loader.js:612:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:551:12)
    at Function.Module._load (internal/modules/cjs/loader.js:543:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:744:10)
    at startup (internal/bootstrap/node.js:238:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:572:3)

Мой локальный узел 10.4.0 через nvm на macOS ... хотя, я думаю, что это не очто.

Что дает?

let activeUserMock = 'someUserName'

const Entity = (function() {
    let lastID     = 0
      , entityList = []
    
    function Entity(userFields, userMethods) {
        this.meta = {id: ++lastID, dob: new Date, creator: activeUserMock}
        
        userFields.forEach(
            function(field) {
                this[field.key] = field.value
            }
        ,this)
        
        userMethods.forEach(
            function(method) {
                this[method.name] = Function(...method.args, method.body)
            }
        ,this)
        
        entityList.push(this)
    }
    
    Entity.findByID = function(id) {
        return entityList.find(function(entity) {
            return entity.meta.id === id
        })
    }
    
    return Entity
})();

// ======= SIMULATE AN END USER —FROM SOME CLIENT UI— MODELING THEIR OWN DOMAIN ==========

new Entity([ //stuff from the user ↴
    {key: 'type', value: 'feature'}
   ,{key: 'name', value: 'LMS'}
   ,{key: 'subs', value: []}
   ,{key: 'sups', value: []}
   ,{key: 'desc', value: 'a module to facilitate learning.'}
],[
    {name: 'addSub', args: ['subID'], body: 'let sub = Entity.findByID(subID); this.subs.push(sub); sub.sups.push(this); return this'}
   ,{name: 'addSup', args: ['supID'], body: 'let sup = Entity.findByID(supID); this.sups.push(sup); sup.subs.push(this); return this'}
])

new Entity([ //stuff from the user ↴
    {key: 'type', value: 'feature'}
   ,{key: 'name', value: 'SRS'}
   ,{key: 'subs', value: []}
   ,{key: 'sups', value: []}
   ,{key: 'desc', value: 'a module that implements the spaced repetition learning technique.'}
],[
    {name: 'addSub', args: ['subID'], body: 'let sub = Entity.findByID(subID); this.subs.push(sub); sub.sups.push(this); return this'}
   ,{name: 'addSup', args: ['supID'], body: 'let sup = Entity.findByID(supID); this.sups.push(sup); sup.subs.push(this); return this'}
])

Entity.findByID(1).addSub(2)

// ==========================================================

console.log(Entity.findByID(1))

1 Ответ

0 голосов
/ 07 июня 2018

В отличие от eval(), конструктор Function() не имеет доступа к вызывающей области, он имеет доступ только к глобальной области.

Этот сценарий завершится ошибкой в ​​узле, поскольку каждый модуль имеет свою собственную областьи Entity не находится в глобальном пространстве имен.

Чтобы проверить это, просто оберните ваш код внутри IIFEE, и вы увидите, что он не будет работать и в браузере.(См. Фрагмент ниже)

Чтобы «исправить» ваш код в узле, вам нужно сделать:

global.Entity = (function() {
 /* ... */
})():

Но вам, вероятно, следует переосмыслить свой подход и использовать вместо него bind,и получить доступ к Entity, используя this.

В браузере также произойдет сбой следующих действий:

(function() {
  let activeUserMock = 'someUserName'

  const Entity = (function() {
      let lastID     = 0
        , entityList = []

      function Entity(userFields, userMethods) {
          this.meta = {id: ++lastID, dob: new Date, creator: activeUserMock}

          userFields.forEach(
              function(field) {
                  this[field.key] = field.value
              }
          ,this)

          userMethods.forEach(
              function(method) {
                  this[method.name] = Function(...method.args, method.body)
              }
          ,this)

          entityList.push(this)
      }

      Entity.findByID = function(id) {
          return entityList.find(function(entity) {
              return entity.meta.id === id
          })
      }

      return Entity
  })();

  // ======= SIMULATE AN END USER —FROM SOME CLIENT UI— MODELING THEIR OWN DOMAIN ==========

  new Entity([ //stuff from the user ↴
      {key: 'type', value: 'feature'}
     ,{key: 'name', value: 'LMS'}
     ,{key: 'subs', value: []}
     ,{key: 'sups', value: []}
     ,{key: 'desc', value: 'a module to facilitate learning.'}
  ],[
      {name: 'addSub', args: ['subID'], body: 'let sub = Entity.findByID(subID); this.subs.push(sub); sub.sups.push(this); return this'}
     ,{name: 'addSup', args: ['supID'], body: 'let sup = Entity.findByID(supID); this.sups.push(sup); sup.subs.push(this); return this'}
  ])

  new Entity([ //stuff from the user ↴
      {key: 'type', value: 'feature'}
     ,{key: 'name', value: 'SRS'}
     ,{key: 'subs', value: []}
     ,{key: 'sups', value: []}
     ,{key: 'desc', value: 'a module that implements the spaced repetition learning technique.'}
  ],[
      {name: 'addSub', args: ['subID'], body: 'let sub = Entity.findByID(subID); this.subs.push(sub); sub.sups.push(this); return this'}
     ,{name: 'addSup', args: ['supID'], body: 'let sup = Entity.findByID(supID); this.sups.push(sup); sup.subs.push(this); return this'}
  ])

  Entity.findByID(1).addSub(2)

  // ==========================================================

  console.log(Entity.findByID(1))
})();

ОБНОВЛЕНИЕ

как конкретно выглядит код, который следует вашей рекомендации «использовать вместо этого связывание и получить доступ к сущности»используя это

this[method.name] = Function(...method.args, method.body).bind(this)

И затем используйте:

body: 'let sub = this.constructor.findByID(subID) ...'

Вместо:

body: 'let sub = Entity.findByID(subID) ...'
...