繁体   English   中英

函数内部的JavaScript新对象

[英]JavaScript new object inside function

我在JavaScript中的OOP有一个问题。 在下面的例子中,当newObj.position.x增加, newObj.x没有增加,尽管我写的事实this.x = this.position.x 你能告诉我为什么会这样吗?

 ClassOne = function( x, y ) { this.x = x; this.y = y; }; ClassTwo = function( x, y, w, h ) { this.x = x; this.y = y; this.w = w; this.h = h; this.position = new ClassOne( this.x, this.y ); this.x = this.position.x; this.y = this.position.y; } var newObj = new ClassTwo( 10, 20, 30, 40 ); for ( var i = 0; i < 15; i++ ) { newObj.position.x++; console.log( newObj.x ); } 

console.log的结果是10、10、10、10、10 ...

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

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

class Position {
 constructor(x,y){
   this.x = x;
   this.y = y;
 }
 toString(){
  return this.x+":"+this.y;
 }
}

class Instance {
  constructor(x,y,w,h){
    this.w = w;
    this.h = h;
    this.position = new Position(x,y);
  }

  get x(){
    return this.position.x;
  }
  set x(x){
   this.position.x = x;
  }

  get y(){
    return this.position.y;
  }
  set y(y){
   this.position.y = y;
  }
}

所以可以做到:

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

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

 class One { constructor (x, y) { this.x = x this.y = y } } class Two { constructor (x, y, w, h) { this.w = w this.h = h this.position = new One(x, y) } get x () { return this.position.x } set x (v) { return this.position.x = v } get y () { return this.position.y } set y (v) { return this.position.y = v } } let newObj = new Two(10, 20, 30, 40) for (let i = 0; i < 15; i++) { newObj.position.x++ console.log(newObj.x) } 

newObj.position.xnewObj.x是2个不同的值。

通过做

newObj.position.x++

您正在增加newObjposition字段的x字段。 因此, newObj本身的x字段不会更改,因为2个字段未链接。

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

使用function objects ,您可以创建如下function objects

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

编辑:看到其他答案后,我想说的是,我知道使用es6类更好(至少出于可读性考虑),但我想保留OP的功能。

@ArunRedhu的答案完全错了。 这与newObjnewObj.position是独立的对象无关,而与xy是原始值这一事实无关。

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

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

 ClassOne = function( x, y ) { this.x = x; this.y = y; }; ClassTwo = function( x, y, w, h ) { this.x = x; this.y = y; this.w = w; this.h = h; this.position = new ClassOne( this.x, this.y ); this.x = this.position.x; this.y = this.position.y; } var newObj = new ClassTwo( [10], [20], 30, 40 ); for ( var i = 0; i < 15; i++ ) { newObj.position.x[0]++; console.log( newObj.x[0] ); } 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM