Apakah ada perbedaan antara mendeklarasikan variabel:
var a=0; //1
...cara ini:
a=0; //2
...atau:
window.a=0; //3
dalam lingkup global?
javascript
Dan
sumber
sumber
Jawaban:
Ya, ada beberapa perbedaan, meskipun secara praktis mereka biasanya tidak besar.
Ada cara keempat, dan pada ES2015 (ES6) ada dua lagi. Saya telah menambahkan cara keempat di akhir, tetapi memasukkan cara ES2015 setelah # 1 (Anda akan melihat alasannya), jadi kami memiliki:
Pernyataan itu dijelaskan
# 1
var a = 0;
Ini menciptakan variabel global yang juga merupakan properti dari objek global , yang kami akses seperti
window
pada browser (atau melaluithis
lingkup global, dalam kode non-ketat). Tidak seperti beberapa properti lain, properti tidak dapat dihapus melaluidelete
.Dalam istilah spesifikasi, ini menciptakan pengidentifikasi yang mengikat pada objek Catatan Lingkungan untuk lingkungan global . Itu membuatnya menjadi properti dari objek global karena objek global adalah tempat pengikat ikatan untuk objek lingkungan global Catatan Lingkungan diadakan. Inilah sebabnya mengapa properti tidak dapat dihapus: Ini bukan hanya properti sederhana, ini adalah pengikat pengikat.
Pengikatan (variabel) didefinisikan sebelum baris pertama kode dijalankan (lihat "Ketika
var
terjadi" di bawah).Perhatikan bahwa pada IE8 dan sebelumnya, properti dibuat pada
window
tidak enumerable (tidak muncul difor..in
laporan). Di IE9, Chrome, Firefox, dan Opera, ini dapat dihitung.# 1.1
let a = 0;
Ini menciptakan variabel global yang bukan properti dari objek global. Ini adalah hal baru pada ES2015.
Dalam istilah spesifikasi, ini menciptakan pengidentifikasi yang mengikat pada Catatan Lingkungan deklaratif untuk lingkungan global daripada objek Catatan Lingkungan. Lingkungan global adalah unik dalam memiliki split Lingkungan Record, satu untuk semua barang-barang lama yang terjadi di obyek global (yang objek Lingkungan Record) dan satu lagi untuk semua barang baru (
let
,const
, dan fungsi-fungsi yang dibuat olehclass
) yang tidak pergi pada objek global.Ikatan dibuat sebelum kode langkah-demi-langkah di blok terlampir dijalankan (dalam hal ini, sebelum kode global dijalankan), tetapi tidak dapat diakses dengan cara apa pun sampai eksekusi langkah-demi-langkah mencapai
let
pernyataan. Setelah eksekusi mencapailet
pernyataan, variabel dapat diakses. (Lihat "Kapanlet
danconst
terjadi" di bawah.)# 1.2
const a = 0;
Menciptakan konstanta global, yang bukan properti dari objek global.
const
persis sepertilet
kecuali bahwa Anda harus memberikan inisialisasi (= value
bagian), dan Anda tidak dapat mengubah nilai konstanta setelah itu dibuat. Di bawah selimut, persis sepertilet
tetapi dengan bendera pada pengenal yang mengikat mengatakan nilainya tidak dapat diubah. Menggunakanconst
melakukan tiga hal untuk Anda:# 2
a = 0;
Ini menciptakan properti pada objek global secara implisit . Karena ini properti biasa, Anda dapat menghapusnya. Saya sarankan tidak melakukan ini, tidak jelas bagi siapa pun yang membaca kode Anda nanti. Jika Anda menggunakan mode ketat ES5, melakukan ini (menugaskan ke variabel tidak ada) adalah kesalahan. Itu salah satu dari beberapa alasan untuk menggunakan mode ketat.
Dan yang menarik, lagi pada IE8 dan sebelumnya, properti yang dibuat tidak dapat dihitung (tidak muncul dalam
for..in
pernyataan). Itu aneh, terutama diberi # 3 di bawah ini.# 3
window.a = 0;
Ini menciptakan properti pada objek global secara eksplisit, menggunakan
window
global yang merujuk pada objek global (pada browser; beberapa lingkungan non-browser memiliki variabel global yang setara, sepertiglobal
pada NodeJS). Karena ini properti biasa, Anda dapat menghapusnya.Properti ini enumerable, pada IE8 dan sebelumnya, dan pada setiap browser lain yang pernah saya coba.
# 4
this.a = 0;
Persis seperti # 3, kecuali kita mereferensikan objek global melalui
this
alih-alih globalwindow
. Ini tidak akan bekerja dalam mode ketat, karena dalam mode global kode ketat,this
tidak memiliki referensi ke objek global (ia memiliki nilaiundefined
sebagai gantinya).Menghapus properti
Apa yang saya maksud dengan "menghapus" atau "menghapus"
a
? Tepatnya: Menghapus properti (seluruhnya) melaluidelete
kata kunci:delete
sepenuhnya menghapus properti dari objek. Anda tidak dapat melakukannya dengan properti yang ditambahkanwindow
secara tidak langsung melaluivar
,delete
diabaikan secara diam-diam atau melempar pengecualian (tergantung pada implementasi JavaScript dan apakah Anda dalam mode ketat).Peringatan : IE8 lagi (dan mungkin sebelumnya, dan IE9-IE11 dalam mode "kompatibilitas" yang rusak): Itu tidak akan membiarkan Anda menghapus properti
window
objek, bahkan ketika Anda seharusnya diizinkan. Lebih buruk, itu melempar pengecualian ketika Anda mencoba ( coba percobaan ini di IE8 dan di browser lain). Jadi ketika menghapus dariwindow
objek, Anda harus bersikap defensif:Itu mencoba untuk menghapus properti, dan jika pengecualian dilemparkan itu melakukan hal terbaik berikutnya dan menyetel properti
undefined
.Ini hanya berlaku untuk
window
objek, dan hanya (sejauh yang saya tahu) ke IE8 dan sebelumnya (atau IE9-IE11 dalam mode "kompatibilitas" yang rusak). Browser lain baik-baik saja dengan menghapuswindow
properti, tunduk pada aturan di atas.Kapan
var
terjadiVariabel didefinisikan melalui
var
pernyataan yang dibuat sebelum setiap langkah-demi-langkah kode dalam konteks eksekusi dijalankan, dan properti ada juga sebelum ituvar
pernyataan.Ini bisa membingungkan, jadi mari kita lihat:
Contoh langsung:
Tampilkan cuplikan kode
Seperti yang Anda lihat, simbol
foo
didefinisikan sebelum baris pertama, tetapi simbolbar
itu tidak. Di manavar foo = "f";
pernyataan itu, sebenarnya ada dua hal: mendefinisikan simbol, yang terjadi sebelum baris pertama kode dijalankan; dan melakukan penugasan untuk simbol itu, yang terjadi di mana garis berada dalam aliran langkah demi langkah. Ini dikenal sebagai "var
mengangkat" karenavar foo
bagian tersebut dipindahkan ("diangkat") ke bagian atas ruang lingkup, tetapifoo = "f"
bagian tersebut dibiarkan di lokasi aslinya. (Lihat Miskin disalahpahamivar
di blog kecil anemia saya.)Kapan
let
danconst
terjadilet
danconst
berbedavar
dalam beberapa hal. Cara yang relevan dengan pertanyaan adalah bahwa meskipun ikatan yang mereka tetapkan dibuat sebelum kode langkah-demi-langkah berjalan, itu tidak dapat diakses sampai pernyataanlet
atauconst
tercapai.Jadi sementara ini berjalan:
Ini menimbulkan kesalahan:
Dua cara lain yang
let
danconst
berbedavar
, yang tidak benar-benar relevan dengan pertanyaan, adalah:var
selalu berlaku untuk seluruh konteks eksekusi (seluruh kode global, atau seluruh kode fungsi pada fungsi yang muncul), tetapilet
danconst
hanya berlaku di dalam blok tempat mereka muncul. Artinya,var
memiliki lingkup fungsi (atau global), tetapilet
danconst
memiliki lingkup blok.Mengulangi
var a
dalam konteks yang sama tidak berbahaya, tetapi jika Anda memilikilet a
(atauconst a
), memiliki lainlet a
atauconst a
atauvar a
merupakan kesalahan sintaks.Berikut ini contoh yang menunjukkan hal itu
let
danconst
segera berlaku di blok mereka sebelum kode apa pun di dalam blok itu berjalan, tetapi tidak dapat diakses hingga pernyataanlet
atauconst
:Perhatikan bahwa yang kedua
console.log
gagal, alih-alih mengaksesa
dari luar blok.Di luar topik: Hindari mengacaukan objek global (
window
)The
window
objek akan sangat, sangat penuh dengan sifat. Kapan pun memungkinkan, sangat disarankan untuk tidak menambah kekacauan. Sebagai gantinya, bungkus simbol Anda dalam paket kecil dan ekspor paling banyak satu simbol kewindow
objek. (Saya sering tidak mengekspor simbol apa pun kewindow
objek.) Anda dapat menggunakan fungsi untuk memuat semua kode Anda agar mengandung simbol Anda, dan fungsi itu bisa anonim jika Anda suka:Dalam contoh itu, kita mendefinisikan suatu fungsi dan langsung menjalankannya (
()
akhir).Fungsi yang digunakan dengan cara ini sering disebut fungsi pelingkupan . Fungsi didefinisikan dalam fungsi scoping variabel akses dapat didefinisikan dalam fungsi scoping karena mereka penutupan atas data itu (lihat: Penutup tidak rumit di blog sedikit anemia saya).
sumber
window['a']=0
untuk membuatnya jelas saya menggunakan jendela sebagai peta? Apakahwindow
spesial sehingga beberapa browser tidak mengizinkan ini dan memaksa saya untuk menggunakanwindow.a
?window.a = 0;
hanya berfungsi di lingkungan peramban, dan hanya dengan konvensi. Mengikat objek global ke variabel yang bernamawindow
tidak ada dalam ES Spec dan karenanya tidak akan berfungsi, misalnya, V8 atau Node.js, sementarathis.a = 0;
(ketika dipanggil dalam konteks eksekusi global) akan bekerja di lingkungan apa pun karena spec tidak menentukan bahwa harus ada sebuah obyek global. Jika membungkus kode Anda dalam IIFE seperti di bagian Off-topic , Anda dapat lulusthis
sebagai parameter bernamawindow
atauglobal
untuk mendapatkan referensi langsung ke objek global.var a = 0;
otomatis menjadi properti dari objek global. Jika saya mendeklarasikanvar b = 0;
dalam deklarasi fungsi, apakah itu juga akan menjadi properti dari beberapa objek yang mendasarinya?Tetap sederhana:
Kode di atas memberikan variabel lingkup global
Kode ini akan memberikan variabel untuk digunakan dalam lingkup saat ini, dan di bawahnya
Ini umumnya sama dengan variabel global.
sumber
a
di bawah ini lingkup saat ini. Kamu bisa. Selain itu, penggunaan "variabel global" Anda sedikit salah - dua tempat yang Anda katakan "variabel global" tidak lebih global daripada tempat yang tidak Anda katakan.Apakah ada objek global yang semua vars digantung secara default? mis: 'deklarasi global.noVar'
sumber
window.*
deklarasi. Deklarasi ini terlihat paling aman terhadap copy-paste kode Anda, dan hapus juga.Bass pada jawaban yang sangat baik dari TJ Crowder : ( Di luar topik: Hindari berantakan
window
)Ini adalah contoh dari idenya:
Html
init.js (Berdasarkan jawaban ini )
script.js
Inilah plnkrnya . Semoga ini bisa membantu!
sumber
Dalam lingkup global tidak ada perbedaan semantik.
Tetapi Anda harus benar-benar menghindari
a=0
karena menetapkan nilai ke variabel yang tidak dideklarasikan.Juga gunakan penutupan untuk menghindari mengedit ruang lingkup global sama sekali
Selalu gunakan penutupan dan selalu angkat ke ruang lingkup global ketika itu benar-benar diperlukan. Anda harus menggunakan penanganan acara yang tidak sinkron untuk sebagian besar komunikasi Anda.
Seperti @AvianMoncellor menyebutkan ada bug IE dengan
var a = foo
hanya mendeklarasikan global untuk cakupan file. Ini adalah masalah dengan interpreter rusak IE yang terkenal. Bug ini memang terdengar familier sehingga mungkin benar.Jadi berpegang teguh pada
window.globalName = someLocalpointer
sumber
delete
avar
).var
. Mereka hanya mekanisme yang sama sekali berbeda yang memiliki hasil praktis yang sama. :-)var
melompat ke berhenti lingkup.