Apakah kata kunci "baru" JavaScript dianggap berbahaya? [Tutup]

568

Dalam pertanyaan lain , pengguna menunjukkan bahwa newkata kunci berbahaya untuk digunakan dan mengusulkan solusi untuk pembuatan objek yang tidak digunakan new. Saya tidak percaya itu benar, sebagian besar karena saya telah menggunakan Prototipe, Scriptaculous dan pustaka JavaScript yang sangat baik lainnya, dan semua orang dari mereka menggunakan newkata kunci.

Terlepas dari itu, kemarin saya menonton pembicaraan Douglas Crockford di teater YUI dan dia mengatakan hal yang persis sama, bahwa dia tidak menggunakan newkata kunci lagi dalam kodenya ( Crockford pada JavaScript - Act III: Function the Ultimate - 50:23 menit ).

Apakah 'buruk' menggunakan newkata kunci? Apa kelebihan dan kekurangan dari menggunakannya?

Pablo Fernandez
sumber
90
BUKAN 'buruk' untuk menggunakan kata kunci baru. Tetapi jika Anda melupakannya, Anda akan memanggil konstruktor objek sebagai fungsi biasa. Jika konstruktor Anda tidak memeriksa konteks pelaksanaannya maka ia tidak akan melihat bahwa 'ini' menunjuk ke objek yang berbeda (biasanya objek global) alih-alih instance baru. Karenanya konstruktor Anda akan menambahkan properti dan metode ke objek global (jendela). Jika Anda selalu memeriksa bahwa 'ini' adalah instance dari objek Anda di fungsi objek, maka Anda tidak akan pernah memiliki masalah ini.
Kristian B
5
Saya tidak mengerti ini. Di satu sisi doug mengecilkan penggunaan new. Tetapi ketika Anda melihat perpustakaan YUI. Anda harus menggunakannya di newmana-mana. Seperti var myDataSource = new Y.DataSource.IO({source:"./myScript.php"}); .
aditya_gaur
2
@aditya_gaur Itu karena jika Anda memerlukan inisialisasi objek, Anda harus meretas initmetode jika Anda menggunakan Object.creatependekatan dan memanggilnya setelah itu. Jauh lebih mudah untuk hanya menggunakan newkeduanya, mengatur rantai prototipe dan memanggil beberapa kode penginisialisasi.
Juan Mendes
67
Saya tidak berpikir ini harus ditutup. Ya, itu kemungkinan akan menginspirasi beberapa racun anti-kipas Crockford tetapi kita berbicara tentang saran populer untuk pada dasarnya menghindari fitur bahasa utama di sini. Mekanisme yang membuat setiap objek JQuery hampir tidak ada artinya (jika menyangkut memori) melibatkan penggunaan kata kunci 'baru'. Pilih metode pabrik untuk terus-menerus menerapkan yang baru, tetapi jangan secara drastis mengurangi opsi arsitektural dan kinerja Anda dengan hanya menggunakan objek literal. Mereka memiliki tempat mereka dan konstruktor memiliki tempat mereka. Ini adalah saran yang mudah dan usang.
Erik Reppen
2
TLDR: Menggunakan newtidak berbahaya. Menghilangkan newitu berbahaya, dan karena itu buruk . Tetapi dalam ES5 Anda dapat menggunakan Mode Ketat , yang melindungi Anda dari bahaya itu dan banyak lainnya.
jkdev

Jawaban:

603

Crockford telah melakukan banyak hal untuk mempopulerkan teknik JavaScript yang baik. Pendiriannya yang tegas tentang unsur-unsur utama bahasa telah memicu banyak diskusi bermanfaat. Yang mengatakan, ada terlalu banyak orang yang menganggap setiap proklamasi "buruk" atau "berbahaya" sebagai Injil, menolak untuk melihat melampaui pendapat satu orang. Kadang-kadang bisa sedikit frustasi.

