2017-09-09 12 views
0

JavaScriptでOOPに1つの問題があります。次の例では、newObj.position.xを増やした場合、newObj.xは、this.x = this.position.xを書き込んだにもかかわらず、増加しません。なぜそれが起こっているのか教えていただけますか?あなたはnewObjectを作成しているときにconsole.logのJavaScriptの新しいオブジェクト内部関数

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

 
ClassTwo = function(x, y, w, h) 
 
{ 
 
\t this.x = x; 
 
\t this.y = y; 
 
\t this.w = w; 
 
\t this.h = h; 
 
\t 
 
\t this.position = new ClassOne(this.x, this.y); 
 
\t this.x = this.position.x; 
 
\t this.y = this.position.y; 
 
} 
 

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

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

結果は10、10、10、10、10 ...

+2

newObj.position.x ++; newObj.position.xを増やすだけです... –

+0

クラスTwoのxは、構築中に一度だけ設定されます –

答えて

1

@ArunRedhu's answerが完全に欠場しています。これは、newObjnewObj.positionが別々のオブジェクトであることとは無関係で、xyがプリミティブな値であることとは関係ありません。

もしxと配列のような非プリミティブ値とClassTwoコンストラクタに渡さyの値を置き換える以外は全く同じ問題に設けられたコードを残す場合は、期待どおりに示されるように、その後の特性が、反映されこの答えの一番下。これは、理由がヒープ・メモリー内の別々のオブジェクトのインスタンス化とは無関係であり、単純に使用されるパラメーターのタイプの結果であることを証明します。

プリミティブと非プリミティブの違いは、プリミティブは値渡しで、非プリミティブは参照渡しであることです。このため、プリミティブを別の変数またはプロパティに割り当てると、その値は参照されるのではなくコピーされます。

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

 
ClassTwo = function(x, y, w, h) 
 
{ 
 
\t this.x = x; 
 
\t this.y = y; 
 
\t this.w = w; 
 
\t this.h = h; 
 
\t 
 
\t this.position = new ClassOne(this.x, this.y); 
 
\t this.x = this.position.x; 
 
\t this.y = this.position.y; 
 
} 
 

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

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

2

あり、それは別のメモリを割り当てheapにあります。したがって、文this.position = new ClassOne(this.x, this.y);this.positionの新しいメモリを割り当て、今度はthis.position.xthis.xは両方とも別々のメモリに属します。ですから、newObj.position.xのインスタンスプロパティを変更するときに両方のプロパティが常に等しい、あなたがゲッターとセッターを使用することができますしたい場合は、これはnewObj.x

+0

私が理解しているように、この点は 'this.position = new ClassOne(this.x、this.y);という行にあります。 'を呼び出すと、新しいオブジェクトが作成されます。したがって、基本的に 'newObj'と' newObj.position'は2つの異なるオブジェクトです、そうですか? –

+0

はい絶対に正しい –

+0

これは「ヒープ内の別のメモリ」または2つのオブジェクトがあるという事実とは関係ありません。この答えは「値渡し」や「プリミティブ」という言葉にも言及していないので、その点を完全に逃してしまいます。正しい説明については[私の答え](https://stackoverflow.com/a/46155463/1541563)をご覧ください。 –

2

に反映されませんでした(と私はそれが好きなので、私はクラスの構文を使用します):

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

だから、1が行うことができます:それは内部的にpositionの値を参照するように

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

それはちょっと気味悪いよ –

+0

@パトリック私は実際に1分速かった;) –

+0

はい私はそれを見ることができる> _> –

2

するgetterとsetterメソッドメンバーでclassを使用してみてください:

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

2

newObj.position.xnewObj.xは、2つの異なる値です。あなたがnewObjpositionフィールドのxフィールドを増やしている

newObj.position.x++ 

を実行して、

。したがって、xフィールドのnewObj自体は変更されません。これは、2つのフィールドがリンクされていないためです。

これらをリンクする方法の1つはアクセサを追加することです。

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の機能を保ちたいと思っていました。

+0

'this.x = x; this.position = new ClassOne(x、y); 'に変更します。これは、これらの代入が新しいClassOne(x、y)そうでなければ無関係である。 –

+0

ええ、私はOPのコードからそれを変更するのを忘れました。それを指摘してくれてありがとう。 – Seblor

関連する問題