为什么这个javascript obj的新实例继承了其他实例属性?

为什么这个javascript obj的新实例继承了其他实例属性?,javascript,node.js,oop,inheritance,Javascript,Node.js,Oop,Inheritance,我构建了一个BaseModel类,我们的所有模型都继承自该类。我遇到了一个问题,TestModel的新实例(如下)正在维护来自其他先前实例化模型的属性 为什么会这样?我做错了什么 var util = require('util'); var ModelBase = function(request, params, definition) { this.request = request; this.def = definition.schema ? definition.sche

我构建了一个BaseModel类,我们的所有模型都继承自该类。我遇到了一个问题,TestModel的新实例(如下)正在维护来自其他先前实例化模型的属性

为什么会这样?我做错了什么

var util = require('util');

var ModelBase = function(request, params, definition) {
  this.request = request;

  this.def = definition.schema ? definition.schema : {};

  if(params && typeof params === 'object' && !Array.isArray()) {
    this.set(params);
  }
};

ModelBase.prototype.... // a lot more proto methods in ModelBase

// TestModel inherits from ModelBase
var TestModel = function(request, params) {
  ModelBase.call(this, request, params, MOCK_MODEL_DEFINITION);
};

util.inherits(TestModel, ModelBase);

var mdl = new TestModel(MOCK_REQUEST, { a: 'A' });
var mdl2 = new TestModel(MOCK_REQUEST);

console.log(mdl.toObject()); // { a: 'A' }
console.log(mdl2.toObject()); // { a: 'A' } - should be empty
编辑:以下是我尝试过的其他一些不起作用的东西:

var TestModel = function(request, params) {
  return new ModelBase(request, params, MOCK_MODEL_DEFINITION);
};

// move the base constructor logic to an init func
var TestModel = function(request, params) {
  this.init(request, params, MOCK_MODEL_DEFINITION);
};

问题是所有对象都从同一源初始化其
def
字段
ModelBase
TestModel
构造函数中的调用方式如下:

ModelBase.call(this, request, params, MOCK_MODEL_DEFINITION);
因此,在所有情况下,
def
都被设置为
MOCK_MODEL_DEFINITION.schema
的值,它是一个定义为
{a:{validate:'validation obj here'}}
的对象,该对象上的任何更改都将由所有
TestModel
对象共享

通过将以下测试添加到代码中,可以轻松测试这一点:

console.log(mdl.def === mdl2.def);
这将显示
true
。这表明
mdl.def
mdl2.def
不是共享相同值的两个对象,而是完全相同的对象

我看到两种解决办法

将模式与数据分离 现在,您正在将用于验证数据的模式存储在与数据相同的结构中。您可以像现在一样将模式存储在
def
中。但是您应该将数据存储到不同的字段中。例如:

var ModelBase = function(request, params, definition) {
  this.def = definition.schema ? definition.schema : {};
  this.data = {};
  this.set(params);
};

ModelBase.prototype.set = function(params) {
  for(var p in params) {
    this.data[p] = params[p];
  }
};
如果您的模式是不可变的,那么共享它们就没有问题

复制用于初始化
def
这里需要做的是通过创建初始化对象的副本来初始化
def
。基本上,不是这样:

this.def = definition.schema ? definition.schema : {};
你需要这个:

this.def = definition.schema ? copy(definition.schema) : {};
其中,
copy
是适合您案例的任何复制操作。以下是一些很好的问题,涵盖了执行浅拷贝和深拷贝的最佳方法:


您没有创建新的
模型库
对象-您只是在不同的范围内调用同一个对象(注意:我不是反对票)。那么如何初始化新的模型库,但保留上下文?这就是问题所在,所以如果您提交答案,我可能会接受。@Adam它似乎在执行
new ModelBase
而不是调用时表现出相同的行为,所以我被难住了。这是什么
this.set(params)
方法?我在尝试您的代码时出错。您对继承的概念有点奇怪,但是上面的代码不应该具有您描述的行为。我猜您编辑它是为了向我们展示,但我测试了您所展示的内容,这两个实例是不同的。当然,我不得不模拟
设置
,因为我不知道它会做什么。除了我找不到任何库来深度复制函数之外:/我不知道你所说的“深度复制功能”是什么意思
jQuery.extend
对深度复制对象中的函数没有问题。jQuery.extend无法工作,因为这是服务器端节点应用程序。Lodash有一个deepClone,但它说:“函数和DOM节点没有被克隆”。所以我有点不知所措。Lodash函数的名称是
cloneDeep
。文档中“未克隆”的意思是一个函数对象没有被复制。99%的情况下,这是您想要的,因为您在创建函数对象后不会修改它。(换句话说,它们的使用就好像它们是不可变的一样。)在创建函数对象之后,您真的需要修改它们吗?我的模式包含Joi验证()。这些未正确克隆,因此我的验证失败。