Apa alasan menggunakan null alih-alih tidak ditentukan di JavaScript?

103

Saya telah menulis JavaScript cukup lama sekarang, dan saya tidak pernah punya alasan untuk menggunakannya null. Tampaknya itu undefinedselalu lebih disukai dan melayani tujuan yang sama secara terprogram. Apa sajakah alasan praktis untuk menggunakan nulldaripada undefined?

Jimmy Cuadra
sumber
Ini adalah kemungkinan duplikat stackoverflow.com/questions/461966/…
grasssea
Ada metode seperti document.getElementById()itu yang dapat kembali nulltetapi tidak undefined, jadi dalam kasus tersebut mengapa Anda menguji pengembaliannya undefined? (Tentu, ini akan berhasil jika Anda menggunakan ==daripada ===, tapi tetap saja, mengapa Anda sengaja menguji hal yang salah?)
nnnnnn
Memiliki tipe yang dapat diprediksi akan sangat membantu dan ini dapat memandu pemikiran untuk menggunakan satu atau lainnya. Dimana sebuah objek selalu dikembalikan, dibutuhkan atau diinginkan oleh desain, gunakan null untuk hasil yang salah (misalnya document.getElementById('does-not-exist')). Variabel var a;dan fungsi mengembalikan nilai default ke tidak ditentukan. Di masa lalu, null berada dalam cakupan global sehingga menggunakannya memperlambat eksekusi dan membuat saya lebih memilih jenis falsy lainnya (false, '', 0) daripada referensi gratis. Saya pribadi menghindari null kecuali jika ada alasan kuat yang sebaliknya karena saya menganggapnya lebih sederhana, yang umumnya lebih baik.
jimmont

Jawaban:

59

Null dan undefined pada dasarnya adalah dua nilai berbeda yang memiliki arti yang sama. Satu-satunya perbedaan adalah pada konvensi bagaimana Anda menggunakannya di sistem Anda . Seperti yang telah disebutkan beberapa orang, beberapa orang menggunakan null untuk arti "tidak ada objek" di mana Anda terkadang mendapatkan objek sementara tidak ditentukan berarti tidak ada objek yang diharapkan (atau bahwa ada kesalahan). Masalah saya dengan itu adalah sepenuhnya sewenang-wenang, dan sama sekali tidak perlu.

Meskipun demikian, ada satu perbedaan utama - variabel yang tidak diinisialisasi (termasuk parameter fungsi di mana tidak ada argumen yang diteruskan, antara lain) selalu tidak terdefinisi.

Itulah sebabnya dalam kode saya, saya tidak pernah menggunakan null kecuali sesuatu yang tidak saya kendalikan mengembalikan null (pencocokan regex misalnya). Keindahan ini adalah menyederhanakan banyak hal. Saya tidak pernah perlu memeriksa apakah x === undefined || x === null. Dan jika Anda terbiasa menggunakan == atau hanya menggunakan if (x) .... Hentikan. !xakan mengevaluasi ke true untuk string kosong, 0, null, NaN - yaitu hal-hal yang mungkin tidak Anda inginkan. Jika Anda ingin menulis javascript yang tidak jelek, selalu gunakan triple sama dengan === dan jangan pernah menggunakan null (gunakan undefined sebagai gantinya). Ini akan membuat hidup Anda lebih mudah.

