Variabel JavaScript menyatakan loop luar atau dalam?

213

Di AS3 saya percaya Anda harus menginisialisasi semua variabel di luar loop untuk meningkatkan kinerja. Apakah ini yang terjadi dengan JavaScript juga? Mana yang lebih baik / lebih cepat / praktik terbaik?

var value = 0;

for (var i = 0; i < 100; i++)
{
    value = somearray[i];
}

atau

for (var i = 0 ; i < 100; i++)
{
    var value = somearray[i];
}
davivid
sumber
7
Di luar! selalu di luar.
BGerrissen
37
Hmm, bukankah deklarasi variabel bisa didorong ke lingkup fungsi di Javascript dan AS3? Jika saya benar, maka itu tidak masalah.
pemboros
3
@Andy - apakah Anda mencoba menetapkan sebelum mendeklarasikan di badan fungsi? Mungkin prasangka Anda membuat Anda tersesat. Kinerja WRT, dengan pelingkupan push-up, jika JS diinterpretasikan, maka akan mengunyah siklus tambahan dalam blok loop. Jika dikompilasi (yang dilakukan kebanyakan mesin saat ini) tidak masalah.
pemboros
2
Pertanyaan bagus! Terima kasih. Setelah membaca semua jawaban, saya percaya jika hanya loop kecil atau hanya variabel temporer saya akan menyimpannya di tempat yang mereka butuhkan dan itu tidak mempengaruhi kinerja. Jika var digunakan dalam fungsi lebih dari sekali, mengapa tidak merujuknya di dalam fungsi dan akhirnya global kemudian dapat duduk di luar fn ()
Dean Meehan
3
Saya terkejut tidak ada yang mencoba mengukur kinerja. Saya membuat jsperf . Tampaknya sedikit lebih cepat ketika dinyatakan di dalam loop untuk Safari dan Firefox, kebalikan dari Chrome ...
Buzut

Jawaban:

281

Sama sekali tidak ada perbedaan dalam arti atau kinerja, dalam JavaScript atau ActionScript.

varadalah arahan untuk parser, dan bukan perintah yang dijalankan saat run-time. Jika pengidentifikasi tertentu telah dideklarasikan varsekali atau lebih di mana saja di badan fungsi (*), maka semua penggunaan pengenal itu di blok akan merujuk ke variabel lokal. Tidak ada bedanya apakah valuedinyatakan demikianvar di dalam loop, di luar loop, atau keduanya.

Karenanya, Anda harus menulis yang menurut Anda paling mudah dibaca. Saya tidak setuju dengan Crockford bahwa menempatkan semua vars di atas fungsi selalu merupakan hal terbaik. Untuk kasus di mana variabel digunakan sementara di bagian kode, lebih baik untuk mendeklarasikan vardi bagian itu, sehingga bagian itu berdiri sendiri dan dapat disalin-tempel. Jika tidak, salin-tempel beberapa baris kode ke fungsi baru selama refactoring, tanpa secara terpisah memilih dan memindahkan yang terkaitvar , dan Anda mendapatkan global yang tidak disengaja.

Khususnya:

for (var i; i<100; i++)
    do something;

for (var i; i<100; i++)
    do something else;

Crockford akan merekomendasikan Anda menghapus yang kedua var (atau menghapus keduanya vardan lakukan di var i;atas), dan jslint akan memukul Anda untuk ini. Tapi IMO lebih mudah dikelola untuk menjaga keduanya var, menjaga semua kode terkait, daripada memiliki sedikit tambahan, kode yang mudah dilupakan di bagian atas fungsi.

Secara pribadi saya cenderung menyatakan sebagai var penugasan pertama dari suatu variabel dalam bagian kode yang independen, terlepas dari apakah ada penggunaan terpisah dari nama variabel yang sama di beberapa bagian lain dari fungsi yang sama. Bagi saya, harus menyatakan varsama sekali adalah JS wart yang tidak diinginkan (akan lebih baik jika memiliki variabel default ke lokal); Saya tidak melihatnya sebagai tugas saya untuk menduplikasi keterbatasan [revisi lama] ANSI C di JavaScript juga.

(*: selain dari pada fungsi yang bersarang)

