Javascript - 创建没有引用的对象

标签 javascript javascript-objects

我在没有引用的情况下创建对象实例时遇到问题。

我研究发现很多人建议使用 jQuery.extend 来创建没有引用的对象。

引用: What is the most efficient way to deep clone an object in JavaScript?

但在我的案例中没有成功。

这是我的代码 JSBin

var MyModel = (function() {
  MyModel = function() {};

  var myModelObj = {
    prop1: null,
    prop2: {
      sub1: null,
      sub2: null
    }
  };

  MyModel.prototype = {
    getProp1: function() {
      return myModelObj.prop1;
    },
    getSub1: function() {
      return myModelObj.prop2.sub1;
    },
    getSub2: function() {
      return myModelObj.prop2.sub2;
    },
    setProp1: function(val) {
      myModelObj.prop1 = val;
    },
    setSub1: function(val) {
      myModelObj.prop2.sub1 = val;
    },
    setSub2: function(val) {
      myModelObj.prop2.sub2 = val;
    },
    getObj: function() {
      return $.extend({}, myModelObj);
    },
    setObj: function(json_obj) {
      myModelObj.prop1 = json_obj.prop1;
      myModelObj.prop2.sub1 = json_obj.prop2.sub1;
      myModelObj.prop2.sub2 = json_obj.prop2.sub2;
    },
    setParam: function(prop1, sub1, sub2) {
      myModelObj.prop1 = prop1;
      myModelObj.prop2.sub1 = sub1;
      myModelObj.prop2.sub2 = sub2;
    }
  };
  return MyModel;
}());

var model1 = new MyModel();
model1.setParam('prop1', 'sub1', 'sub2');
var model2 = new MyModel();
model2.setParam('clone-prop1', 'clone-sub1', 'clone-sub2');
console.log("object 1");
console.log(model1.getObj());
console.log("object 2");
console.log(model2.getObj());

我的预期结果是

model1 = {
   prop1: 'prop1',
   prop2: {
      sub1: 'sub1',
      sub2: 'sub2'
   }
}

model2 = {
   prop1: 'clone-prop1',
   prop2: {
      sub1: 'clone-sub1',
      sub2: 'clone-sub2'
   }
}

但实际上,model1model2 具有与model2 相同的数据。

谁能指出我错在哪里?

=== 更新 ===

@arcyqwerty 的解决方案帮助我解决了在没有引用的情况下创建对象的问题。

var MyModel = function() {
  this.prop1 = null;
  this.prop2 = {
    sub1: null,
    sub2: null
  };
};

MyModel.prototype = {
  getProp1: function() {
    return this.prop1;
  },
  getSub1: function() {
    return this.prop2.sub1;
  },
  getSub2: function() {
    return this.prop2.sub2;
  },
  setProp1: function(val) {
    this.prop1 = val;
  },
  setSub1: function(val) {
    this.prop2.sub1 = val;
  },
  setSub2: function(val) {
    this.prop2.sub2 = val;
  },
  getObj: function() {
    return $.extend({}, this);
  },
  setObj: function(json_obj) {
    this.prop1 = json_obj.prop1;
    this.prop2.sub1 = json_obj.prop2.sub1;
    this.prop2.sub2 = json_obj.prop2.sub2;
  },
  setParam: function(prop1, sub1, sub2) {
    this.prop1 = prop1;
    this.prop2.sub1 = sub1;
    this.prop2.sub2 = sub2;
  }
};

var model1 = new MyModel();
model1.setParam('prop1', 'sub1', 'sub2');
var model2 = new MyModel();
model2.setParam('clone-prop1', 'clone-sub1', 'clone-sub2');
console.log("object 1");
console.log(model1.getObj());
console.log("object 2");
console.log(model2.getObj());

但我还想在OOP 中使用封装 特性。这意味着,我们只通过get 函数获取值对象、属性。在 Javascript 上是否可行? 它解释了为什么我在模型中有一个对象(但它引用了同一个对象)

非常感谢!

最佳答案

试试这个

var MyModel = function() {
  this.prop1 = null;
  this.prop2 = {
    sub1: null,
    sub2: null
  };
};