Penggunaan fungsi yang disediakan oleh newkata kunci memiliki beberapa keunggulan dibandingkan membangun setiap objek dari awal:

  1. Warisan prototipe . Meskipun sering dipandang dengan campuran kecurigaan dan cemoohan oleh mereka yang terbiasa dengan bahasa OO berbasis kelas, teknik pewarisan asli JavaScript adalah cara sederhana dan mengejutkan yang efektif untuk menggunakan kembali kode. Dan kata kunci baru adalah sarana kanonik (dan hanya lintas platform yang tersedia) untuk menggunakannya.
  2. Performa. Ini adalah efek samping dari # 1: jika saya ingin menambahkan 10 metode ke setiap objek yang saya buat, saya hanya bisa menulis fungsi pembuatan yang secara manual menetapkan setiap metode ke setiap objek baru ... Atau, saya bisa menetapkannya ke fungsi penciptaan prototypedan digunakan newuntuk membasmi objek baru. Tidak hanya ini lebih cepat (tidak ada kode yang diperlukan untuk masing-masing dan setiap metode pada prototipe), itu menghindari membengkak setiap objek dengan properti terpisah untuk setiap metode. Pada mesin yang lebih lambat (atau terutama, lebih lambat JS interpreter) ketika banyak objek sedang dibuat ini dapat berarti penghematan yang signifikan dalam waktu dan memori.

Dan ya, newmemiliki satu kelemahan penting, dengan cakap dijelaskan oleh jawaban lain: jika Anda lupa menggunakannya, kode Anda akan rusak tanpa peringatan. Untungnya, kerugian itu mudah dikurangi - cukup tambahkan sedikit kode ke fungsi itu sendiri:

function foo()
{
   // if user accidentally omits the new keyword, this will 
   // silently correct the problem...
   if ( !(this instanceof foo) )
      return new foo();

   // constructor logic follows...
}

Sekarang Anda dapat memiliki keuntungan newtanpa harus khawatir tentang masalah yang disebabkan oleh penyalahgunaan yang tidak disengaja. Anda bahkan bisa menambahkan pernyataan ke cek jika pikiran kode yang rusak diam-diam mengganggu Anda. Atau, seperti dikomentari beberapa orang , gunakan tanda centang untuk memperkenalkan pengecualian runtime:

if ( !(this instanceof arguments.callee) ) 
   throw new Error("Constructor called as a function");

(Perhatikan bahwa cuplikan ini dapat menghindari pengkodean nama fungsi konstruktor, karena tidak seperti contoh sebelumnya ia tidak perlu benar-benar instantiate objek - oleh karena itu, ia dapat disalin ke setiap fungsi target tanpa modifikasi.)

John Resig merinci teknik ini di pos Instansiasi "Kelas" -nya yang Sederhana , serta memasukkan cara untuk membangun perilaku ini ke dalam "kelas" Anda secara default. Pasti layak dibaca ... seperti buku terbarunya, Rahasia Ninja JavaScript , yang menemukan tersembunyi emas dalam hal ini dan banyak lainnya "berbahaya" fitur bahasa JavaScript (yang bab tentang withterutama mencerahkan bagi kita yang awalnya diberhentikan fitur yang banyak difitnah ini sebagai gimmick).

