javascript中的私有變數及如何在函式外部引用這些變數
私有變數
任何在函式中定義的變數,都可認為是私有變數,因為不能在函式外部訪問這些變數。私有變數包括函式的引數、區域性變數、在函式內部定義的其它函式。
如下程式碼:
function add(bum1,num2){
var sum=num1+num2;
return sum;
}
在這個函式中,有3個私有變數:num1、num2、sum。在函式內部可以訪問這些私有變數,但是在函式外部不能訪問它們。
如果再這個函式內部建立一個閉包,那麼這個閉包也可以通過作用域鏈訪問到這些變數。利用這一點,就可以建立訪問私有變數的共有方法。我們把有權訪問私有變數和私有函式的公共方法稱為特權方法。
在物件中建立特權方法的方式:
方式一:在建構函式中定義特權方法:
如下面例項:
function myObject(){
var privateVariable=10;
function privateFunction(){
return false;
}
// 特權方法
this.publicMethod=function () {
privateVariable++;
return privateFunction();
}
}
var age=new myObject();
alert(age.publicMethod());//false
這種模式在建構函式中定義了所有私有變數和函式。能夠在建構函式中定義特權方法是因為特權方法作為閉包,能夠訪問在建構函式中定義的所有變數和函式。
利用私有和特權成員能夠隱藏那些不應該被直接修改的資料。
function Person(name){
this.getName=function(){
return name;
};
this.setName=function(value){
name=value;
};
}
var person=new Person('Lee');
alert(person.getName());//'Lee'
person.setName('lwf');
alert(person.getName());//'lwf'
私有變數name在Person的每個例項中都不相同,因為每次呼叫建構函式都會重新建立這兩個方法。不過,在函式中定義特權方法也有一個缺點,就是你必須使用建構函式來達到這個目的。
建構函式模式的缺點就是針對每個例項都會建立同樣一組新方法,而使用靜態私有變數來實現特權方法就可以避免這個問題。
方式二:使用靜態私有變數來實現特權方法:
(function(){
var privateVariable=10;
function privateFunction(){
return false;
}
//建構函式
MyObject=function(){
};
//公有/特權方法
MyObject.prototype.publicMethod=function(){
privateVariable++;
return privateFunction();
}
})();
這種模式建立了一個私有作用域,並在其中封裝了一個建構函式及其相應方法。共有方法是在原型的基礎上定義的,這一點體現了典型的原型模式。需要注意的是,這種模式在定義建構函式時,並沒使用函式宣告,而是使用了函式表示式。函式宣告只能建立區域性函式,但那並不是我們想要的。出於同樣的原因,我們也沒有在宣告MyObject時使用var關鍵字。記住:初始化未經宣告的變數,總會建立一個全域性變數。因此,MyObject就是一個全域性變數,能夠在私有作用域外被訪問到。但也要知道,在嚴格模式下,給未經宣告的變數賦值會導致錯誤。
這種模式與在建構函式中定義特權方法的主要區別就在於變數和函式是由例項共享的,由於特權方法就是在原型的基礎上定義的,因此所有例項都是用同一個函式。而這個特權方法,作為一個閉包,總是儲存著對包含作用域的引用。
如:
(function(){
var name='';
Person=function(value){
name=value;
};
Person.prototype.getName=function(){
return name;
};
Person.prototype.setName=function(value){
name=value;
}
})();
var person1=new Person('Lee');
console.log(person1.getName());
person1.setName('lwf');
console.log(person1.getName());
var person2=new Person('aaa');
console.log(person2.getName());
console.log(person1.getName());
person2.setName('bbb');
console.log(person2.getName());
console.log(person1.getName());
結果為:
在這個例子中Person建構函式與getName()和setName()方法一樣,都有權訪問私有變數name,在這種模式下,變數name就是一個靜態的、由所有例項共享的屬性。也就是說,在一個例項中,呼叫setName()會影響所有例項,而呼叫setName()或者新建一個Person例項就會賦予name 一個新值。結果就是所有例項返回相同的值。
有這種方式建立靜態私有變數會因為使用原型而增進程式碼複用,但每個例項都沒有自己的私有變數。到底是使用例項變數還是靜態私有變數還是要看你的具體需求而定。