Rumah >hujung hadapan web >tutorial js >Memahami kemahiran closures_javascript javascript

Memahami kemahiran closures_javascript javascript

WBOY
WBOYasal
2016-05-16 16:06:161119semak imbas

1. Mula-mula kita perlu tahu rantai skop pembolehubah

Terdapat dua jenis skop pembolehubah: pembolehubah global dan pembolehubah tempatan. Pembolehubah yang tidak ditakrifkan dalam mana-mana fungsi ialah pembolehubah global, dan pembolehubah yang ditakrifkan dalam fungsi ialah pembolehubah tempatan Ambil perhatian bahawa anda mesti menggunakan kata kunci var apabila mentakrifkan pembolehubah dalam fungsi tanpa kata kunci var adalah pembolehubah global.

Setiap bahagian kod dalam JavaScript mempunyai rantai skop yang berkaitan. Rantaian skop ini ialah senarai objek atau senarai terpaut yang mentakrifkan pembolehubah dalam "skop" bahagian kod ini. Skop kod peringkat atas terdiri daripada pembolehubah global; rantaian skop yang tidak termasuk fungsi bersarang mempunyai dua objek: satu ialah objek parameter fungsi yang ditentukan dan pembolehubah tempatan, dan satu lagi ialah objek pembolehubah global; skop fungsi bersarang Rantaian mempunyai tiga objek: parameter fungsi dan pembolehubah tempatan - parameter fungsi luaran dan pembolehubah tempatan - pembolehubah global. Fungsi boleh mengakses objek pada rantai skop, jadi fungsi boleh mengakses pembolehubah global, tetapi bukan sebaliknya, iaitu pembolehubah tempatan dalam fungsi tidak boleh diakses dari luar fungsi.

var a=1;
function wai(){
  alert(a);        
  var m=10;
  n=20;
}

wai();          //=> 1; 函数内部可以访问全局变量
alert(m);        //=> error; 外部访问函数局部变量报错  
alert(n);        //=> 20; 函数内部定义的变量未使用var关键字,所以是全局变量,外部可以访问

2. Cara membaca pembolehubah setempat secara luaran

Kadangkala, kita perlu mengakses pembolehubah setempat dalam fungsi dari luar Dalam kes ini, kita perlu menggunakan penyelesaian. Kami menggunakan ciri-ciri skop pembolehubah JavaScript untuk mentakrifkan sub-fungsi di dalam fungsi dan sub-fungsi boleh mengakses pembolehubah dalam fungsi induk

function wai(){
 var m=10;
  function nei(){
    alert(m); 
 }
  return nei;
}

var f = wai();
nei();              //=> error; nei()函数是一个局部变量,在外部不能访问
f();               //=> 10;

3. Penutupan

Fungsi nei() dalam kod sebelumnya ialah penutupan Seperti yang dapat dilihat dari di atas, penutupan ialah fungsi yang boleh membaca pembolehubah tempatan di dalam fungsi , ia boleh dianggap sebagai fungsi di dalam dan di luar fungsi Jambatan yang menghubungkan bahagian luar bersama-sama.

Penutupan mempunyai dua fungsi:

Pertama, seperti yang dinyatakan sebelum ini, anda boleh membaca pembolehubah di dalam fungsi

Kedua, pembolehubah tempatan ini boleh disimpan dalam ingatan untuk merealisasikan perkongsian data pembolehubah

function wai(){
  var m=99;
  function nei(){
    alert(m);
    m++;
  }
  return nei;
}
      
var f= wai();
f();         //=> 99;
f();         //=> 100;
f();         //=> 101;

Dalam contoh di atas, apabila fungsi wai() sedang berjalan, pembolehubah m disimpan dalam memori Nilai m boleh dibaca dengan melaksanakan f(), tetapi amaran langsung(m) tidak boleh!

Kami juga boleh menghantar parameter kepada fungsi penutupan Seperti yang ditunjukkan dalam contoh berikut, fungsi tanpa nama ditakrifkan dan fungsi penutupan dikembalikan i kenaikan;

var wai=(function(){
  var i=0;
  return function(num){
    num+=i;
    alert(num);
    i++;
 }
})();
wai(1);//1
wai(2);//3
wai(3);//5
Untuk memahami penutupan dengan lebih mendalam, mari lihat contoh berikut:

Sekarang saya ingin mentakrifkan fungsi yang mengembalikan tatasusunan, dan setiap elemen tatasusunan ialah fungsi, dan setiap fungsi akan muncul nilai indeks yang sepadan

Kami mungkin menulis seperti ini