Shog9
sumber
96
if (! (instanceof arguments.callee)) ini melempar Error ("Konstruktor disebut sebagai fungsi"); // Lebih umum, tidak memerlukan pengetahuan tentang nama konstruktor, buat pengguna memperbaiki kode.
Beberapa
5
Jika Anda khawatir tentang kinerja - dan sebenarnya memiliki alasan untuk itu - maka jangan lakukan pemeriksaan sama sekali. Ingatlah untuk menggunakan new, atau gunakan fungsi pembungkus untuk mengingatnya untuk Anda. Saya menduga bahwa jika Anda berada pada titik di mana itu penting, Anda sudah kehabisan optimasi lainnya seperti memoisasi, jadi panggilan kreasi Anda akan dilokalkan ...
Shog9
65
Menggunakan arguments.calleeuntuk memeriksa apakah Anda telah dipanggil dengan newmungkin tidak begitu baik, karena arguments.calleetidak tersedia dalam mode ketat. Lebih baik menggunakan nama fungsi.
Sean McMillan
69
Jika saya salah mengeja pengenal, kode saya rusak. Haruskah saya tidak menggunakan pengidentifikasi? Tidak menggunakan newkarena Anda bisa lupa menuliskannya dalam kode Anda sama konyolnya dengan contoh saya.
Thomas Eding
16
Jika Anda mengaktifkan mode ketat, jika Anda lupa menggunakan yang baru, Anda akan mendapatkan pengecualian ketika Anda mencoba menggunakan ini: yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town Yaitu lebih mudah daripada menambahkan instance cek untuk setiap konstruktor.
stephenbez
182

Saya baru saja membaca beberapa bagian dari bukunya Crockfords "Javascript: The Good Parts". Saya merasa bahwa dia menganggap segala sesuatu yang pernah menggigitnya berbahaya:

Tentang sakelar jatuh:

Saya tidak pernah membiarkan peralihan beralih ke kasus berikutnya. Saya pernah menemukan bug dalam kode saya yang disebabkan oleh kegagalan yang tidak disengaja segera setelah membuat pidato yang giat tentang mengapa jatuh terkadang bermanfaat. (halaman 97, ISBN 978-0-596-51774-8)

Tentang ++ dan -

Operator ++ (increment) dan - (decrement) telah dikenal berkontribusi pada kode buruk dengan mendorong trickiness berlebihan. Mereka adalah yang kedua setelah arsitektur yang salah dalam mengaktifkan virus dan ancaman keamanan lainnya. (halaman 122)

Tentang baru:

Jika Anda lupa menyertakan awalan baru saat memanggil fungsi konstruktor, maka ini tidak akan terikat ke objek baru. Sayangnya, ini akan terikat pada objek global, jadi alih-alih menambah objek baru Anda, Anda akan menghancurkan variabel global. Itu sangat buruk. Tidak ada peringatan kompilasi, dan tidak ada peringatan runtime. (halaman 49)

Ada lebih banyak, tetapi saya harap Anda mendapatkan gambarannya.

Jawaban saya untuk pertanyaan Anda: Tidak, itu tidak berbahaya. tetapi jika Anda lupa menggunakannya ketika Anda harusnya Anda bisa memiliki beberapa masalah. Jika Anda berkembang di lingkungan yang baik Anda perhatikan itu.

Memperbarui

Sekitar setahun setelah jawaban ini ditulis ECMAScript edisi ke-5 dirilis, dengan dukungan untuk mode ketat . Dalam mode ketat, thistidak lagi terikat ke objek global tetapi ke undefined.

