0

Base2 つのクラスがあるとしましょうChild。Base は、Child の継承元となる基本クラスです。これを視覚化するコードは次のとおりです。

Base.js

function Base(init) {

}

function log() {
  console.log('here');
}
Base.prototype.log = log;

module.exports = Base;

Child.js

var Base = require('../Base.js');

var Child = module.exports = function Child(init) {
  Base.call(this, init);
};

require('util').inherits(Child, Base);

function test() {
  this.log();  // doesn't work
  Base.prototype.log();  // Works but is quite ugly
  Child.super_.prototype.log();  // Works but is even uglier
}

Child.prototype.test = test;

私が絶対にやりたいことは、次のようなthis.log()ことlog()です。継承されたクラスで変数を設定できることはわかっていますが、継承するすべてのクラスに対してそれを行う必要がありBase、これは間違いなく理想的ではありません。this.log()だから私の質問は、継承されたクラスに変数を設定することなく、何かをすることができますか? 私は何か誤解していますか?

4

4 に答える 4

1

更新された回答:

以下のコメントから、うまくいくはずの私の声明に返信してthis.log()ください:

まあ、それが事です。私が子のテスト関数にいるときthisは空のオブジェクトなので、適切なスコープを取得していない行のどこかを想定しています。

をどのように呼び出しているかは示されていませんがtest、そこに問題があると思われます。インスタンス経由で呼び出すChild場合:

var c = new Child();
c.test();

...その後、呼び出し内で子インスタンスになり、そのプロパティを持つオブジェクトをthis(間接的に) 継承します。Parent.prototypelog

でも、呼び方が大事。たとえば、これは機能しません。

var c = new Child();
var f = c.test;
f();

これを行うと、関数の呼び出し内で、インスタンスではなくthisグローバル オブジェクトになります (またはundefined厳密モードの場合) Child。これは、JavaScript では、this主に関数の呼び出し方法によって設定され、そのように呼び出しても目的の設定thisにならないためです。

c.testコールバックとして渡すため、これはコールバックにとって重要です。

someFunctionThatUsesACallback(c.test);

...コールバックするコードが設定されないことを意味thisします。

それを行う必要がある場合は、次のFunction#bindことが役立ちます。

var f = c.test.bind(c); // Returns a version of c.test that, when called,
                        // will have `this` set to `c`
f();                    // Works, `this` is the `Child` instance

同様に:

someFunctionThatUsesACallback(c.test.bind(c));

詳細 (私のブログ):


元の回答:

プロトタイプ階層を正しく設定し、それChild.prototypeを持っlogていない (そしてlogインスタンスにプロパティを設定していない) 場合は、問題なく使用できるはずですthis.log();。できない場合は、階層が正しく設定されていません。

何が機能するのかわかりませんがutil.inherits、 と の関係ChildParent正しく設定することは複雑ではありません。

function Parent() {
}
Parent.prototype.log = function() {
    console.log("log called");
};

