JavaScript函数中的新对象

JavaScript函数中的新对象,javascript,oop,Javascript,Oop,我对JavaScript中的OOP有一个问题。在下面的示例中,当增加newObj.position.x时,newObj.x不会增加,尽管我编写了this.x=this.position.x。你能告诉我为什么会这样吗 ClassOne=函数(x,y) { 这个.x=x; 这个。y=y; }; 第二类=函数(x,y,w,h) { 这个.x=x; 这个。y=y; 这个.w=w; 这个,h=h; this.position=new ClassOne(this.x,this.y); this.x=thi

我对JavaScript中的OOP有一个问题。在下面的示例中,当增加
newObj.position.x
时,
newObj.x
不会增加,尽管我编写了
this.x=this.position.x
。你能告诉我为什么会这样吗

ClassOne=函数(x,y)
{
这个.x=x;
这个。y=y;
};
第二类=函数(x,y,w,h)
{
这个.x=x;
这个。y=y;
这个.w=w;
这个,h=h;
this.position=new ClassOne(this.x,this.y);
this.x=this.position.x;
this.y=this.position.y;
}
var newObj=新的第二类(10,20,30,40);
对于(变量i=0;i<15;i++)
{
newObj.position.x++;
console.log(newObj.x);

}
使用
new
创建
对象时,它会在
堆中分配单独的内存。因此语句
this.position=newclassone(this.x,this.y)
this.position
分配新内存,现在
this.position.x
this.x
都属于单独的内存。因此,当您更改
newObj.position.x
的实例属性时,这不会反映到
newObj.x

如果希望两个属性始终相等,可以使用getter和setter(我将使用类语法,因为我喜欢它):

因此,我们可以:

var player = new Instance(0,0,0,0);
player.x++;
player.position;//0:1

尝试将
与getter和setter成员方法一起使用,以便它在内部引用
位置
的值:

第一类{
构造函数(x,y){
这个。x=x
这个。y=y
}
}
二班{
构造器(x,y,w,h){
这个。w=w
这个。h=h
此位置=新位置(x,y)
}
得到x(){
返回这个.position.x
}
集合x(v){
返回这个。位置。x=v
}
得到y(){
返回这个。位置。y
}
集合y(v){
返回此。位置。y=v
}
}
设newObj=newtwo(10,20,30,40)
for(设i=0;i<15;i++){
newObj.position.x++
console.log(newObj.x)

}
newObj.position.x
newObj.x
是两个不同的值

通过做

newObj.position.x++
您正在增加
newObj
position
字段的
x
字段。因此,
newObj
x
字段本身不会改变,因为这两个字段没有链接

链接它们的一种方法是添加访问器

使用
函数对象
,可以创建如下对象:

ClassOne = function (x, y) {
  this.x = x;
  this.y = y;
};

ClassTwo = function (x, y, w, h) {
  this.w = w;
  this.h = h;

  this.position = new ClassOne(x, y);

  Object.defineProperty(this, 'x', {
    get: function () { return this.position.x; },
    set: function (newValue) { this.position.x = newValue; },
    enumerable: true,
    configurable: true
  });

  Object.defineProperty(this, 'y', {
    get: function () { return this.position.y; },
    set: function (newValue) { this.position.y = newValue; },
    enumerable: true,
    configurable: true
  });
}

var newObj = new ClassTwo(10, 20, 30, 40);

for (var i = 0; i < 15; i++) {
  newObj.position.x++;
  console.log(newObj.x);
}
ClassOne=函数(x,y){
这个.x=x;
这个。y=y;
};
第二类=函数(x,y,w,h){
这个.w=w;
这个,h=h;
这个位置=新的一类(x,y);
Object.defineProperty(这是'x'{
get:function(){返回this.position.x;},
set:function(newValue){this.position.x=newValue;},
可枚举:正确,
可配置:true
});
Object.defineProperty(这个'y'{
get:function(){返回this.position.y;},
set:function(newValue){this.position.y=newValue;},
可枚举:正确,
可配置:true
});
}
var newObj=新的第二类(10,20,30,40);
对于(变量i=0;i<15;i++){
newObj.position.x++;
console.log(newObj.x);
}
编辑:在看到其他答案后,我想说我知道使用es6类更好(至少在可读性方面),但我想保留OP的功能。完全没有抓住要点。这与
newObj
newObj.position
是独立的对象无关,而与
x
y
是基本值这一事实有关

如果您将问题中提供的代码保持完全相同,只是将传递给
ClassTwo
构造函数的
x
y
的值替换为数组等非原语值,则属性将按预期反映,如本答案底部所示。这证明了原因与堆内存中单独对象的实例化无关,只是所用参数类型的结果

基本体和非基本体之间的区别在于,基本体是按值传递的,而非基本体是按引用传递的。因此,将原语指定给另一个变量或属性会导致复制而不是引用该值

ClassOne=函数(x,y)
{
这个.x=x;
这个。y=y;
};
第二类=函数(x,y,w,h)
{
这个.x=x;
这个。y=y;
这个.w=w;
这个,h=h;
this.position=new ClassOne(this.x,this.y);
this.x=this.position.x;
this.y=this.position.y;
}
var newObj=新类别二([10],[20],30,40);
对于(变量i=0;i<15;i++)
{
newObj.position.x[0]+;
console.log(newObj.x[0]);

}
newObj.position.x++;只是增加了newObj.position.x…第二类的x只设置了一次,在构建过程中这只是一个缓慢的过程,我可以看到>>你可能应该删除
这个.x=x;这个。y=y来自
ClassTwo
并更改
this.position=新的ClassOne(this.x,this.y)
这个位置=新的一类(x,y),因为这些任务在其他方面是无关的。是的,对了,我忘了从OP的代码中更改它。谢谢你指出这一点。据我所知,重点是在
this.position=newclassone(this.x,this.y)行中,将创建一个新对象。因此,基本上
newObj
newObj.position
是两个不同的对象,对吗?这与“堆中的独立内存”或有两个对象的事实无关。这个答案甚至没有提到“传递值”或“原始”这两个术语,因此它完全没有抓住要点。有关正确的解释,请参阅。
ClassOne = function (x, y) {
  this.x = x;
  this.y = y;
};

ClassTwo = function (x, y, w, h) {
  this.w = w;
  this.h = h;

  this.position = new ClassOne(x, y);

  Object.defineProperty(this, 'x', {
    get: function () { return this.position.x; },
    set: function (newValue) { this.position.x = newValue; },
    enumerable: true,
    configurable: true
  });

  Object.defineProperty(this, 'y', {
    get: function () { return this.position.y; },
    set: function (newValue) { this.position.y = newValue; },
    enumerable: true,
    configurable: true
  });
}

var newObj = new ClassTwo(10, 20, 30, 40);

for (var i = 0; i < 15; i++) {
  newObj.position.x++;
  console.log(newObj.x);
}