beberapa
sumber
3
Saya sangat setuju. Solusinya: Selalu dokumentasikan bagaimana pengguna harus membuat instance objek Anda. Gunakan contoh dan pengguna kemungkinan akan memotong / menempel. Ada konstruksi / fitur dalam setiap bahasa yang dapat disalahgunakan sehingga menghasilkan perilaku yang tidak biasa / tidak terduga. Itu tidak membuat mereka berbahaya.
nicerobot
45
Ada konvensi untuk selalu memulai konstruktor dengan huruf besar, dan semua fungsi lainnya dengan huruf kecil.
beberapa
61
Saya baru menyadari bahwa Crockford tidak menganggap WHILE berbahaya ... Saya tidak tahu berapa kali saya membuat loop infinitif karena saya lupa menambah variabel ...
beberapa
5
Hal yang sama berlaku untuk ++, -. Mereka mengekspresikan apa yang saya maksudkan dalam bahasa yang sejelas mungkin. Aku cinta mereka! beralih jatuh mungkin jelas bagi beberapa orang, tapi aku lelah tentang itu. Saya menggunakannya ketika mereka jelas lebih jelas ('karena permainan kata, tidak bisa menahan).
PEZ
30
Jawaban saya kepada Crockford: Pemrograman itu sulit, ayo belanja. Sheesh!
Jason Jackson
91

Javascript menjadi bahasa yang dinamis ada banyak cara untuk mengacaukan di mana bahasa lain akan menghentikan Anda.

Menghindari fitur bahasa mendasar seperti new pada dasar bahwa Anda mungkin mengacaukan adalah seperti melepas sepatu baru Anda yang mengkilap sebelum berjalan melalui ladang ranjau untuk berjaga-jaga jika Anda mungkin membuat sepatu Anda becek.

Saya menggunakan konvensi di mana nama fungsi dimulai dengan huruf kecil dan 'fungsi' yang sebenarnya definisi kelas dimulai dengan huruf besar. Hasilnya adalah petunjuk visual yang benar-benar sangat meyakinkan bahwa 'sintaks' salah: -

var o = MyClass();  // this is clearly wrong.

Selain itu, kebiasaan pemberian nama yang baik ini membantu. Setelah semua fungsi melakukan hal-hal dan oleh karena itu harus ada kata kerja dalam namanya sedangkan kelas mewakili objek dan kata benda dan kata sifat tanpa kata kerja.

var o = chair() // Executing chair is daft.
var o = createChair() // makes sense.

Sangat menarik bagaimana pewarnaan sintaks SO telah menafsirkan kode di atas.

AnthonyWJones
sumber
8
Ya, saya hanya memikirkan hal yang sama tentang pewarnaan sintaksis.
BobbyShaftoe
4
Suatu saat saya lupa mengetik kata 'fungsi'. Kata itu harus dihindari bagaimanapun caranya. Lain waktu saya tidak menggunakan kurung kurawal di pernyataan multi-baris if / then. Jadi sekarang saya tidak menggunakan kurung kurawal dan hanya menulis kondisional satu baris.
Hal50000
"Ini jelas salah" . Mengapa? Untuk kelas saya (yang hanya dilakukan if (! this instanceof MyClass) return new MyClass()) saya sebenarnya lebih suka newsintaks -less. Mengapa? Karena fungsi lebih umum daripada fungsi konstruktor . Meninggalkan newmembuatnya mudah untuk mengubah fungsi konstruktor menjadi fungsi biasa ... Atau sebaliknya. Menambahkan menambahkan newmembuat kode lebih spesifik daripada yang seharusnya. Dan karenanya kurang fleksibel. Bandingkan dengan Java yang direkomendasikan untuk menerima Listalih-alih ArrayListagar penelepon dapat memilih implementasinya.
Stijn de Witt
41

Saya pemula untuk Javascript jadi mungkin saya tidak terlalu berpengalaman dalam memberikan sudut pandang yang baik untuk ini. Namun saya ingin membagikan pandangan saya tentang hal "baru" ini.

Saya berasal dari dunia C # di mana menggunakan kata kunci "baru" begitu alami sehingga pola desain pabrik yang terlihat aneh bagi saya.

Ketika saya pertama kali kode dalam Javascript, saya tidak menyadari bahwa ada kata kunci dan kode "baru" seperti yang ada dalam pola YUI dan tidak butuh waktu lama bagi saya untuk mengalami bencana. Saya kehilangan jejak apa yang seharusnya dilakukan baris tertentu ketika melihat kembali kode yang saya tulis. Lebih kacau adalah bahwa pikiran saya tidak bisa benar-benar transit antara batas-batas instance objek ketika saya "kering-menjalankan" kode.

Kemudian, saya menemukan kata kunci "baru" yang bagi saya, itu "memisahkan" hal-hal. Dengan kata kunci baru, itu menciptakan sesuatu. Tanpa kata kunci baru, saya tahu saya tidak akan bingung dengan menciptakan sesuatu kecuali fungsi yang saya panggil memberi saya petunjuk kuat tentang itu.

Misalnya, dengan var bar=foo();saya tidak memiliki petunjuk sebagai bilah apa yang mungkin .... Apakah ini nilai balik atau apakah itu objek yang baru dibuat? Tetapi dengan var bar = new foo();saya tahu pasti bar adalah sebuah objek.

Conrad
sumber
3
Setuju, dan saya percaya pola pabrik harus mengikuti konvensi penamaan seperti makeFoo ()
pluckyglen
3
+1 - kehadiran 'baru' memberikan pernyataan niat yang lebih jelas.
belugabob
4
Respons ini agak aneh, ketika hampir semua yang ada di JS adalah objek. Mengapa Anda perlu tahu pasti bahwa suatu fungsi adalah objek ketika semua fungsi adalah objek?
Joshua Ramirez
@ JoshuaRamirez Intinya bukan itu typeof new foo() == "object". Itu yang newmengembalikan instance dari foo, dan Anda tahu Anda bisa menelepon foo.bar()dan foo.bang(). Namun itu dapat dengan mudah dikurangi dengan menggunakan JsDoc's @return Bukannya saya mengadvokasi untuk kode prosedural (menghindari kata new)
Juan Mendes
1
@JuanMendes Hmm ... Posting Anda membuat saya merasa Anda menyukai yang baru karena kata kunci eksplisit dalam basis kode Anda. Saya bisa menggali itu. Itu sebabnya saya menggunakan pola modul. Saya akan memiliki fungsi bernama createFoo atau NewFoo atau MakeFoo, tidak masalah asalkan eksplisit. Di dalam itu saya mendeklarasikan variabel yang digunakan sebagai penutup di dalam objek literal yang dikembalikan dari fungsi. Objek literal itu akhirnya menjadi objek Anda, dan fungsinya hanyalah fungsi konstruksi.
Joshua Ramirez
39

Kasus lain untuk yang baru adalah apa yang saya sebut Pooh Coding . Winnie the Pooh mengikuti perutnya. Saya katakan pergi dengan bahasa yang Anda gunakan, bukan menentangnya .

Kemungkinannya adalah pengelola bahasa akan mengoptimalkan bahasa untuk idiom yang mereka coba dorong. Jika mereka memasukkan kata kunci baru ke dalam bahasa, mereka mungkin berpikir masuk akal untuk menjelaskan ketika membuat contoh baru.

Kode yang ditulis mengikuti niat bahasa akan meningkat efisiensi dengan setiap rilis. Dan kode menghindari konstruksi utama bahasa akan menderita seiring waktu.

EDIT: Dan ini melampaui kinerja. Saya tidak dapat menghitung berapa kali saya mendengar (atau berkata) "mengapa mereka melakukan itu ?" ketika menemukan kode yang terlihat aneh. Sering kali ternyata pada saat kode itu ditulis ada alasan "bagus" untuk itu. Mengikuti Tao bahasa adalah asuransi terbaik Anda karena tidak ada kode Anda diejek beberapa tahun dari sekarang.

PEZ
sumber
3
+1 untuk tautan Pooh Coding - sekarang saya perlu mencari alasan untuk mengerjakan ini dalam percakapan saya ...
Shog9
LOL! Saya memiliki pengalaman bertahun-tahun di bidang itu dan saya dapat meyakinkan Anda bahwa Anda tidak akan menemukan kesulitan. Mereka sering memanggil saya Pooh di robowiki.net. =)
PEZ
1
Tidak tahu apakah Anda akan melihat komentar ini, tetapi tautan Pooh Coding sudah mati.
Calvin
Terimakasih atas peringatannya. Kami memigrasi robowiki.net ke wiki baru minggu lalu dan konten lama tidak dapat dijangkau saat ini. Saya akan cepat-cepat membuat tautan lama itu berfungsi.
PEZ
24

