JavaScript 閉包介紹
閉包
閉包是JavaScript中最強大的特性之一。JavaScript允許函式嵌套,並且內部函式可以訪問定義在外部函式中的所有變數和函式,以及外部函式能訪問的所有變數和函式。但是,外部函式卻不能夠訪問定義在內部函式中的變數和函式。這給內部函式的變數提供了一定的安全性。而且,當內部函式生存週期大於外部函式時,由於內部函式可以訪問外部函式的作用域,定義在外部函式的變數和函式的生存週期就會大於外部函式本身。當內部函式以某一種方式被任何一個外部函式作用域訪問時,一個閉包就產生了。
var pet = function(name) { // The outer function defines a variable called "name"
var getName = function() {
// The inner function has access to the "name" variable of the outer function
return name;
}
// Return the inner function, thereby exposing it to outer scopes
return getName;
},
myPet = pet("Vivie");
myPet(); // Returns "Vivie"
實際上可能會比上面的程式碼複雜的多。在下面這種情形中,返回了一個包含可以操作外部函式的內部變數方法的物件。
var createPet = function(name) {
var sex;
return {
setName: function(newName) {
name = newName;
},
getName: function() {
return name;
},
getSex: function() {
return sex;
},
setSex: function(newSex) {
if(typeof newSex == "string"
&& (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
sex = newSex;
}
}
}
}
var pet = createPet("Vivie");
pet.getName(); // Vivie
pet.setName("Oliver");
pet.setSex("male");
pet.getSex(); // male
pet.getName(); // Oliver
在上面的程式碼中,外部函式的name變數對內嵌函式來說是可取得的,而除了通過內嵌函式本身,沒有其它任何方法可以取得內嵌的變數。內嵌函式的內嵌變數就像內嵌函式的保險櫃。它們會為內嵌函式保留「穩定」——而又安全——的資料參與執行。而這些內嵌函式甚至不會被分配給一個變數,或者不必一定要有名字。
var getCode = (function(){
var secureCode = "0]Eal(eh&2"; // A code we do not want outsiders to be able to modify...
return function () {
return secureCode;
};
})();
getCode(); // Returns the secret code
儘管有上述優點,使用閉包時仍然要小心避免一些陷阱。如果一個閉包的函式用外部函式的變數名定義了同樣的變數,那在外部函式域將再也無法指向該變數。
var createPet = function(name) { // Outer function defines a variable called "name"
return {
setName: function(name) { // Enclosed function also defines a variable called "name"
name = name; // ??? How do we access the "name" defined by the outer function ???
}
}
}
閉包中的神奇變數this是非常詭異的。使用它必須十分的小心,因為this指代什麼完全取決於函式在何處被呼叫,而不是在何處被定義。一篇絕妙而詳盡的關於閉包的文章可以在這裡找到。
閉包是JavaScript中最強大的特性之一。JavaScript允許函式嵌套,並且內部函式可以訪問定義在外部函式中的所有變數和函式,以及外部函式能訪問的所有變數和函式。但是,外部函式卻不能夠訪問定義在內部函式中的變數和函式。這給內部函式的變數提供了一定的安全性。而且,當內部函式生存週期大於外部函式時,由於內部函式可以訪問外部函式的作用域,定義在外部函式的變數和函式的生存週期就會大於外部函式本身。當內部函式以某一種方式被任何一個外部函式作用域訪問時,一個閉包就產生了。
var pet = function(name) { // The outer function defines a variable called "name"
var getName = function() {
// The inner function has access to the "name" variable of the outer function
return name;
}
// Return the inner function, thereby exposing it to outer scopes
return getName;
},
myPet = pet("Vivie");
myPet(); // Returns "Vivie"
實際上可能會比上面的程式碼複雜的多。在下面這種情形中,返回了一個包含可以操作外部函式的內部變數方法的物件。
var createPet = function(name) {
var sex;
return {
setName: function(newName) {
name = newName;
},
getName: function() {
return name;
},
getSex: function() {
return sex;
},
setSex: function(newSex) {
if(typeof newSex == "string"
&& (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
sex = newSex;
}
}
}
}
var pet = createPet("Vivie");
pet.getName(); // Vivie
pet.setName("Oliver");
pet.setSex("male");
pet.getSex(); // male
pet.getName(); // Oliver
在上面的程式碼中,外部函式的name變數對內嵌函式來說是可取得的,而除了通過內嵌函式本身,沒有其它任何方法可以取得內嵌的變數。內嵌函式的內嵌變數就像內嵌函式的保險櫃。它們會為內嵌函式保留「穩定」——而又安全——的資料參與執行。而這些內嵌函式甚至不會被分配給一個變數,或者不必一定要有名字。
var getCode = (function(){
var secureCode = "0]Eal(eh&2"; // A code we do not want outsiders to be able to modify...
return function () {
return secureCode;
};
})();
getCode(); // Returns the secret code
儘管有上述優點,使用閉包時仍然要小心避免一些陷阱。如果一個閉包的函式用外部函式的變數名定義了同樣的變數,那在外部函式域將再也無法指向該變數。
var createPet = function(name) { // Outer function defines a variable called "name"
return {
setName: function(name) { // Enclosed function also defines a variable called "name"
name = name; // ??? How do we access the "name" defined by the outer function ???
}
}
}
閉包中的神奇變數this是非常詭異的。使用它必須十分的小心,因為this指代什麼完全取決於函式在何處被呼叫,而不是在何處被定義。一篇絕妙而詳盡的關於閉包的文章可以在這裡找到。
留言
張貼留言