BT
sumber
137
Saya tidak setuju dengan ini. Null digunakan untuk mendefinisikan sesuatu yang kosong secara terprogram. Tidak ditentukan dimaksudkan untuk mengatakan bahwa referensi tersebut tidak ada. Nilai null memiliki referensi yang ditentukan ke "nothing". Jika Anda memanggil properti yang tidak ada dari sebuah objek, maka Anda akan mendapatkan tidak terdefinisi. Jika saya akan membuat properti itu sengaja kosong, maka itu harus nol sehingga Anda tahu bahwa itu sengaja. Banyak pustaka javascript bekerja seperti ini.
com2ghz
6
@ com2ghz Yang Anda gambarkan adalah salah satu dari banyak filosofi. Banyak perpustakaan js yang memang berfungsi seperti itu. Banyak juga yang tidak bekerja seperti itu. Dalam javascript, Anda dapat dengan mudah menyimpan nilai eksplisit yang tidak ditentukan dalam objek atau larik seperti yang Anda bisa dengan null. Arti dari keduanya bergantung sepenuhnya pada konteks. IE mereka berarti apa yang Anda ingin mereka maksudkan.
BT
3
Itulah mengapa JS adalah bahasa yang mengerikan. Seperti yang Anda katakan, banyak perpustakaan memiliki filosofi sendiri tetapi Anda menyertakan banyak perpustakaan untuk 1 proyek. Jadi, Anda menemukan banyak konvensi perpustakaan tersebut. Berapa kali Anda perlu melakukan pemeriksaan palsu yang berbeda. Ini bukan terakhir kali Anda menggabungkan objek null menjadi string dan mendapatkan "null" sebagai string. Atau meneruskan 0 sebagai nilai numerik dan bertanya-tanya mengapa pernyataan IF menangani t sebagai salah.
com2ghz
2
@ com2ghz Jadi JS adalah bahasa yang mengerikan karena memiliki null dan undefined? Saya dapat menghitung lusinan keputusan bahasa yang buruk dalam semua bahasa utama, tidak terkecuali di sana. Saya benar-benar tidak perlu atau ingin menggunakan cek palsu dalam kode saya dan selalu menggunakan ===atau !==. JS adalah bahasa yang sangat ekspresif jika Anda tahu cara menggunakannya.
BT
6
Baik. Saya baru mengetahui bahwa null/ undefineddikotomi diperlukan karena versi awal JS tidak memiliki hasOwnPropertyatau inoperatornya. Sekarang ya, saya tidak begitu mengerti mengapa salah satu dari mereka tidak dihapuskan di ES6 atau proposal ES7 yang pernah saya lihat.
Andy
86

Saya tidak benar-benar punya jawaban, tetapi menurut Nicholas C. Zakas , halaman 30 dari bukunya " JavaScript Profesional untuk Pengembang Web " :

Saat mendefinisikan variabel yang nantinya dimaksudkan untuk menampung sebuah objek, disarankan untuk menginisialisasi variabel tersebut nulldaripada yang lainnya. Dengan begitu, Anda dapat secara eksplisit memeriksa nilainya nulluntuk menentukan apakah variabel tersebut telah diisi dengan referensi objek di lain waktu

bbg
sumber
8
+1 ya, saya setuju dan saya selalu mencoba mengingat untuk menginisialisasi vars ke null. Kemudian saya (cukup) yakin itu undefinedberarti bencana telah terjadi. Hanya imho.
Pete Wilson
9
@ Pete - tetapi tidak memberi tahu Anda apa pun tentang "bencana", jadi apa gunanya? Dan Anda hanya bisa membuat asumsi itu jika Anda mengetahui fungsinya mengikuti konvensi.
RobG
7
Di sisi lain, Anda juga dapat menginisialisasi variabel dengan var myVar;dan secara eksplisit memeriksa nilainya undefineduntuk menentukan apakah itu telah diisi dengan referensi objek di lain waktu. Maksud saya adalah ini sepenuhnya akademis - Anda dapat melakukannya dengan cara apa pun, dan siapa pun yang memberi nasihat dengan satu cara hanya mendorong konvensi mereka sendiri.
thdoan
1
Satu-satunya masalah yang saya miliki (sejak saya mulai dengan JavaScript 15 tahun yang lalu) adalah Anda terlalu sering harus menguji undefineddan null. Ini masih sangat mengganggu. Saya menghindari menetapkan variabel nullhanya untuk mengurangi jumlah nullpengujian tambahan .
G Man
4
@GMan - Ini adalah satu-satunya tempat di mana ==perbandingan (sebagai lawan ===) masuk akal: v == null(atau v == undefined) akan memeriksa nol atau tidak ditentukan.
Rick Love
14

Pada akhirnya, karena keduanya nulldan undefinedmemaksa ke nilai yang sama ( Boolean(undefined) === false && Boolean(null) === false), Anda secara teknis dapat menggunakan keduanya untuk menyelesaikan pekerjaan. Namun, ada cara yang benar, IMO.

  1. Biarkan penggunaan undefineduntuk kompiler JavaScript.

    undefineddigunakan untuk mendeskripsikan variabel yang tidak mengarah ke referensi. Ini adalah sesuatu yang akan dijaga oleh kompiler JS untuk Anda. Pada waktu kompilasi, mesin JS akan menetapkan nilai semua variabel yang diangkat ke undefined. Saat mesin menginjak kode dan nilai tersedia, mesin akan menetapkan nilai masing-masing ke variabel masing-masing. Untuk variabel-variabel yang nilainya tidak ditemukan, variabel-variabel tersebut akan terus mempertahankan referensi ke primitif undefined.

  2. Hanya gunakan null jika Anda secara eksplisit ingin menunjukkan nilai variabel sebagai "tidak ada nilai".

    Seperti yang dinyatakan @ com2gz: nulldigunakan untuk mendefinisikan sesuatu yang kosong secara terprogram. undefineddimaksudkan untuk mengatakan bahwa referensi tersebut tidak ada. Sebuah nullnilai memiliki referensi didefinisikan "apa-apa". Jika Anda memanggil properti yang tidak ada dari suatu objek, maka Anda akan mendapatkan undefined. Jika saya akan membuat properti itu dengan sengaja dikosongkan, maka itu harus dilakukan nullagar Anda tahu bahwa itu sengaja.

