《JavaScript面向對象精要》之六:對象模式

6.1 私有成員和特權成員

JavaScript 對象的全部屬性都是公有的,沒有顯式的方法指定某個屬性不能被外界訪問。安全

6.1.1 模塊模式

模塊模式是一種用於建立擁有私有數據的單件對象的模式。 基本作法是使用當即調用函數表達式(IIFE)來返回一個對象。原理是利用閉包。閉包

var yourObj = (function(){
  // private data variables

  return {
    // public methods and properties
  }
}());
複製代碼

模塊模式還有一個變種叫暴露模塊模式,它將全部的變量和方法都放在 IIFE 的頭部,而後將它們設置到須要被返回的對象上。ide

// 通常寫法
var yourObj = (function(){
  var age = 25;

  return {
    name: "Ljc",

    getAge: function(){
      return age;
    }
  }
}());


// 暴露模塊模式
var yourObj = (function(){
  var age = 25;
  function getAge(){
    return age;
  };
  return {
    name: "Ljc",
    getAge: getAge
  }
}());
複製代碼

6.1.2 構造函數的私有成員(不能經過對象直接訪問)

模塊模式在定義單個對象的私有屬性十分有效,但對於那些一樣須要私有屬性的自定義類型呢?你能夠在構造函數中使用相似的模式來建立每一個實例的私有數據。函數

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
複製代碼

這裏有個問題:若是你須要對象實例擁有私有數據,就不能將相應方法放在 prototype 上。ui

若是你須要全部實例共享私有數據。則可結合模塊模式和構造函數,以下:this

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 混入

這是一種僞繼承。一個對象在不改變原型對象鏈的狀況下獲得了另一個對象的屬性被稱爲「混入」。所以,和繼承不一樣,混入讓你在建立對象後沒法檢查屬性來源。 純函數實現:spa

function mixin(receiver, supplier){
  for(var property in supplier){
    if(supplier.hasOwnProperty(property)){
      receiver[property] = supplier[property];
    }
  }
}
複製代碼

這是淺拷貝,若是屬性的值是一個引用,那麼二者將指向同一個對象。prototype

6.3 做用域安全的構造函數

構造函數也是函數,因此不用 new 也能調用它們來改變 this 的值。設計

在非嚴格模式下, this 被強制指向全局對象。code

而在嚴格模式下,構造函數會拋出一個錯誤(由於嚴格模式下沒有爲全局對象設置 thisthis 保持爲 undefined)。

而不少內建構造函數,例如 ArrayRegExp 不須要 new 也能正常工做,這是由於它們被設計爲做用域安全的構造函數。

當用 new 調用一個函數時,this 指向的新建立的對象是屬於該構造函數所表明的自定義類型。所以,可在函數內用 instanceof 檢查本身是否被 new 調用。

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);
  }
}
複製代碼
相關文章
相關標籤/搜索