function Child () {
    Parent.call(this);
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child; // This line is largely optional, but a good idea

// Usage
var c = new Child();
c.log(); // "log called"

しかし、プロパティをインスタンスにオーバーライドlogChild.prototypeたり割り当てたりして、のバージョンのlogを使用したい場合は、プロパティがもう参照されないため、そのまま使用することはできません。Parentlogthis.log()Parent.prototype.log

何かの親バージョンを呼び出す必要がある場合 (私はそれらを「スーパーコール」と呼んでいますが、それはオリジナルではないと思います)、さらに多くの作業を行う必要があります。

私は通常、子を構築するために使用する関数に親コンストラクターを渡すことにより、このような階層を設定します。

var Child = (function(Super) {
    var pp = Super.prototype;

    function Child() {
    }
    Child.prototype = Object.create(pp);

    Child.prototype.doSomething = function() {
        // Call `log` with appropriate `this`
        pp.log.call(this);
    };

    return Child;
})(Parent);

常にそのパターンを使用することで、コードParent内に記述する必要がなくなります (代わりに arg を使用します)。そのため、 rebase が必要な場合は、関数に渡すものを変更するだけです。ChildSuperChild

これはかなり醜い (たとえば、 が一番下にあるため、 からChild派生したものであることが一番上では不明確です) し、ボイラープレート コードが含まれているので、毎回書き直す必要はないと思います。そのための簡単なヘルパー スクリプトを作成しました。を呼び出すと、次のようになります。ParentParentLineage

var Child = Lineage.define(Parent, function(p, pp) {
    p.doSomething = function() {
        // Call `log` with appropriate `this`
        pp.log.call(this);
    };
});

とプロトタイプLineageの両方を引数として渡すことに注意してください。これにより、それらを簡潔に使用できます (そして、これらの引数名を選択できるため、自分に合った用語を使用できます — 私は作成中の「クラス」のプロトタイプに使用します [上記の]、および親のプロトタイプなど)。ChildParentpChildpp

于 2014-04-11T16:30:06.327 に答える
0

global参考までに、これを Node が作成する変数に入れることになりました。それが悪い習慣であることは理解していますが、これはあらゆるクラス、コントローラーなどで使用する必要があるロギング メカニズムであるため、それほどひどい解決策ではないと思います。

ただし、Compound では、no_evalコントローラーを作成できます。つまり、典型的なプロトタイプ関数のように見えることを意味します。したがって、基本的にmixinを作成するか、自分の mixin を要求してクラスのように使用できます。次のようにします。

var ControllerMixin = require(process.cwd() + 'app/mixins/ControllerMixin.js');
var Log;

var LoggerController = module.exports = function LoggerController(init) {
  ControllerMixin.call(this, init);  // mixin approach
  Log = require(process.cwd() + 'app/utils/LoggerMixin.js')(init);  // class approach
};

LoggerController.prototype.index = function index(controller) {
  controller.logMessage('blah');  // using mixin
  Log.logError('hi');  // using class
  global.logWarning('yep');  // global approach
  return controller.send({success: true});
};

したがって、オプションがあります...最善のアプローチであると思われるものを見つける必要があります。

于 2014-08-28T23:36:47.420 に答える
0

node.jsの標準inherits関数は (私の謙虚な意見では) 非常に悪いコードです。代わりにaugment、クラスを作成するために使用することを好みます。

// base.js

var augment = require("augment");

var Base = module.exports = augment(Object, function () {
    this.constructor = function (init) {

    };

    this.log = function () {
        console.log("here");
    };
});

// child.js

var augment = require("augment");
var Base = require("./base");

var Child = module.exports = augment(Base, function (base) {
    this.constructor = function (init) {
        base.constructor.call(this, init);
    };

    this.test = function () {
        this.log();
    };
});

さらに、augment.jsはわずか 20 行のコードであり、どこでも使用できます。

于 2014-04-11T16:36:21.827 に答える
-1

私がオンラインで見るすべての回答は、複雑に見えるか、外部ライブラリに依存しています。従来の OOP と非常によく似たカスタム型の設計パターンを使用すると仮定して、基本にまで煮詰めてみませんか。

親.js

//the main parent class
// class Parent


module.exports = Parent;

function Parent(a) {
    if (!(this instanceof Parent)) {
        return new Parent(a);
    }
    this.a = a; //Some parent variable
}

Parent.prototype = {

    // Instantiate child:
    getChild: function() {
        var Child = require('./child');
        return new Child(this);
    },

    // Some parent function, print some text:
    printText: function(text) {
        console.log(text);
    }
};

child.js

//Similar to class Child extends Parent


module.exports = Child;

function Child(parent) {

    this.parent = parent;
}

Child.prototype = {

    // Prints Parent Variable:
    printParentVariable: function() {
        console.log(this.parent.a);
    },

    // Calls Parent Function:
    callParentFunction: function() {
        this.parent.printText('Child calling parent function.');
    }
};

test.js

var parent = require('./parent')('parent text'); //instantiate parent with some text

var child = parent.getChild();       //create instance of a child

//*** Child has full access to its parents variables and methods ***//

console.log(child.parent.a);         //Print the parent text "parent text"
child.printParentVariable();         //Child method which prints the parent variable "parent text", identical to line above.
child.parent.printText('Child calling parent');      //Call parent method, to print provided text
child.callParentFunction();          //Calls parent method, identical to above.
于 2016-02-07T11:44:20.063 に答える