TLDR; Jangan gunakan undefinedprimitif. Ini adalah nilai yang akan diatur secara otomatis oleh kompiler JS untuk Anda saat Anda mendeklarasikan variabel tanpa penetapan atau jika Anda mencoba mengakses properti objek yang tidak memiliki referensi. Di sisi lain, gunakan nulljika dan hanya jika Anda secara sengaja ingin variabel memiliki "tidak ada nilai".

Saya tidak pernah secara eksplisit mengatur apa pun ke tidak terdefinisi (dan saya belum menemukan ini di banyak basis kode yang pernah saya gunakan). Juga, saya jarang menggunakan null. Satu-satunya waktu yang saya gunakan nulladalah ketika saya ingin menunjukkan nilai argumen menjadi fungsi yang tidak memiliki nilai, yaitu:

function printArguments(a,b) {
  console.log(a,b);
}

printArguments(null, " hello") // logs: null hello
Govind Rai
sumber
Ini seharusnya menjadi jawaban yang dipilih
alaboudi
13

undefined adalah di mana tidak ada gagasan tentang hal itu; itu tidak memiliki tipe, dan tidak pernah direferensikan sebelumnya dalam lingkup itu; null adalah tempat sesuatu diketahui ada, tetapi tidak memiliki nilai.

Yaplex
sumber
4
Bagaimana Anda tahu jika ada upaya untuk menetapkan nilai, tetapi gagal dan tidak ditentukan sebagai gantinya?
RobG
11

Setiap orang memiliki cara pengkodean sendiri dan semantik internal mereka sendiri, tetapi selama bertahun-tahun saya telah menemukan ini sebagai saran paling intuitif yang saya berikan kepada orang-orang yang mengajukan pertanyaan ini: jika ragu, lakukan apa yang dilakukan JavaScript .

Katakanlah Anda bekerja dengan properti objek seperti opsi untuk plugin jQuery ... tanyakan pada diri Anda nilai apa yang diberikan JavaScript pada properti yang belum ditentukan - jawabannya adalah undefined. Jadi dalam konteks ini, saya akan menginisialisasi jenis hal ini dengan 'tidak terdefinisi' agar konsisten dengan JavaScript (untuk variabel, Anda dapat melakukannya var myVar;daripadavar myVar = undefined; ).

Sekarang katakanlah Anda melakukan manipulasi DOM ... nilai apa yang diberikan JavaScript ke elemen yang tidak ada? Jawabannya adalahnull . Ini adalah nilai yang akan saya inisialisasi jika Anda membuat variabel placeholder yang nantinya akan menyimpan referensi ke elemen, fragmen dokumen, atau serupa yang terkait dengan DOM.

Jika Anda bekerja dengan JSON, maka kasus khusus perlu dibuat: untuk nilai properti tidak terdefinisi, Anda harus menyetelnya ke ""atau nullkarena nilaiundefined tidak dianggap sebagai format JSON yang tepat.

Dengan ini dikatakan, seperti yang telah diungkapkan poster sebelumnya, jika Anda menemukan bahwa Anda menginisialisasi sesuatu dengan nullatau undefinedlebih dari sekali di bulan biru, maka mungkin Anda harus mempertimbangkan kembali bagaimana Anda melakukan pengkodean aplikasi Anda.

thdoan
sumber
Meskipun ini adalah sikap yang baik, saya ingin menambahkan jawaban ini: stackoverflow.com/a/37980662/883303
Frederik Krautwald
@FrederikKrautwald terima kasih atas tautannya - itu adalah penggambaran yang sangat jelas.
thdoan
10

Anda mungkin mengadopsi konvensi yang disarankan di sini, tetapi sebenarnya tidak ada alasan yang tepat untuk itu. Itu tidak digunakan secara cukup konsisten untuk menjadi bermakna.