bobince
sumber
4
Saya masih belum bisa memutuskan apakah saya bersama Crockford atau tidak untuk yang ini. Mendeklarasikan variabel di dalam blok terasa sedikit seperti menggunakan pernyataan fungsi kondisional (yang nakal) ... Namun, saya setuju dengan poin Anda juga :) #confused
Daniel Vassallo
20
+1 Saya tidak setuju dengan alasan Crockford (dikutip dalam jawaban Daniel), sebagai pengembang JavaScript kita tidak boleh menulis kode sehingga programmer "keluarga C" lainnya dapat memahaminya. Saya sering menggunakan var di dalam jika blok dan loop karena itu lebih masuk akal bagi saya.
Andy E
4
-1 OP menanyakan apakah vars di badan loop harus dideklarasikan sebelum loop dimulai. Nilai indeks dari loop jelas merupakan kasus khusus (dan diangkat) dan tidak membantu OP sama sekali.
mkoistinen
21
Loop indexes bukan kasus khusus, mereka ditangani dan diangkat dengan cara yang persis sama dengan tugas normal.
bobince
31
+1 Crockford salah tentang yang satu ini (dan yang lainnya, tapi saya ngelantur). Membutuhkan yang varhanya digunakan di bagian atas fungsi hanya meminta penciptaan variabel global yang tidak disengaja. Dan memiliki banyak variabel yang tidak terkait semua dinyatakan dalam satu tempat secara semantik tidak berarti, terutama ketika beberapa variabel tersebut akhirnya tidak pernah digunakan.
MooGoo
64

Secara teori seharusnya tidak membuat perbedaan dalam JavaScript, karena bahasa tidak memiliki lingkup blok, tetapi hanya lingkup fungsi.

Saya tidak yakin tentang argumen kinerja, tetapi Douglas Crockford masih merekomendasikan bahwa varpernyataan harus menjadi pernyataan pertama di badan fungsi. Mengutip dari Konvensi Kode untuk Bahasa Pemrograman JavaScript :

JavaScript tidak memiliki ruang lingkup blok, jadi mendefinisikan variabel dalam blok dapat membingungkan programmer yang berpengalaman dengan bahasa keluarga C lainnya. Tentukan semua variabel di bagian atas fungsi.

Saya pikir dia ada benarnya, seperti yang Anda lihat pada contoh berikut. Mendeklarasikan variabel di bagian atas fungsi tidak boleh membingungkan pembaca untuk berpikir bahwa variabel i disimpan dalam lingkup forblok loop:

function myFunction() {
  var i;    // the scope of the variables is very clear

  for (i = 0; i < 10; i++) {
    // ...
  }
}
Daniel Vassallo
sumber
8
+1 untuk mengatakan kebenaran OP tentang ruang lingkup JS. Saya bertanya-tanya apakah akan menurunkan jawaban yang mengatakan sebaliknya!
pemboros
1
@ Kaniermaine: Saya tidak mengatakan itu tidak mempengaruhi kinerja. Saya baru saja membuat argumen untuk menempatkan mereka di luar loop, tidak relevan dengan kinerja .... Saya tidak punya referensi untuk argumen kinerja, tetapi Anda tidak mengutip jawaban Anda juga :)
Daniel Vassallo
1
@Kieranmaine: apakah Anda memiliki sumber untuk itu?
Andy E
5
@Kieranmaine: AFAIK bahkan jika Anda mendeklarasikan variabel di dalam loop, ecma- / javascriptakan menabrak mereka saat runtime. Itu disebut "Mengangkat". Jadi seharusnya tidak ada perbedaan.
jAndy
1
Bagaimana ES6 letmempengaruhi jawaban ini?
jbyrd
58

The ECMA-/Javascriptbahasa hoistsvariabel yang dideklarasikan di mana saja untuk bagian atas fungsi. Itu karena bahasa ini memang memiliki function scopedan tidak tidak memiliki block scopeseperti banyak bahasa mirip-C lainnya.
Itu juga dikenal sebagailexical scope .

Jika Anda mendeklarasikan sesuatu seperti

var foo = function(){
    for(var i = 0; i < 10; i++){
    }
};

Ini didapat hoisted ke:

var foo = function(){
    var i;
    for(i = 0; i < 10; i++){
    }
}

Jadi itu tidak membuat perbedaan dalam kinerja (Tapi perbaiki saya jika saya benar-benar salah di sini).
Argumen yang jauh lebih baik untuk tidak mendeklarasikan variabel di tempat lain daripada di bagian atas fungsi adalah keterbacaan . Mendeklarasikan variabel dalam a for-loopdapat mengarah pada asumsi yang salah bahwa variabel ini hanya dapat diakses dalam loop body, yang sama sekali salah . Infact Anda dapat mengakses variabel itu di mana saja dalam lingkup saat ini.

jandy
sumber
Jawaban dasar yang sama dengan yang diterima tetapi, IMO, lebih mudah dibaca dan hanya sebagai informatif. Pekerjaan yang baik.
Anne Gunn
5
Bagaimana ES6 letmempengaruhi jawaban ini?
jbyrd
13

Tahun depan, semua browser akan memiliki mesin JS yang mengkompilasi kode sehingga perbedaan kinerja (yang datang dari parsing blok kode yang sama lagi dan lagi ditambah menjalankan penugasan) harus diabaikan.