Saya menulis posting tentang cara mengurangi masalah memanggil konstruktor tanpa kata kunci baru.
Sebagian besar didaktik, tetapi ini menunjukkan bagaimana Anda dapat membuat konstruktor yang bekerja dengan atau tanpa newdan tidak mengharuskan Anda menambahkan kode boilerplate untuk diuji thisdi setiap konstruktor.

http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html

Inilah inti dari teknik ini:

/**
 * Wraps the passed in constructor so it works with
 * or without the new keyword
 * @param {Function} realCtor The constructor function.
 *    Note that this is going to be wrapped
 *    and should not be used directly 
 */
function ctor(realCtor){
  // This is going to be the actual constructor
  return function wrapperCtor(){
    var obj; // object that will be created
    if (this instanceof wrapperCtor) {
      // Called with new
      obj = this;
    } else {
      // Called without new. Create an empty object of the
      // correct type without running that constructor
      surrogateCtor.prototype = wrapperCtor.prototype;
      obj = new surrogateCtor();
    }
    // Call the real constructor function
    realCtor.apply(obj, arguments);
    return obj;
  }

  function surrogateCtor() {}
}

Berikut cara menggunakannya:

// Create our point constructor
Point = ctor(function(x,y){
  this.x = x;
  this.y = y;
});

