Rumah hujung hadapan web tutorial js 谈谈JavaScript中的函数与闭包_基础知识

谈谈JavaScript中的函数与闭包_基础知识

May 16, 2016 pm 05:37 PM
javascript penutupan fungsi penutupan

闭包这东西,说难也难,说不难也不难,下面我就以自己的理解来说一下闭包

一、闭包的解释说明

对于函数式语言来说,函数可以保存内部的数据状态。对于像C#这种编译型命令式语言来说,由于代码总是在代码段中执行,而代码段是只读的,因此函数中的数据只能是静态数据。函数内部的局部变量存放在栈上,在函数执行结束以后,所占用的栈被释放,因此局部变量是不能保存的。

Javascript采用词法作用域,函数的执行依赖于变量作用域,这个作用域是在定义函数时确定的。因此Javascript中函数对象不仅保存代码逻辑,还必须引用当前的作用域链。Javascript中函数内部的局部变量可以被修改,而且当再次进入到函数内部的时候,上次被修改的状态仍然持续。这是因为因为局部变量并不保存在栈上,而是通过一个对象来保存。

决定使用哪个变量是由作用域链决定的,每次生成函数实例时,都会为之创建一个对象用来保存局部变量,并且把这个用于保存局部变量的对象加入作用域链中。不同函数对象可以通过作用域链关联起来。Javascript中所有函数都是闭包,我们不能避免“产生”闭包。

引用一张《Javascript高级程序设计》中的图来说明,虽然这张图并不完全说明所有情况。图中的activation object就是用于保存变量的对象。

 


简而言之,在Javascript中:

闭包:函数实例保存着在执行时所需要的变量的引用,而不会复制保存当时变量的值。(在Object C的实现中,我们可以选择保存当时的值或者是引用)

作用域链:解析变量时查找变量所在的方式,以var作为终止符号,如果链上一直没有var,则一直追溯到全局对象为止。

C#中的闭包特性是由编译器把局部变量转换成引用类型的对象成员实现的。

二、闭包的使用
 
下面通过一些具体例子来说明如何利用闭包这一特性:

1.闭包是在定义的时候产生的

function Foo(){ function A(){} function B(){} function C(){}}
我们每次执行Foo()的时候,都有有A,B,C这三个函数实例(闭包)产生,当Foo执行完毕,生成的实例没有其他引用,因此会被当成垃圾随之销毁(不一定是马上销毁)。
我们来证实一下作用域链是在函数定义时确定的,所以这里显示的应该是'local scope'

var scope = "global scope"; function checkscope() { var scope = "local scope"; function f() { return scope; } return f;}checkscope()()


同样道理:

(function(){ function A(){} function B(){} function C(){}}())
上面的表达式执行完后也会有A,B,C这三个函数实例(闭包)产生,因为这是一个立即执行的匿名函数,这三个闭包只能产生一次。生成的闭包没有其他引用,因此会被当成垃圾随之销毁(不一定是马上销毁)。

我们之所以这么写,目地有两个

1.避免污染全局对象

2.避免多次产生相同的函数实例

 

对比下面两个例子,闭包是如何保存作用域链的:

 function A(){} //比较省内存的写法,创建对象速度快,开销小 (function(prototype){ var name = "a"; function sayName () { alert(name); } function ChangeName() { name += "_changed" } prototype.sayName = sayName;//引用通过执行匿名函数产生的闭包,闭包只会产生一次 prototype.changeName = ChangeName; }(A.prototype)) var a1 = new A(); var a2 = new A();
 a1.sayName(); a1.changeName(); a2.sayName();


