9
Object.create = function (o) {
    function F() {}
    F.prototype = o;
    return new F();
};

JavaScript のプロトタイプ継承から

以前のものから継承した新しいオブジェクトを作成するために、しばらくこのコードを使用してきました。しかし、私はちょっとした驚きに出くわしました。

a = {
    foo: [1,2,3]
}

b = Object.create(a);
// b.foo -> [1,2,3]
b.foo = "test";
// b.foo -> "test"
// a.foo -> [1,2,3]

c = Object.create(a);
// c.foo -> [1,2,3]
c.foo[0] = 'test';
// c.foo -> ["test",2,3]
// a.foo -> ["test",2,3]

変更しようとして、代わりc.fooに変更し、から継承しているため変更を表示しました。私が今見ている唯一の解決策は、の直接プ​​ロパティのみを変更することです:a.fooc.fooab

d = Object.create(a);
d.foo = Object.create(a.foo);
d.foo[0] = 'text';

私が見逃しているより良い解決策があると確信しています!元のオブジェクトを変更する危険を冒さずに、古いオブジェクトから新しいオブジェクトを作成するにはどうすればよいですか?

4

5 に答える 5

1

Crockford = Dを参照するための+1

配列は常に参照によって渡され、配列がコピーされることはないと思います。Array.slice はそれをコピーすると思いますが、それはまれなケースです...

create 関数は主に関数のコピーなどに使用されます。コンストラクター関数を作成するだけなので、そのメソッドを使用することはありません。

function a() {
    this.foo = [0, 1, 2];
}

このようにして、呼び出しごとに常に新しい配列を取得します。b = new a(); を実行するだけです。わたしにはできる...

継承には常に問題があるため、継承を避けようとしています。コンストラクターを使用して、新しい変数をそれに割り当てます (プロトタイプではありません)。ただし、多重継承は扱いにくい...

于 2011-05-27T03:37:02.753 に答える
1

プロトタイプから新しいオブジェクトを作成する場合、コピーは行われません。プロパティもコピーされません:

function F() {}
F.prototype.a = 1
new F().hasOwnProperty("a") // => false
new F().a // => 1

もしあなたがそうするなら

var f = new F();
f.a = 2;

次に、 のプロパティを変更するのではなくF.protoype、新しいプロパティを に追加しますf

var f = new F();
f.a = 2;
f.a // => 2;
delete f.a;
f.a // => 1

したがって、これはプロパティに割り当てるすべての値に適用されます。値を複製したい場合は、明示的に行う必要があります。最も簡単な方法は、コンストラクターで新しいプロパティを設定することです。

function F() {
  this.a = [];
}
var f = new F();
var g = new F();
f.a === g.a // => false

この問題は、プロトタイプに変更可能な値が含まれている場合にのみ発生します。他の値は変更できません (代わりにプロパティが値を変更できます)。

また、F を「サブクラス化」したい場合は、新しいコンストラクターから呼び出すことを忘れないでください。

function F() { this.a = []; }
function G() { F.call(this); }
G.prototype = new F();
于 2011-05-27T03:47:48.277 に答える
1

私が今まで見た中で最高の継承パターンは、Google Closure Library のものです。コンストラクターに基づいています。次に例を示します。

//with this method we will inherit one "class" (there are no real classes in JS) from another.
var inherit = function (c, p) {
    function F() {}
    F.prototype = p.prototype;
    c.prototype = new F;
    c.prototype.constructor = c;
};

//create one "class"
var A = function(){
    this.foo = [1,2,3];
}
//create its instance
var a = new A();

//create another "class"
var C = function(){
    //call the parent constructor
    A.call(this);
}
//make inheritance
inherit(C, A);
//create example of inherited "class"
var c = new C();

そして、結果はあなたが望むとおりです:

console.log(c.foo);
//-> [1,2,3]
c.foo[0] = 'test';
console.log(c.foo);
//-> ['test',2,3]
console.log(a.foo);
//-> [1,2,3]
于 2011-05-27T04:08:11.217 に答える
0

これは解決策です:


Object.create = function (o) {
    function F() {
        for(var prop in this)
            if(o.hasOwnProperty(prop))
                this[prop] = Object.create(o[prop]);
    }
    F.prototype = o;
    return new F();
};

このソリューションの一般的な制限は、プロトタイプに再帰参照を含めないことです。

また、その制限なしでこの問題を解決することは可能ですが、解決策はより複雑になります。無限再帰オブジェクトの作成を防ぐために、初期化プロセス中にある種の一時的なマップ ストレージを使用できます。このストレージは、初期化されたオブジェクト間のキャッシュ参照になります。

于 2011-05-27T04:07:20.603 に答える
0

はい、そうです:

1)

b.foo = "test";
// b.foo -> "test"

a の F.prototype 参照を「test」に置き換えて、エラーが表示されないようにしますが、実際にはこれは 2) よりも悪いです)

2)

c = Object.create(a);
// c.foo -> [1,2,3]
c.foo[0] = 'test';
// c.foo -> ["test",2,3]
// a.foo -> ["test",2,3]

c.foo[0] & a.foo がそれを指しているため、a オブジェクトを変更します (これらは a 値への参照/ポインターです)。

解決策はこちら

于 2011-05-27T03:38:56.523 に答える