// This is good
var pt = new Point(20,30);
// This is OK also
var pt2 = Point(20,30);
Juan Mendes
sumber
6
menghindarinya arguments.calleeluar biasa!
Gregg Lind
2
surrogateConstructorseharusnya surrogateCtor(atau sebaliknya).
David Conrad
Saya memelihara koleksi utilitas serupa yang terinspirasi Crockford, dan mendapati bahwa saya selalu berlari untuk menemukan implementasinya ketika saya memulai proyek baru. Dan ini membungkus bagian mendasar dari pemrograman: objek objek. Semua ini berfungsi, hanya untuk mengaktifkan kode instantiasi yang serampangan? Saya menghargai kecerdikan pembungkus ini, jujur, tapi sepertinya memunculkan kode yang ceroboh.
Joe Coder
1
@ Joecoder Saya memang menyebutkan ini untuk tujuan didaktik saja, saya tidak berlangganan gaya pengkodean paranoia ini. Namun, jika saya sedang menulis perpustakaan kelas, maka ya saya akan menambahkan fitur ini dengan cara yang transparan untuk penelepon
Juan Mendes
22

Alasan di balik tidak menggunakan kata kunci baru, sederhana:

Dengan tidak menggunakannya sama sekali, Anda menghindari jebakan yang datang dengan menghilangkannya secara tidak sengaja. Pola konstruksi yang digunakan YUI, adalah contoh bagaimana Anda dapat menghindari kata kunci baru sama sekali "

var foo = function () {
    var pub= { };
    return pub;
}
var bar = foo();

Atau Anda bisa melakukannya:

function foo() { }
var bar = new foo();

Tapi dengan demikian Anda menjalankan risiko seseorang lupa untuk menggunakan baru kata kunci, dan ini operator yang menjadi semua fubar. AFAIK tidak ada untungnya melakukan ini (selain Anda sudah terbiasa).

Pada Akhir Hari: Ini tentang bersikap defensif. Bisakah Anda menggunakan pernyataan baru? Iya. Apakah itu membuat kode Anda lebih berbahaya? Iya.

Jika Anda pernah menulis C ++, ini mirip dengan mengatur pointer ke NULL setelah Anda menghapusnya.

