7

私は最近、いくつかのgnome shell拡張機能を記述して、javascriptを学習しています。したがって、Javascriptの理解は、gnome-shelljavascriptソースで観察した例によって形作られています。私はクラスを間違って理解していると感じており、いくつかの説明が必要です。

私はいくつかの独自のサブクラスを作成しましたが、いずれの場合も、gnome-shelljavascriptソースの同様のコードに従うだけでそれらを定義しました。

Subclass = function() {
    this._init.apply(this,arguments);
}
Subclass.prototype = {
    __proto__: Superclass.prototype,
    _init: function() {
        Superclass.prototype._init.call(this);
    },
    // add other methods of Subclass here.
}

Subclassこれまでは、これが基本的にSuperclassプラスエクストラであるクラスを作成する標準的な方法だと思っていました。すべてのオブジェクトに_initメソッドがあると思いました。

私は最近、同じメソッドを適用してaのサブクラスを作成しようとしましたClutter.Actor(重要なのは、それがGNOMEシェル定義のクラスではないことです)。オブジェクトをサブクラス化する上記の方法は標準ではないことに気付きました。一つには、すべてのクラスが_init私が想定したような機能を持っているわけではありません。これは、GNOMEシェルがjavascriptクラスで行ったことにすぎません。

だから、私の質問は

  1. サブクラスを作成する上記の方法に関するドキュメントはありますか?私が見たすべてのチュートリアルは、メソッドSubclass.prototype = new Superclass()を実行する代わりに設定するように言ってSubclass.prototype = { __proto__:Superclass.prototype, define_prototype_methods_here }いますが、gnome-shellが一貫して使用する場合は、何らかのメソッドが必要だと思いますか?
  2. クラスを定義する上記の方法にできるだけ近づきたい場合(拡張機能を記述しているGNOMEシェルとのコードの類似性を維持できるようにするため)、すべてを確実に取得するため何に置き換えますか?Superclass.prototype._init.call(this)のメソッド/プロパティ(次に、の定義に追加します)に、関数がない場合(つまり、呼び出す同等のコンストラクター関数がある場合)?Subclass._initSubclass.prototypeSuperclassSubclass.prototypeSuperclass_init

私はこれについて本当に混乱しているので、私の質問があまり意味をなさない場合は許してください。それは私の誤解と混乱の程度のせいでしょう!

編集:説明:-__proto__これは非標準であるため推奨されないことはわかっていますが、私のコードはブラウザで実行されることはありません-GNOME javascript(基本的にはMozilla javascriptエンジン)でのみ実行されるためです。相互互換性について心配する必要はありません。

4

3 に答える 3

8

すでに述べたように、は使用しないでください__proto__これは非標準のプロパティです。 (現在、ブラウザーではJavaScript用に標準化されています。それでも使用しないでください。)しかし、

Subclass.prototype = new Superclass(); // Don't do this

あまり良い方法でもありません。Superclassパラメータを期待する場合はどうなりますか?

より良い選択肢があります。

ES2015以降

classこのすべての配管を処理します。完全な例:

class Superclass {
    constructor(superProperty) {
        this.superProperty = superProperty;
    }
    method() {
        console.log("Superclass's method says: " + this.superProperty);
    }
}
class Subclass extends Superclass {
    constructor(superProperty, subProperty) {
        super(superProperty);
        this.subProperty = subProperty;
    }
    method() {
        super.method(); // Optional, do it if you want super's logic done
        console.log("Subclass's method says: " + this.subProperty);
    }
}

let o = new Subclass("foo", "bar");
console.log("superProperty", o.superProperty);
console.log("subProperty", o.subProperty);
console.log("method():");
o.method();

ES5以前

からのみSubclass.prototype継承しましょう。Superclass.prototypeこれは、たとえばES5を使用して実行できますObject.create

Subclass.prototype = Object.create(Superclass.prototype);
Subclass.prototype.constructor = Subclass;

次に、では、オブジェクトを参照してSubclass呼び出し、初期化する機会があります。Superclassthis

function Subclass() {
    Superclass.call(this); // Pass along any args needed
}

完全な例:

function Superclass(superProperty) {
    this.superProperty = superProperty;
}
Superclass.prototype.method = function() {
    console.log("Superclass's method says: " + this.superProperty);
};
function Subclass(superProperty, subProperty) {
    Superclass.call(this, superProperty);
    this.subProperty = subProperty;
}
Subclass.prototype = Object.create(Superclass.prototype);
Subclass.prototype.constructor = Subclass;

