0

私は最近、実験のために new ではなく Object.create() に切り替えました。classA-> classA's parent->などの多重継承を実現するにはどうすればよいclassA's parent's parentですか?

例:

var test = Object.create(null); 
test.prototype = {
    greet: function () {
        console.info('hello world');
    },

    name: 'myName'
};

var test2 = Object.create(test.prototype);
test2.prototype = {
    name: 'newName'
};

var test3 = Object.create(test2.prototype);
test3.prototype = {
    name: 'another Name'
};

test2はまだあいさつできますが、これは、情報がないためあいさつのないtest3プロトタイプを使用したため、明らかにそうではありません。test2test

私はいくつかの記事を読みましたが__proto__、継承に使用することは強くお勧めしません。これを行う正しいjavascriptyの方法は何ですか?

次のようなものですが、 Object.create を使用します

test2.prototype = new test();
test2.constructor = test2;

test3.prototype = new test2();
test3.constructor = test3;

var a = new test3();
a.greet();
4

2 に答える 2

1

Object.create オブジェクトは別のオブジェクトから直接継承するため、prototypeプロパティには役割がありません。最初の例では、以前に行っていたことに最も近い形式で記述しましたが、Object.create を呼び出すときにオブジェクトのプロパティを設定する必要はありません。呼び出し後に問題なく設定できます (2 番目の例を参照)。

var test1 = Object.create(null, {
    greet : {value : function() {
        console.info('hello world');
    }},

    name : {value : 'myName'}
});

var test2 = Object.create(test1, {
    name : {value : 'alteredProperty'}});

var test3 = Object.create(test2);

test3.greet(); // hello world
console.log(test3.name); // alteredProperty

より単純な例 (プロパティ記述子なし):

var test1 = Object.create(null);
test1.greet = function() {
    console.info('hello world');
};
test1.name = 'myName';

var test2 = Object.create(test1);
test2.name = 'alteredProperty';

var test3 = Object.create(test2);

test3.greet();
console.log(test3.name);

HMR が指摘したように、test1オブジェクトを作成するたびに新しいgreet関数が作成されますが、これは望ましくありません。次の例では、メソッドをプロトタイプのようなオブジェクトにオフロードすることで、この問題を解決しています。

// proto object
var Test1 = {
  greet : function() { console.info('hello world ' + this.name); },
  name : 'Test1'
};

// instance of Test1
var test1 = Object.create(Test1);

// proto object inheriting from Test1
var Test2 = Object.create(Test1)
Test2.name = 'Test2';

// instance of Test2
var test2 = Object.create(Test2);

// proto object inheriting from Test2
var Test3 = Object.create(Test2);
Test3.size = 'big';


// instance of Test3
var test3 = Object.create(Test3);

test3.greet(); // hello world Test2
console.info(test3.name); // Test2
console.info(test3.size); // big
test3.name = 'Mike';
test3.greet(); // hello world Mike

ご覧のとおり、この例は上記の例とほとんど同じですが、一部のオブジェクトの扱い方が異なります。一部のオブジェクト (大文字のもの) は、プロトタイプを持つコンストラクターと同様に動作します。これらは通常、直接使用されず、構築されたオブジェクトのメソッドとデフォルト値を保持します。「クラス」のインスタンスと継承する「クラス」の構文はまったく同じであるため、これは純粋に慣習的なものです。proto オブジェクトが悪用されないようにするのは、あなた次第です。

ボーナス:

function isInstanceOf(child, parent) {
  return Object.prototype.isPrototypeOf.call(parent, child);
}

console.info(isInstanceOf(test3, Test3)); // true
console.info(isInstanceOf(test3, Test1)); // true
console.info(isInstanceOf(test2, Test3)); // false
于 2013-09-30T15:28:05.880 に答える
0

Tibos の方法で Object.create を使用すると、渡されたオブジェクトのすべてのメンバーがprototype、返されたオブジェクトの に配置されるように見えます。

