Node.js - penggunaan module.exports sebagai konstruktor


120

Menurut manual Node.js:

Jika Anda ingin root dari ekspor modul Anda menjadi sebuah fungsi (seperti konstruktor) atau jika Anda ingin mengekspor objek lengkap dalam satu tugas alih-alih membangunnya satu properti pada satu waktu, tetapkan ke module.exports daripada ekspor .

Contoh yang diberikan adalah:

// file: square.js
module.exports = function(width) {
  return {
    area: function() {
      return width * width;
    }
  };
}

dan digunakan seperti ini:

var square = require('./square.js');
var mySquare = square(2);
console.log('The area of my square is ' + mySquare.area());

Pertanyaan saya: mengapa contoh tersebut tidak menggunakan persegi sebagai objek? Apakah hal berikut ini valid dan membuat contoh lebih "berorientasi objek"?

var Square = require('./square.js');
var mySquare = new Square(2);
console.log('The area of my square is ' + mySquare.area());

1
Contoh Anda adalah kesalahan sintaksis. Setelah mengubah nama squareuntuk Squareyang new square()tidak ada lagi.
Sukima

3
Maaf, itu salah ketik. Diperbaiki. Maksud saya adalah untuk menunjukkan nama Objek / Fungsi dimulai dengan huruf besar dan nama contoh dimulai dengan huruf kecil.
Naresh

4
Saya pikir sebanyak itu, Itulah mengapa saya menulis jawaban saya seperti yang saya lakukan. Saya hanya ingin mengatakan bahwa saya sangat senang orang lain melihat modul dengan cara yang sama. Saya sering menggunakan kata kunci baru dan mengatur modul saya untuk mengekspor fungsi konstruktor tunggal. Saya merasa itu membuat pembacaan dan konseptualisasi solusi lebih mudah. Saya dapat mengetahui sekilas jenis konstruksi apa yang ingin saya gunakan. Kudos karena berpikir seperti saya;)
Sukima

Jawaban:


173

Modul CommonJS memungkinkan dua cara untuk menentukan properti yang diekspor. Dalam kedua kasus Anda mengembalikan Objek / Fungsi. Karena fungsi adalah warga kelas pertama dalam JavaScript, mereka dapat bertindak seperti Objek (secara teknis mereka adalah Objek). Oleh karena itu, pertanyaan Anda tentang penggunaan newkata kunci memiliki jawaban yang sederhana: Ya. Saya akan menggambarkan ...

Ekspor modul

Anda dapat menggunakan exportsvariabel yang disediakan untuk melampirkan properti padanya. Setelah diperlukan dalam modul lain, properti yang ditetapkan tersebut menjadi tersedia. Atau Anda dapat menetapkan objek ke properti module.exports. Dalam kedua kasus, apa yang dikembalikan oleh require()adalah referensi ke nilai module.exports.

Contoh pseudo-code tentang bagaimana modul didefinisikan:

var theModule = {
  exports: {}
};

(function(module, exports, require) {

  // Your module code goes here

})(theModule, theModule.exports, theRequireFunction);

Pada contoh di atas module.exportsdan exportsmerupakan objek yang sama. Bagian yang keren adalah Anda tidak melihat semua itu di modul CommonJS Anda karena seluruh sistem mengurusnya untuk Anda semua yang perlu Anda ketahui adalah ada objek modul dengan properti ekspor dan variabel ekspor yang menunjuk ke hal yang sama yang dilakukan module.exports.

Wajibkan dengan konstruktor

Karena Anda dapat melampirkan fungsi secara langsung, module.exportsAnda pada dasarnya dapat mengembalikan fungsi dan seperti fungsi lainnya, fungsi tersebut dapat dikelola sebagai konstruktor (Itu dicetak miring karena satu-satunya perbedaan antara fungsi dan konstruktor dalam JavaScript adalah cara Anda menggunakannya. Secara teknis tidak ada perbedaan.)

Jadi berikut ini adalah kode yang sangat bagus dan saya pribadi mendorongnya:

// My module
function MyObject(bar) {
  this.bar = bar;
}

MyObject.prototype.foo = function foo() {
  console.log(this.bar);
};

module.exports = MyObject;

// In another module:
var MyObjectOrSomeCleverName = require("./my_object.js");
var my_obj_instance = new MyObjectOrSomeCleverName("foobar");
my_obj_instance.foo(); // => "foobar"

Wajibkan untuk non-konstruktor

Hal yang sama berlaku untuk fungsi seperti non-konstruktor:

// My Module
exports.someFunction = function someFunction(msg) {
  console.log(msg);
}

// In another module
var MyModule = require("./my_module.js");
MyModule.someFunction("foobar"); // => "foobar"

