Garis bawahi awalan untuk nama properti dan metode dalam JavaScript

241

Apakah awalan garis bawah dalam JavaScript hanya sebuah konvensi, seperti misalnya dalam metode kelas privat Python?

Dari dokumentasi 2,7 Python:

Variabel instance "Privat" yang tidak dapat diakses kecuali dari dalam suatu objek tidak ada dalam Python. Namun, ada konvensi yang diikuti oleh sebagian besar kode Python: nama diawali dengan garis bawah (misalnya _spam) harus diperlakukan sebagai bagian non-publik dari API (apakah itu fungsi, metode atau anggota data) .

Apakah ini juga berlaku untuk JavaScript?

Ambil contoh kode JavaScript ini:

function AltTabPopup() {
    this._init();
}

AltTabPopup.prototype = {
    _init : function() {
        ...
    }
}

Juga, variabel awali garis bawah digunakan.

    ...
    this._currentApp = 0;
    this._currentWindow = -1;
    this._thumbnailTimeoutId = 0;
    this._motionTimeoutId = 0;
    ...

Hanya konvensi? Atau ada lebih banyak di belakang awalan garis bawah?


Saya mengakui pertanyaan saya sangat mirip dengan pertanyaan ini , tetapi tidak membuat orang lebih pintar tentang pentingnya awalan garis bawah dalam JavaScript.

Kenny Meyer
sumber

Jawaban:

33

Selamat datang di 2019!

Tampaknya proposal untuk memperluas sintaksis kelas untuk memungkinkan #variabel awalan menjadi pribadi diterima. Chrome 74 dikirimkan dengan dukungan ini.

_ nama variabel yang diawali dianggap pribadi oleh konvensi tetapi masih publik.

Sintaks ini mencoba menjadi singkat dan intuitif, meskipun agak berbeda dari bahasa pemrograman lain.

Mengapa sigil # dipilih, di antara semua titik kode Unicode?

  • @adalah favorit awal, tetapi diambil oleh dekorator. TC39 dianggap menukar dekorator dan sigils negara bagian swasta, tetapi komite memutuskan untuk menunda penggunaan pengguna transpiler yang ada.
  • _ akan menyebabkan masalah kompatibilitas dengan kode JavaScript yang ada, yang telah memungkinkan _ pada awal pengidentifikasi atau nama properti (publik) untuk waktu yang lama.

Proposal ini mencapai Tahap 3 pada Juli 2017. Sejak saat itu, telah ada pemikiran yang luas dan diskusi panjang tentang berbagai alternatif. Pada akhirnya, proses pemikiran dan keterlibatan masyarakat yang berkelanjutan ini menghasilkan konsensus baru pada proposal dalam repositori ini. Berdasarkan konsensus itu, implementasi bergerak maju dalam proposal ini.

Lihat https://caniuse.com/#feat=mdn-javascript_classes_private_class_fields

Karuhanga
sumber
257

Itu hanya sebuah konvensi. Bahasa Javascript tidak memberikan arti khusus untuk pengidentifikasi dimulai dengan karakter garis bawah.

Karena itu, konvensi ini cukup berguna untuk bahasa yang tidak mendukung enkapsulasi . Meskipun tidak ada cara untuk mencegah seseorang menyalahgunakan implementasi kelas Anda, setidaknya itu menjelaskan maksud Anda, dan mendokumentasikan perilaku seperti itu salah sejak awal.

Frédéric Hamidi
sumber
4
Ya. Bahkan jika bahasa itu tidak "mendukung" itu, itu adalah konvensi yang sangat berguna untuk dimiliki.
Juho Vepsäläinen
Masalah serius. jsfiddle.net/VmFSR Seperti yang Anda lihat di sana, nilai yang diciptakan nama hanya dapat diakses dengan mengawali nilai baru, dibuat, menggunakan _saya ingin tahu apa yang terjadi !? mengapa tidak this.name?
Muhammad Umer
1
@Muhammad Umer, saya tidak yakin saya mengerti komentar Anda. console.log(someone._name = "Jean Dupont");berfungsi juga console.log(someone.name);, dan itu menugaskan dan mengevaluasi anggota underscore-awalan di belakang properti. Seperti yang Anda lihat , tidak ada enkapsulasi dijamin melalui garis bawah :)
Frédéric Hamidi
3
Secara default, Visual Studio mencoba membantu Anda menghargai ini. Mesin javascript IntelliSense menampilkan properti "pribadi", dari dalam objek, saat menggunakan variabel "ini". Tetapi, ketika dipanggil dari luar, ia menyembunyikan semua atribut yang digarisbawahi.
foxontherock
1
@Karuhanga dia menjawab ini pada tahun 2010 - tentu saja hal-hal telah berubah dalam 10 tahun
Kenny Meyer
99

