Rumah  >  Artikel  >  hujung hadapan web  >  Fahami secara ringkas var dan biarkan dalam pembolehubah atau gelung JavaScript

Fahami secara ringkas var dan biarkan dalam pembolehubah atau gelung JavaScript

WBOY
WBOYke hadapan
2022-09-14 17:18:441441semak imbas

Artikel ini membawakan anda pengetahuan yang berkaitan tentang javascript terutamanya memperkenalkan penjelasan terperinci var dan biarkan dalam pembolehubah atau gelung JavaScript. Artikel ini memperkenalkan kandungan secara terperinci di sekitar tema, yang mempunyai kepentingan tertentu. Untuk nilai rujukan, mari kita lihat di bawah ini saya harap ia akan membantu semua orang.

Fahami secara ringkas var dan biarkan dalam pembolehubah atau gelung JavaScript

[Cadangan berkaitan: tutorial video javascript, bahagian hadapan web]

Gunakan var in untuk gelung Masalah yang disebabkan oleh permulaan pengisytiharan

// 一道经典面试题:
var funcs = [];
for (var i = 0; i < 3; i++) {
  funcs[i] = function() {
    console.log("My value: " + i)
  };
}
for (var j = 0; j < 3; j++) {
  funcs[j]();
}
/*
输出结果:
> My value: 3
> My value: 3
> My value: 3
*/

Sebab mengapa fenomena ini berlaku ialah:

  • Skop pengisytiharan var ialah skop fungsi dan bukannya Skop peringkat blok, jadi pembolehubah var yang ditakrifkan semasa memulakan gelung for masih boleh diakses di luar badan gelung gelung for.
  • Dan apabila diakses selepas gelung tamat, pembolehubah var yang diakses ialah nilai selepas gelung selesai.

Penyelesaian

Gunakan penutupan

Penyelesaian dalam era ES5 adalah untuk mencipta penutupan melalui IIFE, menyimpan pembolehubah dalam badan fungsi, dan kemudian melaksanakan fungsi Pembolehubah var luar tidak akan diakses.