2
Bisakah saya disingkat mensyaratkan ('./ my-object.js') ("foobar")? Atau apakah sintaks require ('module') (params) untuk kasus penggunaan yang berbeda?
Hampus Ahlgren

1
Tidak ada yang menghentikan Anda, Itu semua hanya JavaScript. Jadi ya, Anda bisa menggunakan sintaks yang lebih pendek.
Sukima

3
Contoh pseudo-code tentang bagaimana modul didefinisikan telah sepenuhnya membersihkan pemahaman saya tentang sistem modul Node.js. Terima kasih!
Nitax

130

Menurut saya, beberapa contoh node.js cukup dibuat-buat.

Anda mungkin berharap melihat sesuatu yang lebih seperti ini di dunia nyata

// square.js
function Square(width) {

  if (!(this instanceof Square)) {
    return new Square(width);
  }

  this.width = width;
};

Square.prototype.area = function area() {
  return Math.pow(this.width, 2);
};

module.exports = Square;

Pemakaian

var Square = require("./square");

// you can use `new` keyword
var s = new Square(5);
s.area(); // 25

// or you can skip it!
var s2 = Square(10);
s2.area(); // 100

Untuk orang ES6

class Square {
  constructor(width) {
    this.width = width;
  }
  area() {
    return Math.pow(this.width, 2);
  }
}

export default Square;

Menggunakannya di ES6

import Square from "./square";
// ...

Saat menggunakan kelas, Anda harus menggunakan newkata kunci untuk membuat instatiate itu. Yang lainnya tetap sama.


3
Struktur yang sangat ringkas!
Christophe Marois

1
Jadi sepertinya dalam contoh <ES6 Anda, tidak ada perbedaan antara menggunakan newdan tidak menggunakannya. Tapi, apakah itu hanya karena Anda memiliki cek itu this instanceof square? Jika demikian, apa sebenarnya yang dilakukan mekanisme itu?
arichards

1
Pertanyaan yang saya miliki dan cari, seandainya bermanfaat bagi orang lain: Di mana importdan exportdidefinisikan? Ini adalah kata kunci yang dipesan di ECMAScript 6 (ES6). Sebelum ES6, seseorang harus menggunakan perpustakaan untuk mengelola modul. Modulasi node dimodelkan setelah Modul perpustakaan CommonJS. Apa defaultdi export default Square? Ini menentukan apa yang akan diimpor ketika Anda hanya mengimpor 'file' dan bukan ekspor spesifik lainnya dari file itu. Selama mereka ada, saya menemukan halaman-halaman ini membantu: spring.io/understanding/javascript-modules dan exploringjs.com/es6/ch_modules.html
arichards

1

Pertanyaan ini sebenarnya tidak ada hubungannya dengan cara require()kerjanya. Pada dasarnya, apa pun yang Anda atur module.exportsdalam modul Anda akan dikembalikan dari require()panggilan untuk itu.

Ini akan sama dengan:

var square = function(width) {
  return {
    area: function() {
      return width * width;
    }
  };
}

Tidak perlu newkata kunci saat menelepon square. Anda tidak mengembalikan instance fungsi itu sendiri square, Anda mengembalikan objek baru di akhir. Oleh karena itu, Anda cukup memanggil fungsi ini secara langsung.

Untuk argumen yang lebih rumit new, lihat ini: Apakah kata kunci "baru" JavaScript dianggap berbahaya?


3
Tidak ada yang salah dengan menggunakan kata kunci baru. Saya benci semua FUD di sekitarnya.
Sukima

1
@Sukima Setuju. :-D Saya menunjukkan mengapa itu tidak penting dalam kasus ini, dan terkait dengan pertanyaan lain tentang newagar orang lain dapat berpartisipasi dalam perang di sana.
Brad

0

Kode contohnya adalah:

di main

square(width,function (data)
{
   console.log(data.squareVal);
});

menggunakan berikut ini mungkin berhasil

exports.square = function(width,callback)
{
     var aa = new Object();
     callback(aa.squareVal = width * width);    
}

0

Pada akhirnya, Node adalah tentang Javascript. JS memiliki beberapa cara untuk menyelesaikan sesuatu, hal yang sama untuk mendapatkan "konstruktor", yang penting adalah mengembalikan suatu fungsi .

Dengan cara ini sebenarnya Anda membuat fungsi baru, seperti yang kami buat menggunakan JS di lingkungan Web Browser misalnya.

Secara pribadi saya lebih suka pendekatan prototipe, seperti yang disarankan Sukima di posting ini: Node.js - penggunaan module.exports sebagai konstruktor

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.