Subclass.prototype.method = function() {
    Superclass.prototype.method.call(this); // Optional, do it if you want super's logic done
    console.log("Subclass's method says: " + this.subProperty);
};

var o = new Subclass("foo", "bar");
console.log("superProperty", o.superProperty);
console.log("subProperty", o.subProperty);
console.log("method():");
o.method();

ES3以前

ES3以前にはがありませんがObject.create、ほぼ同じ方法でプロトタイプを設定する関数を簡単に作成できます。

function objectCreate(proto) {
    var ctor = function() { };
    ctor.prototype = proto;
    return new ctor;
}

(注:Object.create引数を1つだけ取るものを作成することでハーフシムを作成できますが、の複数引数バージョンをシムすることはObject.createできないため、ページ上の他のコードも使用すると、間違ったアイデアが表示されますObject.create。)

次に、ES5の例と同じことを行います。

完全な例:

function objectCreate(proto) {
    var ctor = function() { };
    ctor.prototype = proto;
    return new ctor;
}

function Superclass(superProperty) {
    this.superProperty = superProperty;
}
Superclass.prototype.method = function() {
    console.log("Superclass's method says: " + this.superProperty);
};
function Subclass(superProperty, subProperty) {
    Superclass.call(this, superProperty);
    this.subProperty = subProperty;
}
Subclass.prototype = objectCreate(Superclass.prototype);
Subclass.prototype.constructor = Subclass;

Subclass.prototype.method = function() {
    Superclass.prototype.method.call(this); // Optional, do it if you want super's logic done
    console.log("Subclass's method says: " + this.subProperty);
};

var o = new Subclass("foo", "bar");
console.log("superProperty", o.superProperty);
console.log("subProperty", o.subProperty);
console.log("method():");
o.method();

于 2012-05-14T09:29:12.960 に答える
1

現在、Webブラウザで使用する場合はJavaScriptの必須の拡張機能として標準化されてい__proto__ますが、継承階層を設定するときに使用する理由はありません。

代わりに、Object.create(ES5関数を使用してください。時代遅れのブラウザーを本当にサポートする必要がある場合は、ここでの目的のために重要な部分をシムすることができます)。

これが次の場合の例です

var BaseClass = function() {
};

var SubClass = function() {
    // Important that SubClass give BaseClass a chance to init here
    BaseClass.call(this/*, args, if, necessary, here*/);

    // ...
};

// Make `SubClass`'s `prototype` an object that inherits from
// `BaseClass`'s `prototype`:
SubClass.prototype = Object.create(BaseClass.prototype);

// Fix up the `constructor` property
SubClass.prototype.constructor = SubClass;

それでおしまい。

のコンストラクターに引数が必要な場合BaseClassは、引数を次のように渡しますSubClass

これが次の場合の例です

var BaseClass = function(arg) {
    this.prop = arg;
};

var SubClass = function(baseArg) {   // Can accept it, or provide a
    BaseClass.call(this, baseArg);   // hardcoded one here

    // ...
};

SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;

もちろん、ES2015(別名「ES6」)の時点では、そのまま使用できますclass(必要に応じてトランスパイルできます)。

class BaseClass {
    constructor(arg) {
        this.prop = arg;
    }
}

class SubClass extends BaseClass {
    constructor(baseArg) {
        super(baseArg);
    }
}
于 2016-10-08T14:33:30.657 に答える
0

__proto__JavaScriptエンジンの実装では、オブジェクトのクラス定義プロトタイプを参照するために使用されるため、コードで使用しないでください。参照:MDN:__proto__

1>

 Subclass.prototype = new Superclass();

スーパークラスを継承する正しい方法です。

2>スーパークラスの_initメソッドを実際に実行するサブクラスで_initを呼び出したい場合は、サブクラスクラスで定義しないでください。subClass(SubClassのインスタンスオブジェクト)で_initメソッドにアクセスしようとすると、JSエンジンは現在のオブジェクトでそれを検索しようとします。メソッドが見つからない場合は、SubClassプロトタイプタイプチェーン(つまりSuperClass)で検索されます。

サブクラスメソッド内でスーパークラスメソッドを呼び出したい場合は、

Superclass.prototype._init.call(this)

現在のオブジェクトスコープでスーパー関数を実行します。これは、SubClassメソッド内でスーパーメソッドを呼び出すトリックを行います

于 2012-05-14T09:16:16.053 に答える