Analisis terperinci JavaScript bagi rantaian skop

WBOY
Lepaskan: 2022-11-03 16:02:48
ke hadapan
2183 orang telah melayarinya

Artikel ini membawa anda pengetahuan yang berkaitan tentang JavaScript, yang terutamanya memperkenalkan kandungan berkaitan rantai skop ialah satu set peraturan yang bertanggungjawab untuk mengumpul dan mengekalkan pengecam yang diisytiharkan oleh semua Satu siri pertanyaan yang terdiri daripada. pengecam (pembolehubah), dan satu set peraturan yang sangat ketat dilaksanakan untuk menentukan hak akses kod yang sedang dilaksanakan kepada pengecam ini, mari kita lihat bersama-sama, saya harap ia akan membantu semua orang.

Analisis terperinci JavaScript bagi rantaian skop

[Cadangan berkaitan: Tutorial video JavaScript, bahagian hadapan web]

Apakah itu skop ?

Skop ialah satu set peraturan yang bertanggungjawab untuk mengumpul dan mengekalkan satu set pertanyaan yang terdiri daripada semua pengecam (pembolehubah) yang diisytiharkan dan menguatkuasakan satu set peraturan yang sangat ketat yang menentukan hak akses pasangan kod yang sedang dilaksanakan kepada pengecam ini.

Untuk menerangkan apakah skop dalam istilah yang lebih mudah difahami, ia adalah:

  • 作用域首先是一套规则
  • 该规则的用处是用来存储变量,以及如何有限制的获取变量。

Untuk menggunakan analogi yang mungkin tidak sepenuhnya sesuai untuk menerangkan skop, terdapat sebuah bank antarabangsa, dan anda mendepositkan mata wang pelbagai negara di tangan anda apabila anda ingin mengeluarkan wang, ia mempunyai satu set peraturan yang mengehadkan anda kepada hanya Mata wang yang sepadan hanya boleh ditarik balik dari tempat mata wang itu boleh digunakan. Bank ini dan peraturan yang dirumuskannya adalah peranan skop pada pembolehubah.

2. Skop leksikal dan skop dinamik

Dalam JavaScript, skop yang digunakan ialah skop leksikal, juga dipanggil 静态作用域. Ia ditentukan sebelum penyusunan. JavaScript pada asasnya ialah bahasa yang disusun, tetapi penyusunannya berlaku beberapa mikrosaat sebelum kod tersebut dilaksanakan. Tidak seperti bahasa kompilasi lain, ia disusun semasa proses pembinaan, jadi ia kelihatan lebih seperti bahasa yang ditafsirkan.

Tanpa mengira kompilasi dan tafsiran, anda hanya perlu memahami bahawa skop leksikal adalah skop statik. Untuk memahami maksud statik ialah 当代码在书写下定义时就已经确定. Iaitu, skop di mana pembolehubah dan fungsi ditakrifkan dalam kod yang dibaca orang ialah skop mereka.

Gunakan contoh mudah untuk memahami:

var a = 1function foo() {  console.log(a)
}function bar(b) {  var a = 2
  console.log(a)  foo()  function baz() {      console.log(b)
  }  return baz
}var c = bar(a)c()
Salin selepas log masuk

Untuk tiga fungsi yang ditentukan foo, bar, baz dan pembolehubah a, skopnya telah ditentukan semasa menulis.

Oleh itu, apabila kod dilaksanakan, fungsi bar mula-mula memanggil nilai pembolehubah a diluluskan. Apabila nilai pembolehubah a adalah output pertama, ia akan terlebih dahulu bertanya sama ada pembolehubah a telah ditakrifkan dalam skopnya sendiri. Jika ia telah ditakrifkan, ia akan bertanya sama ada Terdapat nilai a, dan pembolehubah output a ialah 2.

kemudian mula memanggil fungsi foo pembolehubah output a dalam foo Begitu juga untuk 会询问自身作用域 sama ada pembolehubah a telah ditakrifkan dalam foo skop global telah ditakrifkan dan nilai wujud, jadi output a ialah 1. Sebenarnya, rantaian skop sudah pun terlibat, tetapi janganlah kita membincangkannya buat masa ini. 自身定义时的作用域