Untuk membuat konvensi berguna, Anda harus tahu dulu bahwa fungsi yang dipanggil mengikuti konvensi. Kemudian Anda harus secara eksplisit menguji nilai yang dikembalikan dan memutuskan apa yang harus dilakukan. Jika Anda tidak terdefinisi , Anda dapat berasumsi bahwa terjadi beberapa jenis kesalahan yang diketahui oleh fungsi yang dipanggil . Tetapi jika terjadi kesalahan, dan fungsi mengetahuinya, dan berguna untuk mengirimkannya ke lingkungan yang lebih luas, mengapa tidak menggunakan objek kesalahan? yaitu melempar kesalahan?

Jadi pada akhirnya, konvensi praktis tidak berguna dalam hal lain selain program yang sangat kecil di lingkungan yang sederhana.

RobG
sumber
3

Properti berguna dalam null yang tidak ditentukan tidak memenuhi syarat:

> null + 3
3
> undefined + 3
NaN

Saya gunakan nullketika saya ingin 'mematikan' nilai numerik, atau untuk menginisialisasi beberapa. Penggunaan terakhir saya adalah memanipulasi transformasi css:

const transforms = { perspective : null, rotateX : null };
// if already set, increase, if not, set to x
runTimeFunction((x) => { trasforms.perspective += x; });
// still useful, as setting perspective to 0 is different than turning it off
runTimeFunction2((x) => { transforms.perspective = null; });

// toCss will check for 'null' values and not set then at all
runTimeFunction3(() => { el.style.transform = toCss(transforms); });

Tidak yakin apakah saya harus menggunakan properti ini, pikir ...

Faccion
sumber
2

Node dan elemen DOM tidak ditentukan, tetapi mungkin nol.

  • NextSibling dari anak terakhir dari sebuah elemen adalah null.

  • PreviousSibling dari anak pertama adalah null.

  • Referensi document.getElementById bernilai null jika elemen tidak ada dalam dokumen.

Tetapi tidak satu pun dari kasus ini yang nilainya tidak terdefinisi ; tidak ada simpul di sana.

kennebec
sumber
Terima kasih untuk penjelasannya. Bagi saya ini tidak bisa lebih kontra-intuitif.
tomekwi
Itu sangat tergantung pada apa yang Anda coba periksa. Misalnya, jika Anda ingin melihat apakah variabel global bernama 'myVar' ada, maka window.myVarakan mengembalikan 'tidak terdefinisi jika tidak ada. Ada banyak sekali hal yang mengembalikan 'tidak terdefinisi' di JavaScript, hanya ada banyak hal yang mengembalikan 'null' - semuanya tergantung pada konteksnya.
thdoan
2

Beberapa orang mengatakan bahwa tidak masalah untuk menginisialisasi objek null. Saya hanya ingin menunjukkan bahwa default argumen yang merusak tidak berfungsi null. Sebagai contoh:

const test = ({ name } = {}) => {
  console.log(name)
}

test() // logs undefined
test(null) // throws error

Ini membutuhkan nullpemeriksaan sebelum memanggil fungsi yang mungkin sering terjadi.

Matt Way
sumber
1

Saya sedang mengerjakan pertanyaan yang tepat ini sekarang, dan melihat filosofi berikut:

  1. Fungsi apa pun yang dimaksudkan untuk mengembalikan hasil harus mengembalikan nol jika gagal menemukan hasil
  2. Setiap fungsi yang TIDAK dimaksudkan untuk mengembalikan hasil secara implisit mengembalikan tidak terdefinisi.

Bagi saya, pertanyaan ini penting karena siapa pun yang memanggil fungsi yang mengembalikan hasil seharusnya tidak memiliki pertanyaan apakah akan menguji undefined vs null.

Jawaban ini tidak mencoba menjawab:

  1. Nilai properti null vs undefined
  2. Variabel dalam fungsi Anda menjadi null vs tidak ditentukan

Menurut pendapat saya, variabel adalah bisnis Anda sendiri dan bukan bagian dari API Anda, dan properti dalam sistem OO mana pun ditentukan dan oleh karena itu harus ditentukan dengan nilai yang berbeda dari yang akan terjadi jika tidak ditentukan (null untuk ditentukan, tidak ditentukan adalah apa yang Anda dapatkan saat mengakses sesuatu yang tidak ada di objek Anda).

Michael
sumber
1

Berikut alasannya: var undefined = 1 adalah javascript legal, tetapi var null = 1merupakan kesalahan sintaks. Perbedaannya adalah itu nulladalah kata kunci bahasa, sedangkan undefined, untuk beberapa alasan, tidak.