JavaScript sebenarnya mendukung enkapsulasi, melalui metode yang melibatkan penyembunyian anggota dalam penutupan (Crockford). Yang mengatakan, itu kadang-kadang rumit, dan konvensi garis bawah adalah konvensi yang cukup bagus untuk digunakan untuk hal-hal yang bersifat pribadi, tetapi Anda tidak perlu bersembunyi.

Zach
sumber
19
Pilih suara untuk memperjelas cara mencapai penutupan, suara bawah untuk mengatakan garis bawah adalah konvensi yang baik. Jadi saya tidak akan memilih yang manapun :)
Jason
3
Menyembunyikan anggota dalam penutupan kadang-kadang dapat menghalangi kemampuan ujian. Memeriksa artikel ini: adequatelygood.com/2010/7/Writing-Testable-JavaScript
Zach Lysobey
4
@Jason - Hanya ingin tahu, mengapa Anda menganggap menggarisbawahi konvensi yang buruk?
Tamás Pap
5
@TamasPap - Beberapa alasan, tetapi hanya pilihan saya: 1) Kruk untuk memaksa JS ke gaya bahasa lain 2) Jika itu dapat diakses, itu akan digunakan. Garis bawah dapat mengotori dan membelit kode luar. 3) Membingungkan dengan programmer JS baru.
Jason
9
Bahkan dengan penutupan, secara teknis masih mungkin untuk mendapatkan akses ke variabel yang disebut "pribadi". Konvensi _ setidaknya membiarkan dev tahu untuk melakukannya dengan risiko sendiri (atau sesuatu seperti itu).
sarink
14

JSDoc 3 memungkinkan Anda untuk membubuhi keterangan fungsi Anda dengan @access private(sebelumnya @privatetag) yang juga berguna untuk menyiarkan maksud Anda ke pengembang lain - http://usejsdoc.org/tags-access.html

philrabin
sumber
10

"Hanya konvensi? Atau ada lebih banyak di belakang awalan garis bawah?"

Terlepas dari konvensi privasi, saya juga ingin membantu membawa kesadaran bahwa awalan garis bawah juga digunakan untuk argumen yang bergantung pada argumen independen, khususnya di peta jangkar URI. Kunci dependen selalu mengarah ke peta.

Contoh (dari https://github.com/mmikowski/urianchor ):

$.uriAnchor.setAnchor({
  page   : 'profile',
  _page  : {
    uname   : 'wendy',
    online  : 'today'
  }
});

Jangkar URI pada bidang pencarian browser diubah menjadi:

\#!page=profile:uname,wendy|online,today

Ini adalah konvensi yang digunakan untuk menggerakkan status aplikasi berdasarkan perubahan hash.

Sam Araiza
sumber
8

import/exportsekarang melakukan pekerjaan dengan ES6. Saya masih cenderung awalan dengan fungsi yang tidak diekspor dengan_ jika sebagian besar fungsi saya diekspor.

Jika Anda hanya mengekspor kelas (seperti dalam proyek sudut), itu tidak diperlukan sama sekali.

export class MyOpenClass{

    open(){
         doStuff()
         this._privateStuff()
         return close();
    }

    _privateStuff() { /* _ only as a convention */} 

}

function close(){ /*... this is really private... */ }
Nicolas Zozol
sumber
Saya tidak berpikir bahwa impor / ekspor menawarkan dukungan untuk metode kelas privat dengan cara apa pun. Maksud saya, ini mendukung fungsionalitas yang serupa di tingkat kelas, tetapi tidak menawarkan menyembunyikan metode yang terkandung. (Yaitu semua metode yang terkandung selalu publik)
bvdb
Anda mengekspor kelas, dan panggilan fungsi dalam fungsi luar. Fungsi-fungsi ini adalah privat.
Nicolas Zozol