--------------------------------------------------------------------------------

 function B(){ //原型链比较短的做法,找到方法的速度快,但是比较耗内存,每次new 调用构造器都有2个函数实例和1个变量产生。 var name = "b"; function sayName () { alert(name); } function changeName() { name += "_changed"; } this.sayName = sayName;//引用闭包,每次调用函数B都会产生新的闭包 this.changeName = changeName; }//如果函数调用之前带有new关键字,则函数作为构造器使用。//本质上来说作为构造器和作为普通函数调用没区别。如果直接调用B(),那么this对象会绑定到全局对象,新生成的闭包会代替旧的闭包赋给全局对象的changeName和sayName属性上,因此旧的闭包会被当成垃圾回收。//如果作为构造器使用,new 关键字会生成一个新的对象(this指向这个新对象)并初始化这个新对象的sayName和changeName属性,因此每次生成的闭包都会因为有引用而保留下来。 var b1 = new B(); b1.sayName(); b1.changeName(); b1.sayName(); var b2 = new B(); b2.sayName(); b1.sayName();


三、泄漏问题:在编译语言中,函数体总在文件的代码段中,并在运行期被装入标志为可执行的内存区。事实上我们不认为函数自身会有生命周期。我们在大多数情况下会认为“引用类型的数据结构”具有生存周期和泄漏的问题,如指针、对象等。

JavaScript中内存的泄漏本质上就是定义函数时生成的保存局部变量的对象因为存在引用而不被当成垃圾被回收。

1.存在循环引用

2.有些对象总不能销毁,如IE6在DOM中的内存泄漏,或者在销毁时不能通知到Javascript引擎,因此也就有些Javascript闭包总不能被销毁。这些情况通常是发生在Javascript宿主对象和Javascript中原生对象沟通不畅导致。

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

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Apakah maksud penutupan dalam ungkapan lambda C++? Apakah maksud penutupan dalam ungkapan lambda C++? Apr 17, 2024 pm 06:15 PM

Dalam C++, penutupan ialah ungkapan lambda yang boleh mengakses pembolehubah luaran. Untuk membuat penutupan, tangkap pembolehubah luar dalam ungkapan lambda. Penutupan memberikan kelebihan seperti kebolehgunaan semula, penyembunyian maklumat dan penilaian malas. Ia berguna dalam situasi dunia sebenar seperti pengendali acara, di mana penutupan masih boleh mengakses pembolehubah luar walaupun ia dimusnahkan.

Bagaimana untuk melaksanakan penutupan dalam ungkapan C++ Lambda? Bagaimana untuk melaksanakan penutupan dalam ungkapan C++ Lambda? Jun 01, 2024 pm 05:50 PM

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.

Apakah kelebihan dan kekurangan penutupan dalam fungsi C++? Apakah kelebihan dan kekurangan penutupan dalam fungsi C++? Apr 25, 2024 pm 01:33 PM

Penutupan ialah fungsi bersarang yang boleh mengakses pembolehubah dalam skop fungsi luar Kelebihannya termasuk pengkapsulan data, pengekalan keadaan dan fleksibiliti. Kelemahan termasuk penggunaan memori, kesan prestasi dan kerumitan penyahpepijatan. Selain itu, penutupan boleh mencipta fungsi tanpa nama dan menyerahkannya kepada fungsi lain sebagai panggilan balik atau hujah.

Selesaikan masalah kebocoran memori yang disebabkan oleh penutupan Selesaikan masalah kebocoran memori yang disebabkan oleh penutupan Feb 18, 2024 pm 03:20 PM

Tajuk: Kebocoran memori disebabkan oleh penutupan dan penyelesaian Pengenalan: Penutupan ialah konsep yang sangat biasa dalam JavaScript, yang membenarkan fungsi dalaman mengakses pembolehubah fungsi luaran. Walau bagaimanapun, penutupan boleh menyebabkan kebocoran memori jika digunakan secara tidak betul. Artikel ini akan meneroka masalah kebocoran memori yang disebabkan oleh penutupan dan menyediakan penyelesaian serta contoh kod khusus. 1. Kebocoran memori disebabkan oleh penutupan Ciri penutupan ialah fungsi dalaman boleh mengakses pembolehubah fungsi luaran, yang bermaksud pembolehubah yang dirujuk dalam penutupan tidak akan dikumpul sampah. Jika digunakan secara tidak betul,

Kesan penunjuk fungsi dan penutupan pada prestasi Golang Kesan penunjuk fungsi dan penutupan pada prestasi Golang Apr 15, 2024 am 10:36 AM

Kesan penunjuk fungsi dan penutupan pada prestasi Go adalah seperti berikut: Penunjuk fungsi: Lebih perlahan sedikit daripada panggilan langsung, tetapi meningkatkan kebolehbacaan dan kebolehgunaan semula. Penutupan: Biasanya lebih perlahan, tetapi merangkumi data dan tingkah laku. Kes praktikal: Penunjuk fungsi boleh mengoptimumkan algoritma pengisihan dan penutupan boleh mencipta pengendali acara, tetapi ia akan membawa kerugian prestasi.

Panggilan berantai dan penutupan fungsi PHP Panggilan berantai dan penutupan fungsi PHP Apr 13, 2024 am 11:18 AM

Ya, kesederhanaan dan kebolehbacaan kod boleh dioptimumkan melalui panggilan berantai dan penutupan: panggilan berantai memaut fungsi panggilan ke antara muka yang lancar. Penutupan mewujudkan blok kod yang boleh digunakan semula dan pembolehubah akses di luar fungsi.

Bagaimanakah penutupan dilaksanakan di Jawa? Bagaimanakah penutupan dilaksanakan di Jawa? May 03, 2024 pm 12:48 PM

Penutupan dalam Java membenarkan fungsi dalaman mengakses pembolehubah skop luar walaupun fungsi luar telah keluar. Dilaksanakan melalui kelas dalaman tanpa nama, kelas dalam memegang rujukan kepada kelas luar dan memastikan pembolehubah luar aktif. Penutupan meningkatkan fleksibiliti kod, tetapi anda perlu sedar tentang risiko kebocoran memori kerana rujukan kepada pembolehubah luaran oleh kelas dalaman tanpa nama memastikan pembolehubah tersebut hidup.

Peranan penutupan fungsi golang dalam pengujian Peranan penutupan fungsi golang dalam pengujian Apr 24, 2024 am 08:54 AM

Penutupan fungsi bahasa Go memainkan peranan penting dalam ujian unit: Menangkap nilai: Penutupan boleh mengakses pembolehubah dalam skop luar, membenarkan parameter ujian ditangkap dan digunakan semula dalam fungsi bersarang. Permudahkan kod ujian: Dengan menangkap nilai, penutupan memudahkan kod ujian dengan menghapuskan keperluan untuk menetapkan parameter berulang kali untuk setiap gelung. Tingkatkan kebolehbacaan: Gunakan penutupan untuk mengatur logik ujian, menjadikan kod ujian lebih jelas dan lebih mudah dibaca.

See all articles