Selepas itu, masukkan panggilan fungsi c, iaitu fungsi baz Nilai pembolehubah b adalah keluaran dalam baz , cari juga

Ini bermakna sama ada pembolehubah b telah ditakrifkan dalam skop fungsi bar sebenarnya ditakrifkan secara tersirat untuk pembolehubah b dalam parameter dan diberikan nilai 1, jadi output akhir ialah 1. 自身定义时的作用域

Ini adalah skop statik Anda hanya perlu melihat kedudukan penulisan pembolehubah dan fungsi untuk menentukan skopnya.

Sebaliknya,

berkaitan dengan skop dinamik dalam JavaScript Hanya penunjuk ini yang terlibat, yang akan diliputi semasa menyemaknya nanti. 动态作用域

Dengan mengandaikan bahawa JavaScript ialah skop dinamik, lihat juga proses pelaksanaan kod dalam contoh di atas.

bar pertama kali dipanggil dan dihantar dalam pembolehubah a Apabila nilai pembolehubah a dikeluarkan untuk kali pertama, pembolehubah a diperoleh sepenuhnya dan 2 adalah output. Apabila memanggil fungsi foo, kerana tiada pembolehubah a dalam skopnya sendiri,

akan dicari ke atas Pada masa ini, ia adalah skop bar fungsi, jadi nilai output ialah 2. 从自身被调用的位置的作用域

Apabila fungsi c dipanggil, iaitu, apabila fungsi baz dipanggil, pembolehubah b tidak wujud dalam dirinya sendiri, jadi cari

, iaitu skop global Pembolehubah b juga tidak ditakrifkan dalam skop global, jadi terus Laporkan ralat. 自身被调用的位置的作用域

3. Klasifikasi skop

Pengkelasan skop boleh dibahagikan kepada kategori statik dan dinamik mengikut yang dinyatakan di atas:

  • 静态作用域
  • 动态作用域
Dalam skop statik, iaitu skop leksikal, ia juga boleh dibahagikan kepada julat tertentu:

  • 全局作用域
  • 函数作用域
  • 块级作用域

3.1 全局作用域

全局作用域可以理解为所有作用域的祖先作用域, 它包含了所有作用域在其中。也就是最大的范围。反向理解就是除了函数作用域和被{}花括号包裹起来的作用域之外,都属于全局作用域

3.2 函数作用域

之所以在全局作用域外还需要函数作用域,主要是有几个原因:

  • 可以存在一个更小的范围存放自身内部的变量和函数,外部无法访问
  • 由于外部无法访问,所以相当于隐藏了内部细节,仅提供输入和输出,符合最小暴露原则
  • 同时不同的函数作用域可以各自命名相同的变量和函数,而不产生命名冲突
  • 函数作用域可以嵌套函数作用域,就像俄罗斯套娃一样可以一层套一层,最终形成了作用域链

用一个例子来展示:

var name = 'xavier'function foo() {  var name = 'parker'
  var age = 18

  function bar() {    var name = 'coin'
    return age
  }  return bar()
}foo()console.log(age) // 报错
Salin selepas log masuk

当代码执行时, 最终会报错表示age查找不到。 因为变量age是在foo函数中定义, 属于foo函数作用域中, 验证了第一点外部无法访问内部。

而当代码只执行到foo函数调用时, 其实foo函数有执行过程, 最终是返回了bar函数的调用,返回的结果应该是18。 在对于编写代码的人来说,其实只需要理解一个函数的作用是什么, 然后给一个需要的输入,最后得出一个预期所想的输出,而不需要在意函数内部到底是怎么编写的。验证了第二点只需要最小暴露原则。

在这代码中, 对name变量定义过三次, 但每次都在各自的作用域中而不会产生覆盖的结果。在那个作用域里调用,该作用域就会返回相应的值。这验证了第三点规避命名冲突。

最终bar函数是在foo函数内部定义的,foo函数获取不到bar内部的变量和函数,但是bar函数可以通过作用域链获取到其父作用域也就是foo里的变量与函数。这验证了第四点。

3.3 块级作用域

块级作用域在ES6之后才开始普及,对于是var声明的变量是无效的,仅对let和const声明的变量有效。以{}包裹的代码块就会形成块级作用域, 例如if语句, try/catch语句,while/for语句。但声明对象不属于。