// in firefox firebug running
// an empty page
var Definition = {
  name : 'Test1'
};
//doesn't matter where it's defined
Definition.greet=function() { 
  console.log(this);//<-what is this in Chrome?
};
Definition.arr=[];
// instance of Test1
var test1 = Object.create(Definition);
var test2 = Object.create(Definition);
console.log(test1.greet===test2.greet);//true
delete test2.greet
delete test2.greet
delete test2.greet
delete test2.greet//can't delete it
test2.greet();
console.log(test1.greet===test2.greet);//true
console.log(test1.arr===test2.arr);//true
test1.arr.push(1);
console.log(test2.arr);//=[1]
var things=[];
for(thing in test1){
  things.push(thing);
}
console.log("all things in test1:",things);
things=[];
for(thing in test1){
  if(test1.hasOwnProperty(thing)){
    things.push(thing);
  }
}
console.log("instance things in test1:",things);//nothing, no instance variables

[アップデート]

上記のコードからわかるように、Object.create は、プロトタイプの最初のパラメーターのすべてのメンバーと、インスタンス メンバーとしての 2 番目のパラメーターを持つオブジェクトを返します。(答えはコメントに mccainz から長い間ありました) 追加の利点 (何年も更新されていない IE8 とブラウザーを無視します) は、インスタンス メンバーで列挙可能、書き込み可能、​​および構成可能を指定でき、ゲッターとセッターを作成できることです。割り当てのように機能します (instance.someprop=22 は実際には instance.someprop(22) になる可能性があります)。

インスタンス固有のメンバーを指定するには、いくつかのパターンを使用できます。これらのパターンを使用すると、コードは new キーワードを使用する場合と同じくらい「醜い」か、さらに悪いように見えますが、これは個人的な好みであり、ゲッターとセッターを作成したり、追加の制御 (列挙可能、書き込み可能および構成可能)。

1 つのパターンは、init 関数を使用することです。

var userB = {
    init: function(nameParam) {
        this.id = MY_GLOBAL.nextId();
        this.name = nameParam;
    },
    sayHello: function() {
        console.log('Hello '+ this.name);
    }
};
var bob = Object.create(userB).init("Bob");

追加の制御を利用するより複雑なものは次のとおりです。

var Person={
  talk:function(){console.log("I'm "+this.name);}
  //,other prototype stuff related to Person
};
var userCreator={
   processInstanceMembers:function(o,initObj){
     this.createName(o,initObj.name);
     Object.defineProperty(o,"_name",{writable:true});
     o.name=initObj.name;
   },
   get:function(initObj,inheritFrom){
     var ret=Object.create(inheritFrom||Person);
     this.processInstanceMembers(ret,initObj);
     return ret;
   },
   createName:function(o){//minimalise closure scope
     Object.defineProperty(o,"name",{
       get:function(){
         return this._name;
       },
       set:function(val){
         if(val.replace(/\s*/gm,"")===""){
           throw new Error("Name can't be empty, or only whitespaces");
         }
         this._name=val;
       },
       enumerable : true
     });
   }
};

//when creating an instance you can choose what to inherit from
//leave it out to inherit from Person
var u=userCreator.get({name:"Ben"});
u.talk();
u.name="Benji";
u.talk();
u.name="  ";//error, name can't be empty

Child の継承を設定するために Parent の新しいインスタンスを作成する必要はありません。これまたはヘルパー関数に Object.create を使用できます。

var Child =function(){
  //get Parent's INSTANCE members defined in the 
  //parent function body with this.parentInstance=...
  Parent.apply(this,arguments);
}
Child.prototype=Object.create(Parent.prototype);
Child.prototype.constructor=Child;
Child.prototype.otherFn=function(){};

これは興味深いと思うかもしれません。ヘルパー関数があるため、必要がなければ Object.create を使用する必要はありません。

于 2013-10-01T04:19:21.660 に答える