function box(){
 var arr=[];
  for(i=0;i<5;i++){
    arr[i]=function(){return i;}
  }
 return arr;  
}
var a=box();
alert(a);        //=>包含五个函数体的数组
alert(a[0]());     //=> 5;
alert(a[1]());    //=> 5;
Kod di atas mendapati bahawa semua tetingkap timbul ialah 5, bukan 0,1,2,3,4 seperti yang kami jangkakan Ini kerana i juga merupakan pembolehubah tempatan yang wujud dalam ingatan ]() Pada masa itu, nilai i sudah 5, dan nilai i terus meningkat semasa keseluruhan proses menjalankan fungsi box().

Penyelesaian: Pelaksanaan penutupan

function box(){
var arr=[];
    for(var i=0;i<5;i++){

         arr[i]=(function(num){
           return function(){return num;}
         })(i);

     }
return arr;     
}

var arr=box();

for(var i=0;i<5;i++){

  alert(arr[i]());//0,1,2,3,4
}

4. Perkara yang perlu diambil perhatian apabila menggunakan penutup

1) Memandangkan penutupan akan menyebabkan pembolehubah dalam fungsi disimpan dalam memori, yang menggunakan banyak memori, penutupan tidak boleh disalahgunakan, jika tidak, ia akan menyebabkan masalah prestasi pada halaman web, dan boleh menyebabkan kebocoran memori dalam IE. Penyelesaiannya adalah untuk memadam semua pembolehubah tempatan yang tidak digunakan sebelum keluar dari fungsi.

2) Penutupan akan menukar nilai pembolehubah di dalam fungsi induk di luar fungsi induk. Oleh itu, jika anda menggunakan fungsi induk sebagai objek, penutupan sebagai kaedah awamnya, dan pembolehubah dalaman sebagai nilai peribadinya, anda mesti berhati-hati untuk tidak mengubah nilai pembolehubah fungsi induk.

5. Berikut ialah beberapa soalan tentang penutupan

Jika anda boleh memahami keputusan kod berikut, anda harus memahami mekanisme operasi penutupan.

Kod Js


var name = "The Window"; 
var object = { 
  name : "My Object", 
  getNameFunc : function(){ 
    return function(){ 
      return this.name;       //=>嵌套函数的this为全局变量或undefined,不会继承父函数的this
    }; 
  } 
}; 
alert(object.getNameFunc()()); //The Window
Sebab mengapa output di atas ialah "Tetingkap" adalah kerana ini dalam fungsi bersarang tidak mewarisi fungsi induk ini, dan nilainya ialah pembolehubah global atau tidak ditentukan (di bawah ECMAScript5), jadi apa yang dikembalikan ialah nama pembolehubah objek global. Jika anda mahu ia mengembalikan atribut nama objek, kodnya adalah seperti berikut:

var name = "The Window"; 
   var object = { 
    name : "My Object", 
    getNameFunc : function(){ 
      var cur=this;
      return function(){ 
        return cur.name;
      }; 
    } 
  }; 
  alert(object.getNameFunc()()); //=》My Object
Kod di atas memperuntukkan objek fungsi induk ini kepada pembolehubah cur, dan fungsi bersarangnya boleh mengakses sifatnya melalui pembolehubah cur

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

Contoh penutupan JavaScript

function outerFun()
{
var a=0;
function innerFun()
{
a++;
alert(a);
} 
}
innerFun();  //=>error
Kod di atas adalah salah Skop innerFun() berada di dalam outerFun(), dan adalah salah untuk memanggilnya di luar outerFun().

ditukar kepada yang berikut, iaitu penutupan:

Kod Js

function outerFun()
{
   var a=0;
  function innerFun()
  {
    a++;
    alert(a);
  }
  return innerFun; //注意这里
}
var obj=outerFun();
obj(); //结果为1
obj(); //结果为2
var obj2=outerFun();
obj2(); //结果为1
obj2(); //结果为2

什么是闭包:

当内部函数 在定义它的作用域 的外部 被引用时,就创建了该内部函数的闭包 ,如果内部函数引用了位于外部函数的变量,当外部函数调用完毕后,这些变量在内存不会被 释放,因为闭包需要它们.

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

再来看一个例子

Js代码

function outerFun()
{
   var a =0;
   alert(a); 
}
var a=4;
outerFun();   //=> 0
alert(a);      //=> 4

结果是 0,4 . 因为在函数内部使用了var关键字 维护a的作用域在outFun()内部.

再看下面的代码:

Js代码

function outerFun()
{
//没有var 
a =0;
alert(a); 
}
var a=4;
outerFun();    //=> 0
alert(a);      //=> 0

结果为 0,0 真是奇怪,为什么呢?

作用域链是描述一种路径的术语,沿着该路径可以确定变量的值 .当执行a=0时,因为没有使用var关键字,因此赋值操作会沿着作用域链到var a=4; 并改变其值.

Kenyataan:
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