Greg Dean
sumber
6
Tidak. Dengan "new foo ()" beberapa properti diatur pada objek yang dikembalikan, seperti konstruktor.
beberapa
34
Jadi, hanya untuk memperjelas ini: Anda tidak harus menggunakan "baru" karena Anda mungkin melupakannya? Anda bercanda, kan?
Bombe
16
@Bombe: dalam bahasa lain melupakan "baru" akan menghasilkan kesalahan. Dalam Javascript, itu hanya terus mengirim truk. Anda bisa lupa, dan tidak pernah sadar. Dan hanya melihat kode erroroneous tidak akan jelas sama sekali apa yang salah.
Kent Fredric
3
@ Greg: Saya tidak melihat bagaimana teknik pertama memungkinkan untuk menggunakan rantai prototipe - objek literal sangat bagus, tetapi membuang kinerja dan keuntungan lain yang disediakan oleh prototipe karena takut tampaknya agak konyol.
Shog9
5
@Bombe - Anda harus menggunakan "baru" karena Anda (dan siapa pun yang menggunakan kode Anda) tidak akan pernah melakukan kesalahan? Anda bercanda, kan?
Greg Dean
20

Saya pikir "baru" menambah kejelasan kode. Dan kejelasan itu layak untuk semuanya. Senang mengetahui ada jebakan, tetapi menghindarinya dengan menghindari kejelasan sepertinya bukan jalan bagi saya.

PEZ
sumber
16

Kasus 1: newtidak diperlukan dan harus dihindari

var str = new String('asd');  // type: object
var str = String('asd');      // type: string

var num = new Number(12);     // type: object
var num = Number(12);         // type: number

Wadah 2: newwajib diisi, jika tidak Anda akan mendapatkan kesalahan

new Date().getFullYear();     // correct, returns the current year, i.e. 2010
Date().getFullYear();         // invalid, returns an error
nyuszika7h
sumber
5
Perlu dicatat bahwa dalam kasus 1, memanggil konstruktor sebagai fungsi hanya masuk akal jika Anda bermaksud konversi tipe (dan tidak tahu apakah objek lambung memiliki metode konversi, seperti toString()). Dalam semua kasus lain, gunakan literal. Bukan String('asd') , tapi sederhana 'asd', dan tidak Number(12) , tapi sederhana 12.
PointedEars
1
@PointedEars Satu pengecualian untuk aturan ini adalah Array: Array(5).fill(0) jelas lebih mudah dibaca daripada [undefined, undefined, undefined, undefined, undefined].fill(0)dan(var arr = []).length = 5; arr.fill(0);
yyny
@YoYoYonnY Pernyataan saya dibuat dalam konteks kasus 1 dari jawaban, yang mengacu pada penggunaan newdengan konstruktor untuk tipe objek yang sesuai dengan tipe primitif . Literal yang Anda sarankan tidak setara dengan Arraypanggilan (coba 0 in …), dan sisanya adalah kesalahan sintaks :) Kalau tidak Anda benar, meskipun harus dicatat juga yang Array(5)bisa ambigu jika Anda mempertimbangkan implementasi yang tidak sesuai (dan karena itu ditiru Array.prototype.fill(…) ).
PointedEars
12

Berikut ini ringkasan singkat yang bisa saya sampaikan dari dua argumen terkuat untuk dan menentang penggunaan newoperator:

Argumen menentang new

  1. Fungsi yang dirancang untuk dipakai sebagai objek menggunakan newoperator dapat memiliki efek bencana jika mereka salah dipanggil sebagai fungsi normal. Kode fungsi dalam kasus seperti itu akan dieksekusi dalam lingkup tempat fungsi dipanggil, alih-alih dalam lingkup objek lokal sebagaimana dimaksud. Ini dapat menyebabkan variabel dan properti global ditimpa dengan konsekuensi yang merusak.
  2. Akhirnya, menulis function Func(), dan kemudian memanggil Func.prototype dan menambahkan barang-barang ke dalamnya sehingga Anda dapat menelepon new Func()untuk membangun objek Anda tampak jelek bagi beberapa programmer, yang lebih suka menggunakan gaya objek pewarisan lain untuk alasan arsitektur dan gaya.

Untuk lebih lanjut tentang argumen ini, lihat buku Douglas Crockford yang hebat dan ringkas Javascript: The Good Parts. Bahkan periksa saja.