var funcs = [];
for (var i = 0; i < 3; i++) {
    // 1. 闭包
    funcs[i] = (function (i) {
        return function () {
            console.log("My value: " + i);
        };
    })(i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

Gunakan pembolehubah let untuk memulakan

Pengisytiharan biarkan ialah skop peringkat blok dan pembolehubah dalam badan gelung tidak akan dibocorkan di luar penyataan blok.

Oleh itu, apabila mengakses pembolehubah i selepas gelung tamat, tiada gangguan daripada pembolehubah skop luar, dan apa yang diakses secara semula jadi adalah nilai pembolehubah yang disimpan dalam badan fungsi.

var funcs = [];
// 2. let
for (let i = 0; i < 3; i++) {
  funcs[i] = function() {
    console.log("My value: " + i);
  };
}
for (var j = 0; j < 3; j++) {
  funcs[j]();
}

Ia juga boleh dilihat dari sini bahawa menggunakan var untuk memulakan gelung for itu sendiri adalah berlawanan dengan intuisi.

Pembolehubah yang digunakan untuk memulakan gelung for hendaklah pembolehubah setempat bagi gelung for ini seharusnya tidak bermakna selepas gelung berakhir.

Tetapi jika anda menggunakan var untuk memulakan, memandangkan skop pembolehubah yang diisytiharkan oleh var ialah skop fungsi, pembolehubah permulaan ini berada dalam skop yang sama seperti gelung for dan tidak dihadkan oleh gelung for.

Ia mestilah pembolehubah tempatan bagi gelung for, tetapi ia didedahkan dalam skop lapisan yang sama seperti gelung for, dan nilai pembolehubah telah diubah mengikut bilangan gelung, yang secara semula jadi akan mempengaruhi akses pembolehubah oleh kod lain selepas gelung berakhir.

Jika anda menggunakan let untuk memulakan gelung for, anda tidak akan menghadapi masalah ini, kerana skop yang diisytiharkan oleh let ialah skop peringkat blok, dan pembolehubah permulaan ini akan menjadi pembolehubah setempat bagi gelung for sebagai dijangka.

Bagaimanakah gelung for mengendalikan pembolehubah permulaan yang diisytiharkan dengan let dan var?

Kesimpulan pertama:

  • Apabila dimulakan dengan var, gelung for akan terus menggunakan var yang dicipta untuk memulakan pembolehubah
  • Dimulakan dengan let , kurungan akan membentuk skopnya sendiri dan gelung for akan menghantar nilai pembolehubah dalam kurungan kepada badan gelung.

Lihat pertama pada kesimpulan pertama, Spesifikasi mengatakan ini:

Yes It boleh dilihat bahawa spesifikasi tidak mempunyai sebarang rawatan khas untuk pembolehubah permulaan var, jadi ia boleh digunakan secara langsung. Pada masa ini, pembolehubah ialah pembolehubah var biasa dan berada dalam skop yang sama dengan gelung for.

Mari kita gunakan kod untuk membuktikannya:

var funcs = [];
for (var i = 0; i < 3; i++) {
    // !!!重复声明了一个同名的var变量
    var i = 5;
    console.log("My value: " + i);
}
/*
只会输出一次:
> My value: 5
*/

var boleh diisytiharkan berulang kali dan nilai akan ditimpa, jadi isytiharkan satu lagi var i = 5 dalam badan gelung , pembolehubah gelung dimusnahkan, dan gelung for akan dilonjak keluar terus.

var funcs = [];
for (var i = 0; i < 3; i++) {
    // 用let声明了一个和循环变量同名的变量
    let i = 5;
    console.log("My value: " + i);
}
/*
一共输出了3次:
> My value: 5
> My value: 5
> My value: 5
*/

Mulakan pembolehubah var dalam skop fungsi, dan pembolehubah let dalam badan gelung berada dalam skop blok Pembolehubah let dalam badan gelung mempunyai keutamaan untuk mengakses pembolehubah biarkan dalam skop blok , jadi nilai i dalam badan gelung akan ditimpa.

Dan kerana pembolehubah var sebenarnya berada dalam skop luar pemboleh ubah let, pemboleh ubah let tidak diisytiharkan berulang kali dan tiada ralat dilaporkan, pembolehubah var juga akan menyelesaikan misinya sebagai pembolehubah gelung seperti yang dijadualkan.

Mari kita lihat kesimpulan kedua, juga melihat spesifikasi dahulu:

Jelas sekali bahawa menggunakan let untuk memulakan akan mempunyai satu panggilan lebih daripada menggunakan var perIterationLets sesuatu. Apakah itu

perIterationLets?

Seperti yang dapat dilihat dari spesifikasi, perIterationLets berasal dari LexicalDeclaration(词法声明) dalam boundNames.

Dan ini LexicalDeclaration(词法声明) sebenarnya adalah kenyataan let yang kami gunakan untuk memulakan.

Boleh difahami bahawa jika kita menggunakan pernyataan let untuk memulakan gelung for, pembolehubah let tidak akan digunakan terus di dalam gelung for seperti pembolehubah var Sebaliknya, pembolehubah let akan dikumpul terlebih dahulu digunakan dalam beberapa cara. Borang ditukar kepada perIterationLets dan kemudian dihantar ke badan gelung.

Untuk apa perIterationLets digunakan?

Daripada spesifikasi, kita dapat melihat bahawa pembolehubah let kami dihantar ke

sebagai parameter sebagai perIterationLets, iaitu badan gelung. ForBodyEvaluation

Dalam badan gelung,

hanya melakukan satu perkara, iaitu, sebagai parameter perIterationLets: CreatePerIterationEnvironment

从字面上理解,CreatePerIterationEnvironment意思就是每次循环都要创建的环境

要注意,这个环境不是{...}里的那些执行语句所处的环境。 {...}里的执行语句是statement,在规范里可以看到,stmt有自己的事情要做。

这个环境是属于圆括号的作用域,也就是我们定义的let初始化变量所在的作用域。

再看看每次循环都要创建的环境被用来干嘛了:

逐步分析一下方法:CreatePerIterationEnvironment这个

  • 首先,把当前执行上下文的词法环境保存下来,作为lastIterationEnv(上一次循环时的环境)
  • 创建一个和lastIterationEnv同级的新作用域,作为thisIterationEnv(本次循环的环境);
  • 遍历我们定义的let初始化变量,也就是perIterationLets,在thisIterationEnv(本次循环的环境)里创建一个同名的可变绑定,找到它们在lastIterationEnv(上一次循环时的环境)里的终值,作为这个同名绑定的初始值;
  • 最后,将thisIterationEnv(本次循环的环境)交还给执行上下文。

简而言之就是,for循环会在迭代之前创建一个和初始化变量同名的变量,并使用之前迭代的终值将这个变量初始化以后,再交还给执行上下文

用伪代码理解一下这个过程就是:

到这里又有一个问题,既然把圆括号内的变量向循环体里传递了,那如果在循环体里又重复声明了一个同名变量,算不算重复声明,会不会报错?

答案是不会。

因为CreatePerIterationEnvironment在执行时,在新环境里创建的是一个可变的绑定,因此如果在循环体内重复声明一个名字为i的变量,只是会影响循环体内执行语句对i值的访问。

var funcs = [];
for (let i = 0; i < 3; i++) {
    // !!!用let声明了一个和循环变量同名的变量
    let i = 5;
    console.log("My value: " + i);
}
/*
一共输出了3次:
> My value: 5
> My value: 5
> My value: 5
*/

总结

在for循环中使用var声明来初始化的话,循环变量会暴露在和for循环同一作用域下,导致循环结束后还能访问到循环变量,且访问到的变量值是经过循环迭代后的值。

解决这个问题的方法如下:

  • 使用闭包将循环变量的值作为局部变量保存起来;
  • 使用ES6的let声明,将循环变量的作用域限制在for循环内部,初始化变量始终是for循环的局部变量,不能在外界被访问到。

for循环是怎么处理用let和var声明的初始化变量的?

  • 用var初始化时,for循环会直接使用创建的var初始化变量;
  • 用let初始化时,圆括号会自成一个作用域,for循环会将圆括号内的变量值往循环体内传递。

【相关推荐:javascript视频教程web前端

Atas ialah kandungan terperinci Fahami secara ringkas var dan biarkan dalam pembolehubah atau gelung JavaScript. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:jb51.net. Jika ada pelanggaran, sila hubungi admin@php.cn Padam