6.1 私有成員和特權(quán)成員
JavaScipt 對象的所有屬性都是公有的玄括,沒有顯式的方法指定某個(gè)屬性不能被外界訪問僧著。
6.1.1 模塊模式
模塊模式是一種用于創(chuàng)建擁有私有數(shù)據(jù)的單件對象的模式锥惋。
基本做法是使用立即調(diào)用函數(shù)表達(dá)式(IIFE)來返回一個(gè)對象屋群。原理是利用閉包。
var yourObj = (function(){
// private data variables
return {
// public methods and properties
}
}());
模塊模式還有一個(gè)變種叫暴露模塊模式您宪,它將所有的變量和方法都放在 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è)對象的私有屬性十分有效宪巨,但對于那些同樣需要私有屬性的自定義類型呢磷杏?你可以在構(gòu)造函數(shù)中使用類似的模式來創(chuàng)建每個(gè)實(shí)例的私有數(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
這里有個(gè)問題:如果你需要對象實(shí)例擁有私有數(shù)據(jù)揖铜,就不能將相應(yīng)方法放在 prototype
上茴丰。
如果你需要所有實(shí)例共享私有數(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 混入
這是一種偽繼承贿肩。一個(gè)對象在不改變原型對象鏈的情況下得到了另外一個(gè)對象的屬性被稱為“混入”。因此龄寞,和繼承不同汰规,混入讓你在創(chuàng)建對象后無法檢查屬性來源。
純函數(shù)實(shí)現(xiàn):
function mixin(receiver, supplier){
for(var property in supplier){
if(supplier.hasOwnProperty(property)){
receiver[property] = supplier[property];
}
}
}
這是淺拷貝物邑,如果屬性的值是一個(gè)引用溜哮,那么兩者將指向同一個(gè)對象滔金。
6.3 作用域安全的構(gòu)造函數(shù)
構(gòu)造函數(shù)也是函數(shù),所以不用 new 也能調(diào)用它們來改變 this
的值茂嗓。在非嚴(yán)格模式下餐茵, this
被強(qiáng)制指向全局對象。而在嚴(yán)格模式下述吸,構(gòu)造函數(shù)會拋出一個(gè)錯(cuò)誤(因?yàn)閲?yán)格模式下沒有為全局對象設(shè)置 this
忿族,this
保持為 undefined
)。
而很多內(nèi)建構(gòu)造函數(shù)蝌矛,例如 Array
道批、RegExp
不需要 new
也能正常工作,這是因?yàn)樗鼈儽辉O(shè)計(jì)為作用域安全的構(gòu)造函數(shù)入撒。
當(dāng)用 new
調(diào)用一個(gè)函數(shù)時(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);
}
}