Javascript - 创建没有引用的对象

时间:2016-03-03 02:57:42

标签: javascript javascript-objects

我在创建没有引用的Object实例时遇到问题。

我研究并发现很多人建议使用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());

但我也想在encapsulation中使用OOP功能。这意味着,我们只通过get函数获取值对象,属性。可以Javascript吗? 它解释了为什么我在Model中有一个对象(但是它引用了同一个对象)

非常感谢!

2 个答案:

答案 0 :(得分:3)

试试这个

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污染名称空间,我认为在原始代码中它是有意义的,但是否则似乎没有必要。

-

编辑:封装

如果您需要通过getter / setter设置对象的属性,您可以尝试这样的事情:

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;
    }
  });
};

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

如果你所在的平台没有defineProperty,你也可以通过在构造函数中保留var privateObject并在构造函数中使用this.getProp1 = function() { return privateObject.prop1; }而不是在原型上复制它。净效果类似于使用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

答案 1 :(得分:1)

这个arcyqwerty答案的变体演示了对数据进行更深入的封装。权衡是每个实例都获得自己的方法副本,而不是在"类"电平:

var MyModel = function() {
  var prop1 = null;
  var prop2 = {
    sub1: null,
    sub2: null
  };
  this.getProp1 = function() {
    return prop1;
  };
  this.getSub1 = function() {
    return prop2.sub1;
  };
  this.getSub2 = function() {
    return prop2.sub2;
  };
  this.setProp1 = function(val) {
    prop1 = val;
  };
  this.setSub1 = function(val) {
    prop2.sub1 = val;
  };
  this.setSub2 = function(val) {
    prop2.sub2 = val;
  };
  this.getObj = function() {
    return {
      prop1: prop1,
      prop2: {
        sub1: prop2.sub1,
        sub2: prop2.sub2
      }
    };
  };
  this.setObj = function(json_obj) {
    prop1 = json_obj.prop1;
    prop2.sub1 = json_obj.prop2.sub1;
    prop2.sub2 = json_obj.prop2.sub2;
  };
  this.setParam = function(_prop1, _sub1, _sub2) {
    prop1 = _prop1;
    prop2.sub1 = _sub1;
    prop2.sub2 = _sub2;
  };
};

你说,

  

但我想知道我们如何保护Javascript上的属性?

我认为这是错误的问题。 JS是一种不同的语言,与Java或Ruby不同。它至少与OO一样是一种功能语言。当你做JS时,你可能不应该尝试表现得好像是在Java工作,而是学习它的民风。