В отличие от 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) ...'