Argumen yang mendukung new

  1. Menggunakan newoperator dan penugasan prototypal cepat.
  2. Hal-hal tentang tidak sengaja menjalankan kode fungsi konstruktor di namespace global dapat dengan mudah dicegah jika Anda selalu menyertakan sedikit kode dalam fungsi konstruktor Anda untuk memeriksa untuk melihat apakah mereka dipanggil dengan benar, dan, dalam kasus di mana mereka tidak , menangani panggilan dengan tepat seperti yang diinginkan.

Lihat posting John Resig untuk penjelasan sederhana tentang teknik ini, dan untuk penjelasan yang lebih dalam tentang model pewarisan yang ia dukung.

alegscog
sumber
Pembaruan pada argumen yang menentang: # 1 dapat dikurangi dengan menggunakan 'use strict';mode (atau metode di tautan Anda) # 2 Memiliki gula synatic dalam ES6 , namun perilakunya sama seperti sebelumnya.
ninMonkey
9

Saya setuju dengan pez dan beberapa di sini.

Tampak jelas bagi saya bahwa "baru" adalah penciptaan objek deskriptif diri, di mana pola YUI menggambarkan Greg Dean sepenuhnya dikaburkan .

Kemungkinan seseorang bisa menulis var bar = foo;atau di var bar = baz();mana baz bukan metode membuat objek tampaknya jauh lebih berbahaya.

annakata
sumber
8

Saya pikir baru itu jahat, bukan karena jika Anda lupa menggunakannya secara tidak sengaja mungkin akan menimbulkan masalah, tetapi karena itu merusak rantai warisan, membuat bahasa lebih sulit untuk dipahami.

JavaScript adalah berorientasi objek berbasis prototipe. Karenanya setiap objek HARUS dibuat dari objek lain seperti itu var newObj=Object.create(oldObj). Di sini oldObj disebut prototipe newObj (karenanya "berbasis prototipe"). Ini menyiratkan bahwa jika sebuah properti tidak ditemukan di newObj maka itu akan dicari di oldObj . newObj secara default dengan demikian akan menjadi objek kosong tetapi karena rantai prototipe ini tampaknya memiliki semua nilai oldObj .

Di sisi lain jika Anda melakukannya var newObj=new oldObj(), prototipe newObj adalah oldObj.prototype , yang tidak perlu sulit untuk dipahami.

Triknya adalah menggunakan

Object.create=function(proto){
  var F = function(){};
  F.prototype = proto;
  var instance = new F();
  return instance;
};

Di dalam fungsi ini dan hanya di sini yang baru harus digunakan. Setelah ini cukup gunakan metode Object.create () . Metode ini menyelesaikan masalah prototipe.

Mihir Gogate
sumber
7
Sejujurnya, saya tidak liar tentang teknik ini - itu tidak menambahkan sesuatu yang baru, dan sebagai jawaban Anda menggambarkan itu bahkan bisa berakhir menjadi penopang. IMHO, memahami rantai prototipe dan instantiasi objek sangat penting untuk memahami JavaScript ... Tetapi jika itu membuat Anda tidak nyaman untuk menggunakannya secara langsung, maka menggunakan fungsi pembantu untuk mengurus beberapa detail baik-baik saja, asalkan Anda ingat apa yang Anda lakukan. perbuatan. FWIW: variasi (agak lebih berguna) tentang ini adalah bagian dari ECMAScript edisi ke-5. std, dan sudah tersedia di beberapa browser - jadi Anda harus berhati-hati untuk tidak mendefinisikan ulang secara membabi buta!
Shog9
BTW: Saya tidak yakin mengapa Anda membuat CW ini, tetapi jika Anda ingin mempostingnya kembali dengan koreksi pemformatan yang saya buat, berhati-hatilah untuk menghindari kotak centang itu ...
Shog9
2
Tidak perlu sulit dimengerti? var c = new Car()sama dengan melakukanvar c = Object.create(Car.prototype); Car.call(c)
Juan Mendes