Juga, jangan pernah mengoptimalkan kinerja kecuali Anda harus melakukannya. Menjaga variabel tetap dekat dengan tempat Anda membutuhkannya saat pertama kali menjaga kode Anda tetap bersih. Di sisi negatif, orang yang terbiasa dengan bahasa dengan cakupan blok mungkin bingung.

Aaron Digulla
sumber
6

Pertimbangan lain, sekarang kita miliki letdan constdi ES2015, adalah bahwa Anda sekarang dapat variabel lingkup khusus ke blok loop. Jadi, kecuali jika Anda memerlukan variabel yang sama di luar loop (atau jika setiap iterasi tergantung pada operasi yang dilakukan untuk variabel itu dalam iterasi sebelumnya), mungkin lebih baik untuk melakukan ini:

for (let i = 0; i < 100; i++) {
    let value = somearray[i];
    //do something with `value`
}
Matt Browne
sumber
4

Saya baru saja melakukan tes sederhana di Chrome. Cobalah biola di browser Anda dan lihat hasilnya

  var count = 100000000;
    var a = 0;
    console.log(new Date());

    for (var i=0; i<count; i++) {
      a = a + 1
    }

    console.log(new Date());

    var j;
    for (j=0; j<count; j++) {
      a = a + 1;
    }

    console.log(new Date());

    var j;
    for (j=0; j<count; j++) {
        var x;
        x = x + 1;
    }

    console.log(new Date());

Hasilnya adalah bahwa tes terakhir memakan waktu ~ 8 detik dan 2 sebelumnya hanya ~ 2 detik. Sangat berulang dan terlepas dari pesanan.

Jadi, ini membuktikan kepada saya, bahwa seseorang harus selalu mendeklarasikan vars di luar loop. Kasus penasaran bagi saya adalah yang pertama di mana saya menyatakan idalam pernyataan for (). Yang ini tampaknya sama cepatnya dengan tes ke-2 di mana saya pra-mendeklarasikan indeks.

mkoistinen
sumber
14
@KP: hasilnya hanya terbukti jika Anda mengujinya sendiri atau jika banyak orang memverifikasinya. @mkoistinen: Saya membuat tes yang lebih adil, jsfiddle.net/GM8nk . Setelah menjalankan skrip beberapa kali di Chrome 5, saya dapat melihat bahwa tidak ada pemenang yang konsisten. Ketiga variasi tampil lebih baik daripada yang lain setelah beberapa refresh. -1 dari saya, saya takut. Catatan, Anda mungkin ingin menjalankan yang ini di browser lain. IE dan Fx tidak suka 100 juta iterasi.
Andy E
1
@AndyE. Wow, jadi berdasarkan tes sederhana ini, IE sucks 100X lebih? =)
mkoistinen
2
Hasil ada di semua tempat bagi saya, tidak ada pemenang lintas-browser yang jelas meskipun kadang-kadang ada perbedaan kecepatan yang signifikan. Aneh. Saya pikir biola Andy adalah ujian yang lebih baik, menempatkan masing-masing kandidat dalam fungsinya sendiri ... tentu saja jika skrip asli dijalankan di luar fungsi, seharusnya tidak benar-benar menguji apa pun karena vardinyatakan sebagai variabel variabel global yang akan tetaplah global.
bobince
4
Lebih dari setahun setelah fakta, tetapi SHAPOW
sdleihssirhc
2
Ini bukan milik saya, tetapi saya pikir beberapa dari Anda akan tertarik: jsperf.com/var-in-for-loop
m1.
1

JavaScript adalah bahasa yang ditulis di bagian bawah oleh C atau C ++, saya tidak begitu yakin yang mana. Dan salah satu tujuannya adalah menyelamatkan lavour dari penanganan memori internal. Bahkan dalam C atau C ++, Anda tidak perlu khawatir tentang apakah itu akan menghabiskan banyak sumber daya ketika variabel dideklarasikan di dalam loop. Mengapa Anda harus khawatir tentang hal itu dalam JavaScript?

Yan Yang
sumber
1
C atau C ++ mungkin ada di bagian bawah JavaScript. Tetapi kita tidak boleh lupa bahwa, browser mengkonversi JavaScript ke bahasa yang mendasarinya (C, C ++). Jadi kinerjanya tergantung pada browser
Kira
3
@ Kira Sebenarnya tidak bisa dikonversi ke C / C ++. Javascript dikompilasi ke dalam serangkaian instruksi yang dieksekusi oleh JS runtime (yaitu mesin virtual yang berjalan di browser). Prinsip yang sama berlaku untuk bahasa dinamis lain seperti Python dan Ruby.
Anthony E
@AnthonyE, Terima kasih atas informasinya. Saya tidak yakin tentang konversi JS ke C atau C ++. Jadi saya menggunakan mungkin dalam komentar saya
Kira
0