MyModel.prototype = {
  getProp1: function() {
    return this.prop1;
  },
  getSub1: function() {
    return this.prop2.sub1;
  },
  getSub2: function() {
    return this.prop2.sub2;
  },
  setProp1: function(val) {
    this.prop1 = val;
  },
  setSub1: function(val) {
    this.prop2.sub1 = val;
  },
  setSub2: function(val) {
    this.prop2.sub2 = val;
  },
  getObj: function() {
    return $.extend({}, this);
  },
  setObj: function(json_obj) {
    this.prop1 = json_obj.prop1;
    this.prop2.sub1 = json_obj.prop2.sub1;
    this.prop2.sub2 = json_obj.prop2.sub2;
  },
  setParam: function(prop1, sub1, sub2) {
    this.prop1 = prop1;
    this.prop2.sub1 = sub1;
    this.prop2.sub2 = sub2;
  }
};

var model1 = new MyModel();
model1.setParam('prop1', 'sub1', 'sub2');
var model2 = new MyModel();
model2.setParam('clone-prop1', 'clone-sub1', 'clone-sub2');
console.log("object 1");
console.log(model1.getObj());
console.log("object 2");
console.log(model2.getObj());

原始构造函数的问题在于 MyModel 的实例,尽管使用 new 关键字创建的不同对象都共享相同的 myModelObj (仅创建一次)。使用此解决方案,每次创建新的 MyModel 时都会创建新的字段。

这类似于 MyModel = function() { this.myModelObj = {...}; } 并使用 this.myModelObj.prop 访问字段,但此时 myModelObj 有点多余,因为您可以在 this 上设置属性 直接。

此外,使用此解决方案,您可以直接使用 model1.prop 而不必说 model1.getObj().prop(尽管这也有效)

--

注:我看到也有点奇怪

var ClassName = (function() {
  ClassName = function() { ...; };
  ClassName.prototype = { ... };
  return ClassName;
})();

你这样做而不是这样做有什么原因吗

var ClassName = function() { ... };
ClassName.prototype = { ... };

?

如果您不想用 myModelObj 污染命名空间,我想这在原始代码中是有意义的,但在其他情况下似乎没有必要。

--

编辑:封装

如果你需要通过 getters/setters 来设置一个对象的属性,你可以尝试这样的事情:

var MyModel = function() {
  var privateObject = {
    prop1: null,
    prop2: {
      sub1: null,
      sub2: null
    }
  };
  Object.defineProperty(this, 'prop1', {
    get: function() { 
      console.log('Getting prop1 through getter');
      return privateObject.prop1;
    },
    set: function(value) {
      console.log('Setting prop1 through setter');
      privateObject.prop1 = value;
    }
  });
};

缺点是您将无法使用原型(prototype)链共享 getter/setter 函数,这意味着您将有很多函数对象。对于少数情况,这可能很好(性能方面)。如果您的类有子类,它也会影响继承。

如果您在没有defineProperty 的平台上,您也可以通过在构造函数中保留var privateObject 并使用this.getProp1 = function 来复制它() { 返回 privateObject.prop1; } 在构造函数中而不是在原型(prototype)中。最终效果类似于使用 defineProperty

--

编辑:或使用 getter/setter syntax

注意:返回的对象不是 instanceof F

function F() {
  var fields = { prop: null };
  return {
    get prop() {
      console.log("getter");
      return fields.prop;
    },
    set prop(value) {
      console.log("setter");
      fields.prop = value;
    }
  };
}
f = new F
f.prop = 123
f.prop

关于Javascript - 创建没有引用的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35762344/

相关文章:

javascript - jquery通过ajax和animate加载内容

javascript - 如何对对象数组进行排序和切片

javascript - 当列名包含空格时如何使用 SQL 查询 Javascript 对象?

javascript - Angular ui.router 设置祖先状态命名 View

javascript - 将对象数组的特殊元素推送到另一个对象数组

javascript - 将对象值映射到键 - Javascript

javascript - 如何使用 forEach 和 push 函数更新 Javascript 中的对象数组?

javascript - 带连字符的 Webpack 条目

javascript - 将应用程序从 Angular 5 更新到 Angular 8 会导致样式问题

javascript - Android加载外部本地javascript文件到WebView中