let obj = {  a: 1,   // 这个区域不叫做块级作用域}  

if (true) {  // 这个区域属于块级作用域
  var foo = 1
  let bar = 2}console.log(foo)  // 1console.log(bar)  // 报错
Salin selepas log masuk

用一个大致的类比来形容全局作用域,函数作用域和块级作用域。一个家中所有的范围就称为全局作用域,而家中的各个房间里的范围则是函数作用域, 甚至可能主卧中还配套有单独的卫生间的范围也属于函数作用域,拥有的半开放式厨房则是块级作用域。

假设你要在家中寻找自己的猫,当它在客厅中,也就是全局作用域里,你可以立马找到。但如果猫在房间里,而没发出声音。你在客厅中是无法判断它在哪里,也就是无法找到它。这就是函数作用域。但是如果它在半开放式厨房里,由于未完全封闭,它是能跑出来的,所以你还是能找得到它。 反之你在房间里,如果它也在,那么可以直接找到。但如果你在房间而它在客厅中,则你可以选择开门去客厅寻找,一样也能找到。

4. 执行上下文和作用域的关系

上述的过程过于理论化,因而现在通过对于实质的情况也就是内存中的情况来讨论。

之前上一篇说过在ES3中执行上下文都有三大内容:

  • 变量对象
  • 作用域链
  • this

实际在内存中,对于全局作用域来说,它所涵盖的范围就是全局对象GO。因为全局对象保存了所有关于全局作用域中的变量和方法。

而对于函数来说,当函数被调用时所创建出的函数执行上下文里的活动对象AO所涵盖的范围就是函数作用域, 并且函数本身存在有一个内部属性[[scope]], 它是用来保存其父作用域的,而父作用域实际上也是另一个变量对象。

对于块级代码来说,就不能用ES3这套来解释,而是用ES6中词法环境和变量环境来解释。块级代码会创建出块级执行上下文,但块级执行上下文里只存在词法环境,不存在变量环境,因而这词法环境里的环境记录就是块级作用域。

相同的解释对于全局和函数也一样,对于ES6中,它们执行上下文里的词法环境和变量环境的环境记录涵盖的范围就是它们的作用域。

用一段代码来更好的理解:

var a = 'a'function foo() {    let b = 'b'
    console.log(c)
}if (true) {    let a = 'c'
    var c = 'c'
    console.log(a)
}foo()console.log(a)
Salin selepas log masuk

对于这段代码刚编译完准备开始执行,也就是代码创建时,此刻执行上下文栈和内存中的图为:

当开始进行到if语句时,会创建块级执行上下文,并执行完if语句时执行上下文栈和内存图为:

当if语句执行完后, 就会被弹出栈,销毁块级执行上下文。然后开始调用foo函数,创建函数执行上下文,此时执行栈和内存图为:

当foo执行时,变量b被赋值为'b',同时输出c时会在自身环境记录中寻找,但未找到,因而往上通过自身父作用域,也就是全局作用域的环境记录中寻找,找到c的值为'c',输出'c'。

5. 作用域链

通过上文阐述的各个知识点,作用域链就很好理解了,在ES3中就是执行上下文里其变量对象VO + 自身父作用域,然后每个执行上下文依次串联出一条链路所形成的就是作用域链。

而在ES6中就是执行上下文里的词法环境里的环境记录+外部环境引用。外部环境引用依次串联也会形成一条链路,也属于作用域链。

它的作用在于变量的查找路径。当代码执行时,遇到一个变量就会通过作用域链不断回溯,直到找到该值又或者是到了全局作用域这顶层还是不存在,则会报错。

以及之后关于闭包的产生,也是由于作用域链的存在所导致的。这会在之后的复习里涉及到。

6. 一些练习

6.1 自己设计一道简单的练习题

var a = 10let b = 20const c = {  d: 30}function foo() {  console.log(a)  let e = 50
  return b + e
  a = 40}function bar() {  console.log(f)  var f = 60
  let a = 70
  console.log(f)  return a + c.d}if (a <= 30) {  console.log(a)  let b = foo()  console.log(b)
} 

console.log(b)
c.d = bar()console.log(a)console.log(c.d)
Salin selepas log masuk

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

Atas ialah kandungan terperinci Analisis terperinci JavaScript bagi rantaian skop. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:juejin.im
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!