Yah, itu tergantung pada apa yang Anda coba capai ... jika valueseandainya hanya variabel sementara di dalam blok loop maka jauh lebih jelas untuk menggunakan bentuk kedua. Ini juga lebih logis dan bertele-tele.

Crozin
sumber
Saya telah menemukan bahwa mendorong semua deklarasi variabel ke atas - termasuk variabel sementara - sebenarnya dapat menyebabkan kebingungan karena hanya menjadi 'berisik'.
Daniel Sokolowski
0

Tidak ada bedanya jika Anda mendeklarasikan variabel di dalam atau di luar untuk loop. Di bawah ini adalah kode sampel untuk diuji.

function a() {
   console.log('Function a() starts');
   console.log(new Date());
    var j;
    for (j=0; j<100000000; j++) {
        var x;
        x = x + 1;
    }
    console.log(new Date());
    console.log('Function a() Ends');
}
a()
function b() {
console.log('Function B() starts');
   console.log(new Date());
    var a;
    var j;
    for (j=0; j<100000000; j++) {
      a = a + 1;
    }
    console.log(new Date());
    console.log('Function B() Ends');
}
b()

Hasilnya menunjukkan dalam kasus saya

Function a() starts
VM121:3 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:9 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:10 Function a() Ends
VM121:14 Function B() starts
VM121:15 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:21 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:22 Function B() Ends

Terima kasih - MyFavs.in

myfavs.in
sumber
dalam kedua kasus Anda mendeklarasikan j di luar loop! X_x
john ktejik
Saya mencobanya di Chromium 81 dengan letbukannya vardan a()cenderung sedikit lebih lambat (seperti 120 vs 115 ms = ~ 6% = IMO tidak signifikan)
mikiqex
-1

Pertanyaan di sini pada dasarnya adalah untuk menyatakan var di dalam satu loop. Coba pikirkan apa yang terjadi jika Anda melakukan ini:

var a = 30;
var a = 50;
var a = 60;

Apakah Anda pikir ini benar? Tidak ... karena Anda tidak ingin mendeklarasikan variabel berkali-kali. Ketika Anda mendeklarasikan variabel di dalam sebuah loop, bukankah itu menyatakan berapa kali loop berjalan? Jelas itu akan menampar Anda ketika Anda berada dalam mode 'gunakan ketat'. Orang-orang tidak setuju dengan Crockford tanpa memikirkan pertanyaan aslinya.

Jadi selalu baik untuk mendeklarasikan variabel di atas - 1. Agar mudah dibaca, 2. Membuat kebiasaan yang baik.

Vivek Pohre
sumber
1
"Ketika kamu mendeklarasikan variabel di dalam sebuah loop, bukankah itu menyatakan berapa kali loop itu berjalan?" <- Tidak, itu tidak benar. Deklarasi variabel akan diangkat, jadi yang tersisa hanyalah tugas.
Matthias
-2

Dalam hal kinerja setelah menjalankan pengujian pada Chrome, Firefox, dan jsperf pada OS Linux tampaknya ada perbedaan kinerja antara deklarasi variabel dalam satu lingkaran dan keluar dari satu lingkaran. Ini adalah perbedaan kecil tetapi ini juga diperparah oleh jumlah iterasi dan jumlah deklarasi variabel.

Oleh karena itu untuk kinerja terbaik saya harus menyarankan mendeklarasikan variabel di luar loop. Atau lebih baik lagi deklarasikan variabel Anda. Lihat contoh.

// inline
for (var ai = 0, al = 100000000, av; ai < al; ai++) {
    av = av + 1;
}

// outside
var bv;
var bl = 100000000;
for (var bi = 0; bi < bl; bi++) {
    bv = bv + 1;
}

Perhatikan bagaimana variabel 'al' dan 'av' ada di dalam baris deklarasi loop. Deklarasi inline ini telah memberi saya kinerja yang lebih baik secara konsisten. Bahkan lebih dari deklarasi variabel di luar loop. Sekali lagi perbedaan kinerja sangat kecil.

https://jsperf.com/outside-inline-for-loop-ase/1

AlexanderElias
sumber
Bagi saya tes Anda memberi di dalam lingkaran. Dan bagaimanapun tidak, perbedaannya terlalu kecil untuk disimpulkan, dan jawaban yang diterima dengan jelas menjelaskan tidak ada perbedaan
Ulysse BN
Ketika deklarasi variabel diangkat, benar-benar tidak ada perbedaan.
trincot