JavaScriptの継承:Object.createとnew


123

JavaScriptでは、これら2つの例の違いは何ですか。

前提条件:

function SomeBaseClass(){
}

SomeBaseClass.prototype = {
    doThis : function(){
    },

    doThat : function(){
    }
}

Object.createを使用した継承の例A:

function MyClass(){
}

MyClass.prototype = Object.create(SomeBaseClass.prototype);

新しいキーワードを使用した継承例B

function MyClass(){
}

MyClass.prototype = new SomeBaseClass();

どちらの例も同じことをするようです。いつどちらを選ぶか?

追加の質問:以下のリンク(15行目)のコードを検討してください。関数自身のコンストラクターへの参照がプロトタイプに格納されています。なぜこれが便利なのですか?

https://github.com/mrdoob/three.js/blob/master/src/loaders/ImageLoader.js

抜粋(リンクを開かない場合):

THREE.ImageLoader.prototype = {

    constructor: THREE.ImageLoader
}

23
なぜこれが重複としてマークされているのですか?他の質問と答えは、言及さえしないでくださいObject.create。これは間違いであり、再開する必要があります。
Scott Rippey 2014年

2
どちらかと言えば、stackoverflow.com
questions / 4166616 /…の

1
そのコメントに13票を投じましたが、まだ再開されていません。
TJ

回答:


111

あなたの質問であなたはそれについて言及しました Both examples seem to do the same thingそれ、それはまったく真実ではありません、なぜなら

あなたの最初の例

function SomeBaseClass(){...}
SomeBaseClass.prototype = {
    doThis : function(){...},
    doThat : function(){...}
}
function MyClass(){...}
MyClass.prototype = Object.create(SomeBaseClass.prototype);

この例では、継承しているだけSomeBaseClass' prototypeですが、SomeBaseClass好きなプロパティがある場合はどうでしょうか

function SomeBaseClass(){ 
    this.publicProperty='SomeValue'; 
}

あなたがそれを好きなように使うなら

var obj=new MyClass();
console.log(obj.publicProperty); // undefined
console.log(obj);​

objオブジェクトがありませんpublicPropertyようにプロパティを、この例では、

2番目の例

MyClass.prototype = new SomeBaseClass();

constructor関数を実行して、オブジェクトSomeBaseClass全体のインスタンスを作成し、継承しSomeBaseClassます。したがって、使用する場合

    var obj=new MyClass();
    console.log(obj.publicProperty); // SomeValue
    console.log(obj);​

この場合、この例のようpublicProperty、そのプロパティはobjオブジェクトでも使用できます。

Object.create一部の古いブラウザではが利用できないため、その場合は

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

上記のコードObject.createは、使用できない場合に関数を追加するだけなので、Object.create関数を使用できますObject.create。上記のコードは実際に何が行われるかを説明していると思います それが何らかの形で役立つことを願っています。


6
こんにちはシェイク。これについてあなたの努力をありがとう。はい、違いは、コンストラクターが2番目の例では実行されますが、最初の例では実行されないことです。(これは私の場合には望ましいことです)。スーパー実装から継承されない未定義のパブリックプロパティについては、子のコンストラクターでSomeBaseClass.call(this)を呼び出すだけです。このフィドルを確認してください:jsfiddle.net/NhQGB
ChrisRich

ライブラリ/フレームワークを使用せずに、JSで適切に継承するための超シンプルな方法を探していました。この例(上記のフィドルで)は、最新のブラウザーに最適なアプローチだと思います。おそらくObject.Create polyfillはレガシーブラウザのサポートを追加できるでしょうか?
ChrisRich、2012年

基本的に要約すると、.prototype = newを実行すると、基本クラスでこれに割り当てた値を継承し、object.createを実行すると、基本クラスのプロトタイプにあるものだけを継承しますよね?
davidjnelson 2014

この「MyClass.prototype = new SomeBaseClass()」は、MyClassのインスタンスがまだ作成されていないときにSomeBaseClassの新しいインスタンスが作成されることを意味しますか?

いいえ、メインオブジェクトを作成するときのみ、プロトタイプはそれに設定されSomeBaseClassます。
アルファ

39

どちらの例も同じことをするようです。

あなたの場合はそうです。

いつどちらを選ぶか?

