JavaScript闭包-闭包的作用域
闭包(closure)是JavaScript中的一个十分重要的概念。闭包是指在另一个作用域中保存了一份它从上级函数或作用域取得的变量(键值对),而这些键值对是不会随着上一级函数的执行完闭而被销毁的。闭包从本质上来说是在讨论一个对象的成员属性何时被GC(垃圾回收机制)处理的问题。
我们其实在前面的函数的传值中就已经接触了闭包。在讲解函数的传值时我们列举了一个比较对象属性的函数sortByProperty,在这个函数中,它的返回值是一个匿名函数,实际上这就是一个闭包。我们仍然以这个例子来讲解闭包的作用域。该函数的代码稍作修改,如下:
// 比较对象属性大小的通用函数 function compareObjectFunction(prop){ //匿名函数 return function(obj1,obj2){ if(obj1[prop] > obj2[prop]) return 1; else if(obj1[prop] < obj2[prop]) return -1; else return 0; } } // 创建2个对象 var o1 = {name:"Leon",age:22} var o2 = {name:"Ada",age:25} // 比较对象的name属性 var compare = compareObjectFunction("name"); // 返回值 var returnValue = compare(o1,o2); console.info(rel); //比较name属性会返回1,比较age属性会返回-1
在上面的例子中,使用闭包的最大好处是compareObjectFunction的作用域变大了,当compareObjectFunction函数执行结束之后,prop这个变量依然存在。
在java和C++等静态面向对象编程语言中,在执行完var compare = compareObjectFunction("name")这句话之后,内存会被释放,prop这个属性会被垃圾回收。但是在JavaScript中,当代码执行到var rel = compare(o1,o2);的时候,仍然可以访问prop属性,这种通过返回函数来扩大函数的作用域的方法就是闭包。
需要注意的一点是:闭包不等于匿名函数。我们创建闭包的方式通常是在一个函数的内部创建另一个函数。那么,闭包是如何做到放大函数的作用域的呢?我们仍然以函数执行时的作用域内存模型来讲解这个问题。
首先我们创建了compareObjectFunction函数,然后创建了2个对象o1和o2,完成这些代码之后,内存中的作用域链模型如下图所示:
compareObjectFunction的作用域链的高位指向全局作用域,低位指向自己的作用域。此时在全局作用域中有3个变量。
接下来开始比较对象的name属性,执行以下代码:
var compare = compareObjectFunction("name"); var returnValue = compare(o1,o2);
通过将name作为参数传入compareObjectFunction函数来对两个对象进行名字大小的比较。执行完上面两句代码之后,作用域链的内存模型如下图所示:
在执行compareObjectFunction函数的时候,它返回的是一个匿名函数,匿名函数也有它的作用域链。它的高位指向全局作用域,中间位指向包含它的compareObjectFunction的作用域,低位才是指向自己的作用域。
当程序执行完compareObjectFunction("name")这句代码之后,compareObjectFunction函数执行完毕,GC开始对它进行回收。但是这时GC会发现还有一个匿名函数指向compareObjectFunction的作用域,此时GC就不会回收这块作用域内存。而compareObjectFunction的作用域链和函数本身的内存会被GC作为垃圾回收。
当程序执行到compare(o1,o2)时,它首先在自己的作用域中将obj1和obj2的值分别修改为o1和o2,然后它需要调用prop属性,由于在它自己的作用域空间中没有找到这个属性,它就会到链表上一级指向的作用域compareObjectFunction作用域中去查找,此时发现prop属性为name,所以它就使用name属性来进行比较,并得到返回值。
可以看到,正是因为由于一个匿名函数指向了compareObjectFunction的作用域,使得compareObjectFunction函数在执行完后,它的作用域空间不被GC进行垃圾回收,从而使prop属性的作用域被放大了。
JavaScript的闭包虽然可以放大函数的作用域,但是它的代价是程序执行时会占用更多的内存空间,所以我们不可以滥用闭包,只有在需要使用的时候才用它。
以上就是JavaScript闭包-闭包的作用域的内容,更多相关内容请关注PHP中文网(www.php.cn)!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



typedef struct digunakan dalam bahasa C untuk mencipta alias jenis struktur untuk memudahkan penggunaan struktur. Ia alias jenis data baharu kepada struktur sedia ada dengan menentukan alias struktur. Faedah termasuk kebolehbacaan yang dipertingkatkan, penggunaan semula kod dan pemeriksaan jenis. Nota: Struktur mesti ditakrifkan sebelum menggunakan alias itu mestilah unik dalam program dan hanya sah dalam skop di mana ia diisytiharkan.

Pengecualian nilai jangkaan pembolehubah dalam Java boleh diselesaikan dengan: memulakan pembolehubah menggunakan nilai nol menggunakan semakan dan tugasan;

Kelebihan penutupan JavaScript termasuk mengekalkan skop pembolehubah, membolehkan kod modular, pelaksanaan tertunda, dan keburukan pengendalian peristiwa termasuk kebocoran memori, peningkatan kerumitan, overhed prestasi dan kesan rantaian skop.

Arahan prapemproses #include dalam C++ memasukkan kandungan fail sumber luaran ke dalam fail sumber semasa, menyalin kandungannya ke lokasi yang sepadan dalam fail sumber semasa. Digunakan terutamanya untuk memasukkan fail pengepala yang mengandungi pengisytiharan yang diperlukan dalam kod, seperti #include <iostream> untuk memasukkan fungsi input/output standard.

Ungkapan C++ Lambda menyokong penutupan, yang menyimpan pembolehubah skop fungsi dan menjadikannya boleh diakses oleh fungsi. Sintaks ialah [capture-list](parameters)->return-type{function-body}. capture-list mentakrifkan pembolehubah untuk ditangkap Anda boleh menggunakan [=] untuk menangkap semua pembolehubah tempatan mengikut nilai, [&] untuk menangkap semua pembolehubah tempatan melalui rujukan, atau [variable1, variable2,...] untuk menangkap pembolehubah tertentu. Ungkapan Lambda hanya boleh mengakses pembolehubah yang ditangkap tetapi tidak boleh mengubah suai nilai asal.

Kitaran hayat penunjuk pintar C++: Penciptaan: Penunjuk pintar dicipta apabila memori diperuntukkan. Pemindahan pemilikan: Pindahkan pemilikan melalui operasi pemindahan. Keluaran: Memori dikeluarkan apabila penunjuk pintar keluar dari skop atau dikeluarkan secara eksplisit. Pemusnahan objek: Apabila objek runcing dimusnahkan, penunjuk pintar menjadi penunjuk tidak sah.

boleh. C++ membenarkan definisi dan panggilan fungsi bersarang. Fungsi luaran boleh menentukan fungsi terbina dalam, dan fungsi dalaman boleh dipanggil terus dalam skop. Fungsi bersarang meningkatkan enkapsulasi, kebolehgunaan semula dan kawalan skop. Walau bagaimanapun, fungsi dalaman tidak boleh mengakses pembolehubah tempatan fungsi luaran secara langsung, dan jenis nilai pulangan mesti konsisten dengan pengisytiharan fungsi luaran Fungsi dalaman tidak boleh rekursif sendiri.

Dalam JavaScript, jenis penunjuk ini termasuk: 1. Objek global 2. Panggilan fungsi; 4. Pengendali acara; Selain itu, penunjuk kepada ini boleh ditetapkan secara eksplisit menggunakan kaedah bind(), call(), dan apply().
