ホームページ  >  記事  >  ウェブフロントエンド  >  なぜnodejsは継承できないのか

なぜnodejsは継承できないのか

PHPz
PHPzオリジナル
2023-04-26 09:06:54467ブラウズ

近年、Node.js (以下、Node) は、世界で最も人気のあるサーバーサイド JavaScript プラットフォームの 1 つになりました。 Node には、実行速度、メモリ使用量、サポートされているライブラリやフレームワークなど、多くの機能がありますが、いくつかの側面では依然として独自の制限があります。最も顕著な問題の 1 つは、Node.js を継承できないことです。

オブジェクト指向プログラミングでは、継承は開発者が基本クラス (親クラス) を作成し、それに基づいて他のサブクラスを作成できるようにする重要な機能です。これらのサブクラスは、親クラスのメソッドをオーバーライドしたり、新しいメソッドを追加して機能を拡張および再利用したりできます。 Node.js のコンテキストでは、継承は通常、クラス間でプロパティとメソッドをコピーする形式をとります。ただし、Node.js の非同期モデルと JavaScript の柔軟性との相互作用により、Node では継承があまり直感的ではなく、実装が難しい場合があります。この記事では、Node.js が継承できない理由といくつかの代替案について説明します。

1. Node.js での継承の実装の問題

Node.js での継承の問題を認識するには 2 つの重要な要素があります:

  1. 非同期プログラミングモデル

Node.js の機能の 1 つは、JavaScript と密接に関係している非同期プログラミング モデルです。 Node.js はシングルスレッドであるため、複数のクライアント要求やその他の非同期タスクを処理するには、非同期モデルを使用する必要があります。非同期モデルは Node.js の効率を高めますが、継承された実装と競合します。非同期プログラミングでは、関数呼び出しはタイマーに基づいて行われるためです。非同期関数を呼び出した後、プログラムは実行を継続し、非同期コールバックが完了するまで関数には戻りません。

次のコード部分を考えてみましょう:

class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`Hello, my name is ${this.name}.`);
  }
}

class User extends Person {
  constructor(name, email) {
    super(name);
    this.email = email;
  }

  static log(email) {
    console.log(`User ${email} logged in.`);
  }

  login() {
    User.log(this.email);
    this.greet();
  }
}

const alice = new User('Alice', 'alice@example.com');
alice.login();

この例には、クラス Person と、# を継承する別のクラス User があります。 ##人###。 User インスタンスで login メソッドを呼び出すときは、まず User クラスに固有の log メソッドを呼び出し、次に親クラスの greet メソッドを呼び出します。ただし、関数は非同期で実行されるため、結果は期待どおりにはなりません。<pre class="brush:php;toolbar:false">User alice@example.com logged in. undefined</pre>実際、呼び出し順序は間違っています。

this.greet

は非同期動作に基づいて呼び出されるため、このメソッドの実行は、非同期 User.log メソッドのコールバックの後に実行されます。そのため、画面には 未定義 が表示されます。

オブジェクト指向 JavaScript
  1. 2 番目の問題は、JavaScript 自体のオブジェクト指向プログラミング パターンのサポートです。 JavaScript は従来のオブジェクト指向言語ではなく、クラスベースのオブジェクト モデルではなくプロトタイプベースのオブジェクト モデルを使用します。プロトタイプ モデルは、継承のようなクラス継承を直接サポートしていません。Node.js で継承を実装したい場合は、JavaScript オブジェクト指向プログラミング スキルを使用する必要があります。

プロトタイプベースの継承モデルでは、開発者は

Object.create()

メソッドを使用してオブジェクトを作成し、それをプロトタイプとしてサブクラスに渡す必要があります。この継承パターンの利点は、クラスのメソッドだけでなくプロパティも継承できるため、柔軟性が高いことです。 以下はプロトタイプベースの例です:

class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`Hello, my name is ${this.name}.`);
  }
}

const User = Object.create(Person.prototype, {
  email: { value: null, enumerable: true, writable: true }
});

User.constructor = User;

User.constructor('Tom', 'tom@example.com');

console.log(User);
User.greet();

この例では、オブジェクトを手動で作成し、そのプロトタイプを

person.prototype

に指定します。 User を定義するとき、Person を直接継承するのではなく、Object.create メソッドを使用して、親クラスのプロトタイプに基づいてオブジェクトを作成しました。ユーザーは、User.constructor 関数呼び出しを通じてユーザーを登録します。 2. 解決策

Node.js にはいくつかの制限がありますが、継承された機能を実現するための解決策がいくつかあります。ここでは、一般的なソリューションをいくつか紹介します。

モジュールベースの継承
  1. Node.js にはモジュールベースのアーキテクチャがあり、このモデルを使用して実装するモジュールを作成できます。継承。 。 Node.js のモジュール システムを使用すると、さまざまな JavaScript ファイルの関数、オブジェクト、クラスをインポートし、それらを 1 つのモジュールに結合できます。継承を実装するには、親クラス モジュールと子クラス モジュールを作成し、親クラス モジュールの関数、オブジェクト、クラスを子クラス モジュールで使用します。

これは Person クラスを継承する例です

//person.js
module.exports = class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`Hello, my name is ${this.name}.`);
  }
};

//user.js
const Person = require('./person');

class User extends Person {
  constructor(name, email) {
    super(name);
    this.email = email;
  }

  static log(email) {
    console.log(`User ${email} logged in.`);
  }

  login() {
    User.log(this.email);
    this.greet();
  }
}

const user = new User('Tom', 'tom@example.com');
user.login();

この例では、

Person

モジュールと User モジュールがあります。後者は前者から引き継いでいます。 User モジュールで require('./person') を使用し、Person モジュールをインポートし、extends Person を使用したことに注意してください。 Userperson から継承します。最後に、User オブジェクトを作成し、greet メソッドの呼び出しを試みます。今回の結果は問題ありませんでした。

ES6 プロキシの使用
  1. Node.js の問題を解決するもう 1 つの方法は、ES6 プロキシを使用することです。プロキシは JavaScript の新機能で、これを使用すると、オブジェクトまたは関数に対してフック関数を実行し、リクエストに基づいてそれらの動作を変更できます。

これが例です:

class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`Hello, my name is ${this.name}.`);
  }
}

class User extends Person {
  constructor(name, email) {
    super(name);
    this.email = email;
    this.proxy = new Proxy(this, {
      get(target, propKey) {
        return target[propKey] || target.__proto__[propKey];
      },
    });
  }

  static log(email) {
    console.log(`User ${email} logged in.`);
  }

  login() {
    User.log(this.email);
    this.proxy.greet();
  }
}

const user = new User('Tom', 'tom@example.com');
user.login();

在这个例子中,我们使用了一个新的属性 this.proxy。该属性是使用 new Proxy() 创建一个新的 Proxy 实例,该实例包装了当前的对象。 我们在 get 钩子函数中进行了一些重点的操纵,当我们通过 this.proxy.greet() 调用 greet 方法时,它会在当前对象上执行搜索不到,然后自动查找其原型,并在原型上找到该方法。

三、总结

继承是面向对象编程中的一个重要特性。然而,在 Node.js 的环境中,由于其异步性和 JavaScript 本身的面向对象编程模型,继承并不像在传统面向对象语言中那样简单直观。但是,我们可以通过模块模式和 ES6 Proxy 等解决方案来实现继承,以实现更完整的面向对象编程体验。无论使用哪种方案,重要的是确保我们在开发过程中遵循最佳实践,以确保代码的可维护性和稳健性。

以上がなぜnodejsは継承できないのかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。