SomeBaseClass関数本体がある場合、これはnewキーワードで実行されます。これは通常意図されたものではありません-プロトタイプチェーンをセットアップしたいだけです。同じ特権メソッドを継承するすべてのインスタンスでプライベートスコープの変数が共有されているオブジェクトを実際にインスタンス化するため、深刻な問題が発生する場合もありMyClassます。他の副作用も考えられます。

したがって、通常はを優先する必要がありますObject.create。ただし、一部のレガシーブラウザではサポートされていません。これは、new(明白な)害を与えないことが多いため、アプローチが頻繁に発生しすぎる理由です。また、見ていこの答えを


これが最良の答えです。よく説明されています
spex

8

Object.create()意図した通りに使えば違いがわかります。実際、prototypeコードから単語を完全に隠すことができ、内部で仕事をします。を使用するとObject.create()、次のようになります

var base =  {
    doThis : function(){
    },

    doThat : function(){
    }
};

そして、これから他のオブジェクトを拡張/継承できます

var myObject = Object.create( base );
// myObject will now link to "base" via the prototype chain internally

したがって、これは別の概念であり、より「オブジェクト指向」の方法で継承されます。Object.create()たとえば、を使用してすぐに使用できる「コンストラクタ関数」はありません。もちろん、これらのオブジェクト内で自己定義コンストラクター関数を作成して呼び出すこともできます。

使用するための1つの議論Object.create()は、JavaScriptのデフォルトの方法を使用するよりも、他のオブジェクトから/ * inherit * を混合する方が自然に見えるかもしれないということです


7
Object.createnewコンストラクター関数が必要な場合に、従来のアプローチを実際に置き換えることはできません
Bergi

1
それは間違いなく@Bergiです。このブログ投稿を見てください:davidwalsh.name/javascript-objects-deconstruction。また、初期化オブジェクトを2番目のパラメーターとしてObject.create()に渡すこともできます。
LocalPCGuy 2015

@LocalPCGuy:いいえ、できませんObject.create。クロージャの作成に必要な関数を呼び出さないためです。もちろん、Object.createあなたはinitあなたのオブジェクトにメソッドを置いてすぐにそれを呼び出すことができます、そしてそれthisはあなたが簡潔な構文を得るように戻るかもしれません-しかし待ってください、それその時コンストラクタです。
Bergi

1
init関数の呼び出しはコンストラクターと同様に機能しますが、コンストラクターではありません。そして、そのメソッドでは、従来のアプローチをObject.createに正確に置き換えることができます。また、オブジェクトリンケージのメンタルモデルは、「新規」で作成されたものよりもはるかに単純です。
LocalPCGuy 2015

まあ、私のメンタルモデルnewは「オブジェクトリンケージ」を使用しているので、それほど大きな違いはありません。実際、2つのことだけがあります。.constructorが呼び出され.init、その関数には.prototype、プロトタイプオブジェクトを指すプロパティがありません。残りはちょうど構文です-と私は好むnew XオーバーObject.create(x).init()
Bergi、2015

0

私はJavaスクリプトの専門家ではありませんが、「Object.create」と「new」の違いを理解するための簡単な例を次に示します。

ステップ1:いくつかのプロパティとアクションを持つ親関数を作成します。

function Person() {

this.name = 'venkat';

this.address = 'dallas';

this.mobile='xxxxxxxxxx'

}

Person.prototype.func1 = function () {

    return this.name + this.address;
}

ステップ2:Newキーワードを使用して Person関数の上に拡張される子関数(PersonSalary)を作成します。

function PersonSalary() {
    Person.call(this);
}
PersonSalary.prototype = new Person();

PersonSalary();

ステップ3:Object.createキーワードを使用して、Person関数の上に拡張する2番目の子関数(PersonLeaves)を作成します。

function PersonLeaves() {
 Person.call(this);
}
PersonLeaves.prototype = Object.create(Person.prototype);


PersonLeaves();

//両方の子関数のプロトタイプを確認します。

PersonSalary.prototype
PersonLeaves.prototype

これらの子関数はどちらもPerson(parent function)プロトタイプにリンクし、そのメソッドにアクセスできますが、newを使用して子関数を作成すると、不要なすべての親プロパティを持つ新しいオブジェクトが返されます。 「New」を使用したオブジェクトまたは関数であり、親関数は実行されたくない。

ここにポイントがあります

親関数の一部のメソッドに委任するだけで、新しいオブジェクトを作成したくない場合は、Object.createを使用するのが最善の方法です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.