Dalam beberapa tahun kebelakangan ini, Node.js (selepas ini dirujuk sebagai Node) telah menjadi salah satu platform JavaScript bahagian pelayan yang paling popular di dunia. Walaupun ia mempunyai banyak ciri, sama ada kelajuan berjalan, jejak memori atau perpustakaan dan rangka kerja yang disokong, Node masih mempunyai batasannya sendiri dalam beberapa aspek. Salah satu masalah yang paling menonjol ialah Node.js tidak boleh diwarisi.
Dalam pengaturcaraan berorientasikan objek, warisan ialah ciri penting yang membolehkan pembangun mencipta kelas asas (kelas induk) dan mencipta subkelas lain berdasarkannya. Subkelas ini boleh mengatasi kaedah dalam kelas induk atau menambah kaedah baharu untuk melanjutkan dan menggunakan semula fungsi. Dalam konteks Node.js, warisan biasanya berbentuk penyalinan sifat dan kaedah antara kelas. Walau bagaimanapun, disebabkan model tak segerak Node.js dan interaksinya dengan fleksibiliti JavaScript, pewarisan tidak begitu intuitif dalam Node dan kadangkala sukar untuk dilaksanakan. Artikel ini akan meneroka sebab Node.js gagal mewarisi dan beberapa alternatif.
1. Masalah dalam melaksanakan warisan dalam Node.js
Terdapat dua faktor utama dalam melaksanakan warisan dalam Node.js:
Salah satu ciri Node.js ialah model pengaturcaraan tak segeraknya, yang berkait rapat dengan JavaScript. Memandangkan Node.js adalah satu-benang, ia mesti menggunakan model tak segerak untuk mengendalikan berbilang permintaan pelanggan dan tugas tak segerak yang lain. Model tak segerak menjadikan Node.js lebih cekap, tetapi bercanggah dengan pelaksanaan yang diwarisi. Kerana dalam pengaturcaraan tak segerak, panggilan fungsi dibuat berdasarkan pemasa. Selepas memanggil fungsi tak segerak, program akan terus berjalan sehingga panggilan balik tak segerak selesai sebelum kembali ke fungsi.
Pertimbangkan sekeping kod berikut:
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();
Dalam contoh ini, kita mempunyai kelas Person
dan kelas lain User
, yang mewarisi daripada Person
. Apabila kita memanggil kaedah User
pada contoh login
, kaedah User
unik untuk kelas log
akan dipanggil dahulu, dan kemudian kaedah greet
kelas induk akan dipanggil. Tetapi oleh kerana fungsi itu dilaksanakan secara tidak segerak, hasilnya tidak akan seperti yang kita mahu:
User alice@example.com logged in. undefined
Malah, susunan panggilan tidak betul. Memandangkan this.greet
dipanggil berdasarkan tingkah laku tak segerak, pelaksanaan kaedah ini berlaku selepas panggilan balik kaedah User.log
tak segerak. Itulah sebabnya undefined
dicetak pada skrin.
Masalah kedua ialah sokongan JavaScript sendiri untuk corak pengaturcaraan berorientasikan objek. JavaScript bukan bahasa berorientasikan objek tradisional dan menggunakan model objek berasaskan prototaip dan bukannya model objek berasaskan kelas. Model prototaip tidak menyokong warisan kelas secara langsung seperti warisan Jika anda ingin melaksanakan warisan dalam Node.js, anda perlu menggunakan beberapa kemahiran pengaturcaraan berorientasikan objek JavaScript.
Dalam corak warisan berasaskan prototaip, pembangun perlu menggunakan kaedah Object.create()
untuk mencipta objek dan menghantarnya kepada subkelas sebagai prototaip. Kelebihan corak warisan ini ialah ia lebih fleksibel kerana ia membolehkan anda mewarisi bukan sahaja kaedah kelas, tetapi juga sifat.
Berikut ialah contoh berasaskan prototaip:
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();
Dalam contoh ini, kami mencipta objek secara manual dan kemudian menghalakan prototaipnya ke Person.prototype
. Apabila mentakrifkan User
, kami tidak mewarisi langsung Person
, tetapi menggunakan kaedah Object.create
untuk mencipta objek berdasarkan prototaip kelas induk. Pengguna mendaftarkan pengguna melalui User.constructor
panggilan fungsi.
2. Penyelesaian
Walaupun Node.js mempunyai beberapa had, terdapat beberapa penyelesaian untuk mencapai fungsi yang diwarisi. Di sini kami memperkenalkan beberapa penyelesaian biasa:
Node.js mempunyai seni bina berasaskan modul dan anda boleh menggunakan model ini untuk mencipta modul yang melaksanakan harta pusaka . Sistem modul Node.js membolehkan anda mengimport fungsi, objek dan kelas dalam fail JavaScript yang berbeza dan menggabungkannya ke dalam satu modul. Cara untuk melaksanakan warisan adalah dengan mencipta modul kelas induk dan modul kelas anak, dan menggunakan fungsi, objek dan kelas modul kelas induk dalam modul kelas anak.
Berikut ialah contoh di mana pelaksanaan mewarisi daripada kelas Orang
//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();
Dalam contoh ini, kami mempunyai modul Person
dan modul User
, modul yang terakhir mewarisi daripada bekas. Harap maklum bahawa kami menggunakan User
dalam modul require('./person')
untuk mengimport modul Person
dan menggunakan extends Person
untuk mewarisi User
daripada Person
. Akhir sekali, kami mencipta objek User
dan cuba memanggil kaedah greet
. Keputusan kali ini tiada masalah.
Cara lain untuk menyelesaikan masalah dalam Node.js ialah menggunakan Proksi ES6. Proksi ialah ciri baharu dalam JavaScript yang membolehkan kami menjalankan fungsi cangkuk pada objek atau fungsi dan mengubah tingkah lakunya berdasarkan permintaan kami.
Berikut ialah contoh:
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 等解决方案来实现继承,以实现更完整的面向对象编程体验。无论使用哪种方案,重要的是确保我们在开发过程中遵循最佳实践,以确保代码的可维护性和稳健性。
Atas ialah kandungan terperinci Mengapa nodejs tidak boleh diwarisi. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!