Pengenalan paradigma OOP mempopularkan konsep pengaturcaraan utama seperti Warisan, Polimorfisme, Abstraksi dan Enkapsulasi. OOP dengan cepat menjadi paradigma pengaturcaraan yang diterima secara meluas dengan pelaksanaan dalam beberapa bahasa seperti Java, C , C#, JavaScript dan banyak lagi. Sistem OOP menjadi lebih kompleks dari semasa ke semasa, tetapi perisiannya kekal tahan terhadap perubahan. Untuk meningkatkan kebolehlanjutan perisian dan mengurangkan ketegaran kod, Robert C. Martin (a.k.a Uncle Bob) memperkenalkan prinsip SOLID pada awal 2000-an.
SOLID ialah akronim yang terdiri daripada satu set prinsip — prinsip tanggungjawab tunggal, prinsip tertutup terbuka, prinsip penggantian Liskov, prinsip pengasingan antara muka dan prinsip penyongsangan kebergantungan — yang membantu jurutera perisian mereka bentuk dan menulis boleh diselenggara, berskala dan fleksibel kod. Matlamatnya? Untuk meningkatkan kualiti perisian yang dibangunkan mengikut paradigma Pengaturcaraan Berorientasikan Objek (OOP).
Dalam artikel ini, kami akan menyelidiki semua prinsip SOLID dan menggambarkan cara ia dilaksanakan menggunakan salah satu bahasa pengaturcaraan web yang paling popular, JavaScript.
Huruf pertama dalam SOLID mewakili prinsip tanggungjawab tunggal. Prinsip ini mencadangkan bahawa kelas atau modul harus melaksanakan hanya satu peranan.
Ringkasnya, kelas harus mempunyai satu tanggungjawab atau satu sebab untuk berubah. Jika kelas mengendalikan lebih daripada satu fungsi, mengemas kini satu fungsi tanpa menjejaskan yang lain menjadi rumit. Komplikasi seterusnya boleh mengakibatkan kerosakan dalam prestasi perisian. Untuk mengelakkan masalah seperti ini, kita harus melakukan yang terbaik untuk menulis perisian modular di mana kebimbangan diasingkan.
Jika kelas mempunyai terlalu banyak tanggungjawab atau fungsi, ia menjadi sakit kepala untuk mengubah suai. Dengan menggunakan prinsip tanggungjawab tunggal, kita boleh menulis kod yang modular, lebih mudah diselenggara dan kurang terdedah kepada ralat. Ambil, sebagai contoh, model seseorang:
class Person { constructor(name, age, height, country){ this.name = name this.age = age this.height = height this.country = country } getPersonCountry(){ console.log(this.country) } greetPerson(){ console.log("Hi " + this.name) } static calculateAge(dob) { const today = new Date(); const birthDate = new Date(dob); let age = today.getFullYear() - birthDate.getFullYear(); const monthDiff = today.getMonth() - birthDate.getMonth(); if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { age--; } return age; } }
Kod di atas nampaknya baik, bukan? Tidak cukup. Kod sampel melanggar prinsip tanggungjawab tunggal. Daripada menjadi satu-satunya model dari mana contoh Orang lain boleh dibuat, kelas Orang juga mempunyai tanggungjawab lain seperti kalkulasiAge, greetPerson dan getPersonCountry.
Tanggungjawab tambahan yang dikendalikan oleh kelas Person ini menyukarkan untuk menukar hanya satu aspek kod. Contohnya, jika anda cuba memfaktorkan semula calculateAge, anda mungkin juga terpaksa memfaktorkan semula model Person. Bergantung pada seberapa padat dan kompleks asas kod kami, mungkin sukar untuk mengkonfigurasi semula kod tanpa menyebabkan ralat.
Mari cuba dan semak semula kesilapan itu. Kita boleh memisahkan tanggungjawab ke dalam kelas yang berbeza, seperti:
class Person { constructor(name, age, height, country){ this.name = name this.age = age this.height = height this.country = country } getPersonCountry(){ console.log(this.country) } greetPerson(){ console.log("Hi " + this.name) } static calculateAge(dob) { const today = new Date(); const birthDate = new Date(dob); let age = today.getFullYear() - birthDate.getFullYear(); const monthDiff = today.getMonth() - birthDate.getMonth(); if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { age--; } return age; } }
Seperti yang anda boleh lihat daripada kod sampel di atas, kami telah mengasingkan tanggungjawab kami. Kelas Orang kini merupakan model yang dengannya kita boleh mencipta objek orang baharu. Dan kelas PersonUtils hanya mempunyai satu tanggungjawab — untuk mengira umur seseorang. Kelas PersonService mengendalikan ucapan dan menunjukkan kepada kita negara setiap orang.
Jika kita mahu, kita masih boleh mengurangkan lagi proses ini. Berikutan SRP, kami ingin memisahkan tanggungjawab kelas ke tahap minimum supaya apabila terdapat isu, pemfaktoran semula dan penyahpepijatan boleh dilakukan tanpa banyak kerumitan.
Dengan membahagikan fungsi kepada kelas yang berasingan, kami mematuhi prinsip tanggungjawab tunggal dan memastikan setiap kelas bertanggungjawab untuk aspek khusus aplikasi.
Sebelum kita beralih ke prinsip seterusnya, perlu diingatkan bahawa mematuhi SRP tidak bermakna setiap kelas harus tegas mengandungi satu kaedah atau fungsi.
Walau bagaimanapun, mematuhi prinsip tanggungjawab tunggal bermakna kita harus bersungguh-sungguh dalam memberikan fungsi kepada kelas. Segala sesuatu yang dijalankan oleh kelas haruslah berkait rapat dalam setiap segi. Kita mesti berhati-hati agar tidak mempunyai beberapa kelas berselerak di merata-rata tempat, dan kita harus, dengan segala cara, mengelakkan kelas yang membuak-buak dalam pangkalan kod kita.
Prinsip buka-tutup menyatakan bahawa komponen perisian (kelas, fungsi, modul, dll.) harus terbuka kepada sambungan dan tertutup kepada pengubahsuaian. Saya tahu apa yang anda fikirkan — ya, idea ini mungkin kelihatan bercanggah pada mulanya. Tetapi OCP hanya meminta perisian itu direka bentuk dengan cara yang membolehkan sambungan tanpa perlu mengubah suai kod sumber.
OCP adalah penting untuk mengekalkan pangkalan kod yang besar, kerana garis panduan ini membolehkan anda memperkenalkan ciri baharu dengan sedikit atau tiada risiko melanggar kod. Daripada mengubah suai kelas atau modul sedia ada apabila keperluan baharu timbul, anda harus melanjutkan kelas yang berkaitan dengan menambah komponen baharu. Semasa anda melakukan ini, pastikan anda menyemak bahawa komponen baharu tidak memperkenalkan sebarang pepijat kepada sistem.
Prinsip OC boleh dicapai dalam JavaScript menggunakan ciri Warisan kelas ES6.
Coretan kod berikut menggambarkan cara melaksanakan prinsip Terbuka-Tutup dalam JavaScript, menggunakan kata kunci kelas ES6 yang disebutkan di atas:
class Person { constructor(name, dateOfBirth, height, country){ this.name = name this.dateOfBirth = dateOfBirth this.height = height this.country = country } } class PersonUtils { static calculateAge(dob) { const today = new Date(); const birthDate = new Date(dob); let age = today.getFullYear() - birthDate.getFullYear(); const monthDiff = today.getMonth() - birthDate.getMonth(); if(monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { age--; } return age; } } const person = new Person("John", new Date(1994, 11, 23), "6ft", "USA"); console.log("Age: " + PersonUtils.calculateAge(person.dateOfBirth)); class PersonService { getPersonCountry(){ console.log(this.country) } greetPerson(){ console.log("Hi " + this.name) } }
Kod di atas berfungsi dengan baik, tetapi ia terhad untuk mengira hanya luas segi empat tepat. Sekarang bayangkan bahawa terdapat keperluan baru untuk mengira. Katakan, sebagai contoh, kita perlu mengira luas bulatan. Kami perlu mengubah suai kelas shapeProcessor untuk memenuhinya. Walau bagaimanapun, mengikut piawaian JavaScript ES6, kami boleh melanjutkan fungsi ini untuk mengambil kira kawasan bentuk baharu tanpa perlu mengubah suai kelas shapeProcessor.
Kita boleh melakukannya seperti itu:
class Person { constructor(name, age, height, country){ this.name = name this.age = age this.height = height this.country = country } getPersonCountry(){ console.log(this.country) } greetPerson(){ console.log("Hi " + this.name) } static calculateAge(dob) { const today = new Date(); const birthDate = new Date(dob); let age = today.getFullYear() - birthDate.getFullYear(); const monthDiff = today.getMonth() - birthDate.getMonth(); if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { age--; } return age; } }
Dalam coretan kod di atas, kami memperluaskan fungsi kelas Shape dengan menggunakan kata kunci extends. Dalam setiap subkelas, kami mengatasi pelaksanaan kaedah kawasan(). Mengikut prinsip ini, kami boleh menambah lebih banyak bentuk dan kawasan proses tanpa perlu mengubah suai kefungsian kelas ShapeProcessor.
Prinsip penggantian Liskov menyatakan bahawa objek subkelas seharusnya boleh menggantikan objek superclass tanpa melanggar kod. Mari kita pecahkan cara ia berfungsi dengan contoh: jika L ialah subkelas P, maka objek L harus menggantikan objek P tanpa memecahkan sistem. Ini hanya bermakna bahawa subkelas sepatutnya dapat mengatasi kaedah superclass dengan cara yang tidak memecahkan sistem.
Dalam amalan, prinsip penggantian Liskov memastikan syarat berikut dipatuhi:
Sudah tiba masanya untuk menggambarkan prinsip penggantian Liskov dengan sampel kod JavaScript. Lihatlah:
class Person { constructor(name, dateOfBirth, height, country){ this.name = name this.dateOfBirth = dateOfBirth this.height = height this.country = country } } class PersonUtils { static calculateAge(dob) { const today = new Date(); const birthDate = new Date(dob); let age = today.getFullYear() - birthDate.getFullYear(); const monthDiff = today.getMonth() - birthDate.getMonth(); if(monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { age--; } return age; } } const person = new Person("John", new Date(1994, 11, 23), "6ft", "USA"); console.log("Age: " + PersonUtils.calculateAge(person.dateOfBirth)); class PersonService { getPersonCountry(){ console.log(this.country) } greetPerson(){ console.log("Hi " + this.name) } }
Dalam coretan kod di atas, kami mencipta dua subkelas (Basikal dan Kereta) dan satu superclass (Kenderaan). Untuk tujuan artikel ini, kami melaksanakan satu kaedah (OnEngine) untuk superclass.
Salah satu syarat teras untuk LSP ialah subkelas harus mengatasi kefungsian kelas induk tanpa melanggar kod. Dengan mengingati perkara itu, mari kita lihat bagaimana coretan kod yang baru kita lihat melanggar prinsip penggantian Liskov. Pada hakikatnya, Kereta mempunyai enjin dan boleh menghidupkan enjin tetapi basikal secara teknikalnya tidak mempunyai enjin dan oleh itu tidak boleh menghidupkan enjin. Jadi, Basikal tidak boleh mengatasi kaedah OnEngine dalam kelas Kenderaan tanpa melanggar kod.
Kami kini telah mengenal pasti bahagian kod yang melanggar prinsip penggantian Liskov. Kelas Kereta boleh mengatasi fungsi OnEngine dalam superclass dan melaksanakannya dengan cara yang membezakannya daripada kenderaan lain (seperti kapal terbang, contohnya) dan kod itu tidak akan pecah. Kelas Kereta memenuhi prinsip penggantian Liskov.
Dalam coretan kod di bawah, kami akan menggambarkan cara menstruktur kod agar mematuhi prinsip penggantian Liskov:
class Person { constructor(name, age, height, country){ this.name = name this.age = age this.height = height this.country = country } getPersonCountry(){ console.log(this.country) } greetPerson(){ console.log("Hi " + this.name) } static calculateAge(dob) { const today = new Date(); const birthDate = new Date(dob); let age = today.getFullYear() - birthDate.getFullYear(); const monthDiff = today.getMonth() - birthDate.getMonth(); if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { age--; } return age; } }
Berikut ialah contoh asas kelas Kenderaan dengan fungsi umum, bergerak. Ia adalah kepercayaan umum bahawa semua kenderaan bergerak; mereka hanya bergerak melalui mekanisme yang berbeza. Salah satu cara kita akan menggambarkan LSP adalah untuk mengatasi kaedah move() dan melaksanakannya dengan cara yang menggambarkan cara kenderaan tertentu, contohnya, Kereta akan bergerak.
Untuk berbuat demikian, kami akan mencipta kelas Kereta yang memanjangkan kelas Kenderaan dan mengatasi kaedah pergerakan agar sesuai dengan pergerakan kereta, seperti:
class Person { constructor(name, dateOfBirth, height, country){ this.name = name this.dateOfBirth = dateOfBirth this.height = height this.country = country } } class PersonUtils { static calculateAge(dob) { const today = new Date(); const birthDate = new Date(dob); let age = today.getFullYear() - birthDate.getFullYear(); const monthDiff = today.getMonth() - birthDate.getMonth(); if(monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { age--; } return age; } } const person = new Person("John", new Date(1994, 11, 23), "6ft", "USA"); console.log("Age: " + PersonUtils.calculateAge(person.dateOfBirth)); class PersonService { getPersonCountry(){ console.log(this.country) } greetPerson(){ console.log("Hi " + this.name) } }
Kami masih boleh melaksanakan kaedah pergerakan dalam kelas sub-kenderaan lain—contohnya—kapal terbang.
Begini cara kami melakukannya:
class Rectangle { constructor(width, height) { this.width = width; this.height = height; } area() { return this.width * this.height; } } class ShapeProcessor { calculateArea(shape) { if (shape instanceof Rectangle) { return shape.area(); } } } const rectangle = new Rectangle(10, 20); const shapeProcessor = new ShapeProcessor(); console.log(shapeProcessor.calculateArea(rectangle));
Dalam dua contoh di atas, kami menggambarkan konsep utama seperti warisan dan kaedah mengatasi.
N.B: Ciri pengaturcaraan yang membenarkan subkelas melaksanakan kaedah yang telah ditakrifkan dalam kelas induk dipanggil kaedah mengatasi.
Mari lakukan pengemasan dan susun semuanya, seperti:
class Shape { area() { console.log("Override method area in subclass"); } } class Rectangle extends Shape { constructor(width, height) { super(); this.width = width; this.height = height; } area() { return this.width * this.height; } } class Circle extends Shape { constructor(radius) { super(); this.radius = radius; } area() { return Math.PI * this.radius * this.radius; } } class ShapeProcessor { calculateArea(shape) { return shape.area(); } } const rectangle = new Rectangle(20, 10); const circle = new Circle(2); const shapeProcessor = new ShapeProcessor(); console.log(shapeProcessor.calculateArea(rectangle)); console.log(shapeProcessor.calculateArea(circle));
Kini, kami mempunyai 2 subkelas yang mewarisi dan mengatasi satu fungsi daripada kelas induk dan melaksanakannya mengikut keperluan mereka. Pelaksanaan baharu ini tidak melanggar kod.
Prinsip pengasingan antara muka menyatakan bahawa tiada pelanggan harus dipaksa untuk bergantung pada antara muka yang tidak digunakannya. Ia mahu kami mencipta antara muka yang lebih kecil dan lebih khusus yang berkaitan dengan pelanggan tertentu, dan bukannya mempunyai antara muka monolitik yang besar yang memaksa pelanggan melaksanakan kaedah yang mereka tidak perlukan.
Memastikan antara muka kami padat menjadikan asas kod lebih mudah untuk dinyahpepijat, diselenggara, diuji dan dilanjutkan. Tanpa ISP, perubahan dalam satu bahagian antara muka yang besar boleh memaksa perubahan pada bahagian pangkalan kod yang tidak berkaitan, menyebabkan kami menjalankan pemfaktoran semula kod yang dalam kebanyakan kes bergantung pada saiz pangkalan kod boleh menjadi tugas yang sukar.
JavaScript, tidak seperti bahasa pengaturcaraan berasaskan C seperti Java, tidak mempunyai sokongan terbina dalam untuk antara muka. Walau bagaimanapun, terdapat teknik yang antara muka dilaksanakan dalam JavaScript.
Antara muka ialah satu set tandatangan kaedah yang mesti dilaksanakan oleh kelas.
Dalam JavaScript, anda mentakrifkan antara muka sebagai objek dengan nama kaedah dan tandatangan fungsi, seperti:
class Person { constructor(name, age, height, country){ this.name = name this.age = age this.height = height this.country = country } getPersonCountry(){ console.log(this.country) } greetPerson(){ console.log("Hi " + this.name) } static calculateAge(dob) { const today = new Date(); const birthDate = new Date(dob); let age = today.getFullYear() - birthDate.getFullYear(); const monthDiff = today.getMonth() - birthDate.getMonth(); if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { age--; } return age; } }
Untuk melaksanakan antara muka dalam JavaScript, cipta kelas dan pastikan ia mengandungi kaedah dengan nama dan tandatangan yang sama yang dinyatakan dalam antara muka:
class Person { constructor(name, dateOfBirth, height, country){ this.name = name this.dateOfBirth = dateOfBirth this.height = height this.country = country } } class PersonUtils { static calculateAge(dob) { const today = new Date(); const birthDate = new Date(dob); let age = today.getFullYear() - birthDate.getFullYear(); const monthDiff = today.getMonth() - birthDate.getMonth(); if(monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { age--; } return age; } } const person = new Person("John", new Date(1994, 11, 23), "6ft", "USA"); console.log("Age: " + PersonUtils.calculateAge(person.dateOfBirth)); class PersonService { getPersonCountry(){ console.log(this.country) } greetPerson(){ console.log("Hi " + this.name) } }
Sekarang kami telah mengetahui cara membuat dan menggunakan antara muka dalam JavaScript. Perkara seterusnya yang perlu kita lakukan ialah menggambarkan cara mengasingkan antara muka dalam JavaScript supaya kita dapat melihat bagaimana semuanya sesuai dan menjadikan kod lebih mudah untuk diselenggara.
Dalam contoh berikut, kami akan menggunakan pencetak untuk menggambarkan prinsip pengasingan antara muka.
Dengan mengandaikan kita mempunyai pencetak, pengimbas dan faks, mari buat antara muka yang mentakrifkan fungsi objek ini:
class Rectangle { constructor(width, height) { this.width = width; this.height = height; } area() { return this.width * this.height; } } class ShapeProcessor { calculateArea(shape) { if (shape instanceof Rectangle) { return shape.area(); } } } const rectangle = new Rectangle(10, 20); const shapeProcessor = new ShapeProcessor(); console.log(shapeProcessor.calculateArea(rectangle));
Dalam kod di atas, kami mencipta senarai antara muka yang diasingkan atau diasingkan daripada mempunyai satu antara muka besar yang mentakrifkan semua fungsi ini. Dengan memecahkan fungsi ini kepada bit yang lebih kecil dan antara muka yang lebih khusus, kami membenarkan pelanggan yang berbeza untuk melaksanakan hanya kaedah yang mereka perlukan dan mengekalkan semua bit lain.
Dalam langkah seterusnya, kami akan mencipta kelas yang melaksanakan antara muka ini. Mengikut prinsip pengasingan antara muka, setiap kelas hanya akan melaksanakan kaedah yang diperlukan.
Jika kita ingin melaksanakan pencetak asas yang hanya boleh mencetak dokumen, kita hanya boleh melaksanakan kaedah print() melalui printerInterface, seperti:
class Shape { area() { console.log("Override method area in subclass"); } } class Rectangle extends Shape { constructor(width, height) { super(); this.width = width; this.height = height; } area() { return this.width * this.height; } } class Circle extends Shape { constructor(radius) { super(); this.radius = radius; } area() { return Math.PI * this.radius * this.radius; } } class ShapeProcessor { calculateArea(shape) { return shape.area(); } } const rectangle = new Rectangle(20, 10); const circle = new Circle(2); const shapeProcessor = new ShapeProcessor(); console.log(shapeProcessor.calculateArea(rectangle)); console.log(shapeProcessor.calculateArea(circle));
Kelas ini hanya melaksanakan PrinterInterface. Ia tidak melaksanakan kaedah imbasan atau faks. Dengan mengikut prinsip pengasingan antara muka, pelanggan — dalam kes ini, kelas Pencetak — telah mengurangkan kerumitannya dan meningkatkan prestasi perisian.
Sekarang untuk prinsip terakhir kami: prinsip penyongsangan kebergantungan. Prinsip ini mengatakan bahawa modul peringkat tinggi (logik perniagaan) harus bergantung pada abstraksi dan bukannya bergantung secara langsung pada modul peringkat rendah (konkrit). Ia membantu kami mengurangkan kebergantungan kod dan menawarkan fleksibiliti pembangun untuk mengubah suai dan mengembangkan aplikasi pada tahap yang lebih tinggi tanpa menghadapi komplikasi.
Mengapakah prinsip penyongsangan kebergantungan mengutamakan pengabstrakan berbanding kebergantungan langsung? Ini kerana pengenalan abstraksi mengurangkan potensi kesan perubahan, meningkatkan kebolehujian (mengejek abstraksi dan bukannya pelaksanaan konkrit) dan mencapai tahap fleksibiliti yang lebih tinggi dalam kod anda. Peraturan ini memudahkan untuk melanjutkan komponen perisian melalui pendekatan modular dan juga membantu kami mengubah suai komponen peringkat rendah tanpa menjejaskan logik peringkat tinggi.
Mematuhi DIP menjadikan kod lebih mudah untuk diselenggara, dilanjutkan dan skala, dengan itu menghentikan pepijat yang mungkin berlaku kerana perubahan dalam kod. Ia mengesyorkan agar pembangun menggunakan gandingan longgar dan bukannya gandingan ketat antara kelas. Secara amnya, dengan mengamalkan pemikiran yang mengutamakan abstraksi berbanding kebergantungan langsung, pasukan akan memperoleh ketangkasan untuk menyesuaikan diri dan menambah fungsi baharu atau menukar komponen lama tanpa menyebabkan gangguan riak. Dalam JavaScript, kami dapat melaksanakan DIP menggunakan pendekatan suntikan kebergantungan, seperti:
class Person { constructor(name, age, height, country){ this.name = name this.age = age this.height = height this.country = country } getPersonCountry(){ console.log(this.country) } greetPerson(){ console.log("Hi " + this.name) } static calculateAge(dob) { const today = new Date(); const birthDate = new Date(dob); let age = today.getFullYear() - birthDate.getFullYear(); const monthDiff = today.getMonth() - birthDate.getMonth(); if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { age--; } return age; } }
Dalam contoh asas di atas, kelas Aplikasi ialah modul peringkat tinggi yang bergantung pada abstraksi pangkalan data. Kami mencipta dua kelas pangkalan data: MySQLDatabase, dan MongoDBDatabase. Pangkalan data ialah modul peringkat rendah dan kejadiannya disuntik ke dalam masa jalan Aplikasi tanpa mengubah suai Aplikasi itu sendiri.
Prinsip SOLID ialah blok binaan asas untuk reka bentuk perisian berskala, boleh diselenggara dan teguh. Set prinsip ini membantu pembangun menulis kod yang bersih, modular dan boleh disesuaikan.
Prinsip SOLID menggalakkan kefungsian padu, kebolehlanjutan tanpa pengubahsuaian, penggantian objek, pemisahan antara muka dan pengabstrakan ke atas kebergantungan konkrit. Pastikan anda menyepadukan prinsip SOLID ke dalam kod anda untuk mengelakkan pepijat mendapat semua faedahnya.
Kod nyahpepijat sentiasa menjadi tugas yang membosankan. Tetapi semakin anda memahami kesilapan anda, semakin mudah untuk membetulkannya.
LogRocket membolehkan anda memahami ralat ini dengan cara baharu dan unik. Penyelesaian pemantauan bahagian hadapan kami menjejaki penglibatan pengguna dengan bahagian hadapan JavaScript anda untuk memberi anda keupayaan untuk melihat dengan tepat perkara yang dilakukan pengguna yang membawa kepada ralat.
LogRocket merekodkan log konsol, masa muat halaman, surih tindanan, permintaan/tindak balas rangkaian perlahan dengan badan pengepala, metadata penyemak imbas dan log tersuai. Memahami kesan kod JavaScript anda tidak akan menjadi lebih mudah!
Cuba secara percuma.
Atas ialah kandungan terperinci Prinsip SOLID untuk JavaScript. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!