Jika kode Anda bergantung pada perbandingan undefinedseolah-olah itu adalah kata kunci ( if (foo == undefined)- kesalahan yang sangat mudah dibuat) yang hanya berfungsi karena tidak ada yang mendefinisikan variabel dengan nama itu. Semua kode itu rentan terhadap seseorang yang secara tidak sengaja atau jahat mendefinisikan variabel global dengan nama itu. Tentu saja, kita semua tahu bahwa mendefinisikan variabel global secara tidak sengaja sama sekali tidak mungkin dalam javascript ...

Joel Mueller
sumber
1
Gunakan void 0alih-alih tidak ditentukan.
Frederik Krautwald
1

Hanya ingin menambahkan bahwa dengan penggunaan perpustakaan javascript tertentu, null dan undefined dapat memiliki konsekuensi yang tidak diinginkan.

Misalnya, getfungsi lodash , yang menerima nilai default sebagai argumen ke-3:

const user = {
  address: {
    block: null,
    unit: undefined,
  }
}
console.log(_.get(user, 'address.block', 'Default Value')) // prints null
console.log(_.get(user, 'address.unit', 'Default Value')) // prints 'Default Value'
console.log(_.get(user, 'address.postalCode', 'Default Value')) // prints 'Default Value'

Contoh lain: Jika Anda menggunakan defaultProps di React, jika properti dilewatkan null , props default tidak digunakan karena null diinterpretasikan sebagai nilai yang ditentukan . misalnya

class MyComponent extends React.Component {
   static defaultProps = {
      callback: () => {console.log('COMPONENT MOUNTED')},
   }
   componentDidMount() {
      this.props.callback();
   }
}
//in some other component
<MyComponent />   // Console WILL print "COMPONENT MOUNTED"
<MyComponent callback={null}/>   // Console will NOT print "COMPONENT MOUNTED"
<MyComponent callback={undefined}/>   // Console WILL print "COMPONENT MOUNTED"
lilbitofchee.dll
sumber
0

Saya sepenuhnya tidak setuju bahwa penggunaan null atau undefined tidak diperlukan. undefined adalah hal yang menjaga seluruh proses rangkaian prototipe tetap hidup. Jadi compiler hanya dengan null tidak dapat memeriksa apakah properti ini sama dengan null, atau tidak ditentukan dalam prototipe titik akhir. Dalam bahasa bertipe dinamis lainnya (fe Python), ini melontarkan pengecualian jika Anda menginginkan akses ke properti yang tidak ditentukan, tetapi untuk bahasa berbasis prototipe, kompilator juga harus memeriksa prototipe induk dan di sini adalah tempat di mana sebagian besar kebutuhan yang tidak ditentukan.

Arti keseluruhan penggunaan null hanyalah mengikat variabel atau properti dengan objek yang tunggal dan memiliki arti kekosongan, serta penggunaan null memiliki tujuan kinerja. 2 kode ini memiliki waktu eksekusi yang berbeda.

var p1 = function(){this.value = 1};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p1();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p;
});
big_array.reduce((sum, p)=> sum + p.value, 0)

var p2 = function(){this.value = 1, p.x = null};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p2();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p; 
});
big_array.reduce((sum, p)=> sum + p.value, 0)
VahagnNikoghosian
sumber
0

Variabel yang tidak diketahui: undefined.

Variabel belum diketahui ada nilai: null.

  1. Anda menerima objek dari server server_object,.
  2. Referensi Anda server_object.errj. Ini memberitahumu itu undefined. Itu artinya dia tidak tahu apa itu.
  3. Sekarang Anda referensi server_object.err. Ini memberitahumu itu null. Itu berarti Anda mereferensikan variabel yang benar tetapi kosong; oleh karena itu tidak ada kesalahan.

Masalahnya adalah ketika Anda mendeklarasikan nama variabel tanpa nilai ( var hello) js menyatakan bahwa undefined: variabel ini tidak ada; sedangkan programmer sebagian besar berarti: "Saya belum memberinya nilai", definisi null.

Jadi perilaku default seorang programmer — mendeklarasikan sebuah variabel tanpa nilai sebagai tidak ada — bertentangan dengan js — mendeklarasikannya sebagai tidak ada. Dan selain itu, !undefineddan !nullkeduanyatrue begitu sebagian besar pemrogram memperlakukan mereka sebagai setara.

Anda tentu saja dapat memastikan bahwa Anda selalu melakukannya var hello = nulltetapi sebagian besar tidak akan membuang-buang kode mereka untuk memastikan kewarasan tipe dalam bahasa yang sengaja diketik secara longgar, ketika mereka dan !operator memperlakukan keduanya undefineddan nullsetara.

newfivefour
sumber