6.1 私有成員和特權(quán)成員
JavaScipt 對象的所有屬性都是公有的,沒有顯式的方法指定某個屬性不能被外界訪問。
6.1.1 模塊模式
模塊模式是一種用于創(chuàng)建擁有私有數(shù)據(jù)的單件對象的模式。
基本做法是使用立即調(diào)用函數(shù)表達(dá)式(IIFE)來返回一個對象。原理是利用閉包。
var yourObj = (function(){
// private data variables
return {
// public methods and properties
}
}());
模塊模式還有一個變種叫暴露模塊模式,它將所有的變量和方法都放在 IIFE
的頭部,然后將它們設(shè)置到需要被返回的對象上。
// 一般寫法
var yourObj = (function(){
var age = 25;
return {
name: "Ljc",
getAge: function(){
return agel
}
}
}());
// 暴露模塊模式
var yourObj = (function(){
var age = 25;
function getAge(){
return agel
};
return {
name: "Ljc",
getAge: getAge
}
}());
6.1.2 構(gòu)造函數(shù)的私有成員(不能通過對象直接訪問)
模塊模式在定義單個對象的私有屬性十分有效,但對于那些同樣需要私有屬性的自定義類型呢?你可以在構(gòu)造函數(shù)中使用類似的模式來創(chuàng)建每個實例的私有數(shù)據(jù)。
function Person(name){
// define a variable only accessible inside of the Person constructor
var age = 22;
this.name = name;
this.getAge = function(){
return age;
};
this.growOlder = function(){
age++;
}
}
var person = new Person("Ljc");
console.log(person.age); // undefined
person.age = 100;
console.log(person.getAge()); // 22
person.growOlder();
console.log(person.getAge()); // 23
這里有個問題:如果你需要對象實例擁有私有數(shù)據(jù),就不能將相應(yīng)方法放在 prototype
上。
如果你需要所有實例共享私有數(shù)據(jù)。則可結(jié)合模塊模式和構(gòu)造函數(shù),如下:
var Person = (function(){
var age = 22;
function InnerPerson(name){
this.name = name;
}
InnerPerson.prototype.getAge = function(){
return age;
}
InnerPerson.prototype.growOlder = function(){
age++;
};
return InnerPerson;
}());
var person1 = new Person("Nicholash");
var person2 = new Person("Greg");
console.log(person1.name); // "Nicholash"
console.log(person1.getAge()); // 22
console.log(person2.name); // "Greg"
console.log(person2.getAge()); // 22
person1.growOlder();
console.log(person1.getAge()); // 23
console.log(person2.getAge()); // 23
6.2 混入
這是一種偽繼承。一個對象在不改變原型對象鏈的情況下得到了另外一個對象的屬性被稱為“混入”。因此,和繼承不同,混入讓你在創(chuàng)建對象后無法檢查屬性來源。
純函數(shù)實現(xiàn):
function mixin(receiver, supplier){
for(var property in supplier){
if(supplier.hasOwnProperty(property)){
receiver[property] = supplier[property];
}
}
}
這是淺拷貝,如果屬性的值是一個引用,那么兩者將指向同一個對象。
6.3 作用域安全的構(gòu)造函數(shù)
構(gòu)造函數(shù)也是函數(shù),所以不用 new 也能調(diào)用它們來改變 this
的值。在非嚴(yán)格模式下, this
被強制指向全局對象。而在嚴(yán)格模式下,構(gòu)造函數(shù)會拋出一個錯誤(因為嚴(yán)格模式下沒有為全局對象設(shè)置 this
,this
保持為 undefined
)。
而很多內(nèi)建構(gòu)造函數(shù),例如 Array
、RegExp
不需要 new
也能正常工作,這是因為它們被設(shè)計為作用域安全的構(gòu)造函數(shù)。
當(dāng)用 new
調(diào)用一個函數(shù)時,this
指向的新創(chuàng)建的對象是屬于該構(gòu)造函數(shù)所代表的自定義類型。因此,可在函數(shù)內(nèi)用 instanceof
檢查自己是否被 new
調(diào)用。
function Person(name){
if(this instanceof Person){
// called with "new"
}else{
// called without "new"
}
}
具體案例:
function Person(name){
if(this instanceof Person){
this.name = name;
}else{
return new Person(name);
}
}