javascript是基於對象的一門語言,沒有想java等語言那樣子擁有封裝的特性。可是javascript能夠經過閉包來進行模擬。javascript
一、構造函數與私有成員java
能夠用構造函數造成一個閉包,實現內部成員的私有化。閉包
function Person(){
//私有成員
var country = 'cn';
//特權方法
this.getCountry = function(){
return country;
}
}
var man1 = new Person();
var man2 = new Person();
console.log(man1.country );//undefined
console.log(man2.country );//undefined
console.log( man1.getCountry() );//'cn'
console.log( man2.getCountry() );//'cn'函數
這個例子在內存中應該是這個樣子的:this
也就是每實例化一次,都會建立私有成員。spa
man2.country之因此爲undefined,是由於country不是對象的屬性而是私有屬性。因此沒法經過這種原型鏈的方式去訪問到,因此就是該對象沒有這個屬性。prototype
man2.getCountry()之因此能訪問到,那就是由於閉包了。由於Person構造函數在運行完以後還有一個man2.getCountry()存在,因此不會將其做用域從內存中刪除--從而造成了一個閉包。當運行man2.getCountry這條語句到return country;時,因爲本身的做用域中並無country這個屬性。因此順着做用域鏈往上找。在上一級的做用域中找到而後返回。code
二、對象字面量與私有性對象
原理和第一種同樣,只是寫法上不一樣。blog
var obj; (function(){ //私有成員 var name = 'quan'; //公共成員部分 obj = { getName: function(){ return name; } } }()) console.log( obj.getName() );//'quan'
或者下面:
var obj = (function(){ //私有成員 var name = 'quan'; //公共成員部分 return { getName: function(){ return name; } }; }()) console.log( obj.getName() );//'quan'
三、原型和私有性
以上的兩種方法,都有一個共同的問題,就是沒實例化一個對象都會建立一次私有成員。那有沒有一種方法,能夠將一些經常使用的私有成員只建立一次呢。答案就是利用原型。原型prototype也是一個對象是函數的一個屬性;是利用構造函數實例化一個對象以後,對象的一個屬性__proto__。
function Person(){ // } Person.prototype = (function(){ //原型中的私有成員 var country = 'cn'; //原型中的公有成員 return { getCountry: function(){ return country; } } }()) var man1 = new Person(); var man2 = new Person(); console.log(man1.country);//undefined console.log(man2.country);//undefined console.log( man1.getCountry() );//'cn' console.log( man2.getCountry() );//'cn'
內存狀況以下圖的第二部分。第一部分爲第一種狀況。能夠看到,和第一種比,會減小一些內存。
第1、第二個console.log爲undefined緣由和第一種狀況是同樣的。
第3、第四個log輸出的緣由就稍稍有點不一樣。首先,man1沒有getCountry這個方法,因此沿着原型鏈在上一級的原型中找到getCountry方法而後調用getCountry方法。而後後面的部分就和第一種同樣的原理了。就是閉包了。
可是這第三種方法也是有缺點的。那就是訪問時要順着原型鏈向上找,若是原型鏈很長,那也會變慢。