高程3總結#第6章面向對象的程序設計

面向對象的程序設計

理解對象

屬性類型

  • 建立自定義對象的最簡單方式就是建立一個Object的實例,而後再爲它添加屬性和方法javascript

    var person=new Object();
    person.name="Nicholas";
    person.age=20;
    person.job="Software Engineer";
    person.sayName=function(){
      alert(this.name)
    }
  • 對象字面量稱爲建立這種對象的首選方式java

    var person={
      name:"Nicholas",
      age:20,
      job:"Software Engineer",
      sayName:function(){
        alert(this.name);
      }
    };
  • 兩種屬性函數

    • 數據屬性,能夠讀取和寫入值,有四個描述其行爲的特性測試

      • [[Configurable]]表示可否經過delete刪除屬性從而從新定義屬性,可否修改屬性的特性,或者可否把屬性修改成訪問器屬性,特性默認值爲true
      • [[Enumerable]]表示可否經過for-in循環返回屬性,特性默認值爲true
      • [[Writable]]表示可否修改屬性的值,特性默認值爲true
      • [[Value]]包含這個屬性的數據值,讀取屬性值的時候,從這個位置讀,寫入屬性值的時候,把新值保存在這個位置,特性默認值是undefined
      • 要修改屬性默認的特性,使用Object.definePropery()方法,這個方法接收三個參數:屬性所在的對象、屬性的名字和一個描述符對象。this

        var person={};
        Object.definePropery(person,"name",{
          writable:false,
          value:"Nicholas"
        });
        alert(person.name);//"Nicholas"
        person.name="Greg";
        alert(person.name);//"Nicholas"
    • 訪問器屬性,包含一對getter和setter函數。在讀取訪問器屬性的時候,會調用getter函數,這個函數負責返回有效的值。在寫入訪問器屬性的時候,會調用setter函數並傳入新值,這個函數負責決定如何處理數據。spa

      • [[Configurable]]表示可否經過delete刪除屬性從而從新定義屬性,可否修改屬性的特性,或者可否把屬性修改成數據屬性,特性默認值爲true
      • [[Enumerable]]表示可否經過for-in循環返回屬性,特性默認值爲true
      • [[Get]]在讀取屬性時調用的函數,默認值爲undefined
      • [[Set]]在寫入屬性時調用的函數,默認值爲undefined
      • 訪問器屬性不能直接定義,必須使用Object.defineProperty()來定義

定義多個屬性

  • Object.defineProperties()方法能夠經過描述符一次定義多個屬性,這個方法接收兩個對象參數,一個對象是要添加和修改其屬性的對象,第二個對象的屬性與第一個對象中要添加或修改的屬性一一對應prototype

    var book = {};
    Object.defineProperties(book, {
      _year: {
        value: 2004
      },
      edition: {
        value: 1
      },
      year: {
        get: function(){
          return this._year;
        },
        set: function(newValue){
          if (newValue > 2004) {
            this._year = newValue;
            this.edition += newValue - 2004;
          }
        }
      }
    });

讀取屬性的特性

  • Object.getOwnPropertyDescription()方法,能夠取得給定屬性的描述符,這個方法接收兩個參數,屬性所在的對象和要讀取其描述符的屬性名稱設計

    var book = {};
    Object.defineProperties(book, {
      _year: {
        value: 2004
      },
      edition: {
        value: 1
      },
      year: {
        get: function(){
          return this._year;
        },
        set: function(newValue){
          if (newValue > 2004) {
            this._year = newValue;
            this.edition += newValue - 2004;
          }
        }
      }
    });
    var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
    alert(descriptor.value); //2004
    alert(descriptor.configurable); //false
    alert(typeof descriptor.get); //"undefined"
    var descriptor = Object.getOwnPropertyDescriptor(book, "year");
    alert(descriptor.value); //undefined
    alert(descriptor.enumerable); //false
    alert(typeof descriptor.get); //"function"

建立對象

工廠模式

function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
  alert(this.name);
};
return o;
}
var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");

構造函數模式

function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
  alert(this.name);
};
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
  • 只要經過new操做符來調用,那它就能夠做爲構造函數指針

    // 看成構造函數使用
    var person = new Person("Nicholas", 29, "Software Engineer");
    person.sayName(); //"Nicholas"
    // 做爲普通函數調用
    Person("Greg", 27, "Doctor"); // 添加到 window
    window.sayName(); //"Greg"
    // 在另外一個對象的做用域中調用
    var o = new Object();
    Person.call(o, "Kristen", 25, "Nurse");
    o.sayName(); //"Kristen"

原型模式

function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"Nicholas"
var person2 = new Person();
person2.sayName(); //"Nicholas"
alert(person1.sayName == person2.sayName); //true
  • 不管何時,只要建立了一個新函數,就會根據一組特定的規則爲該函數建立一個prototype屬性,這個屬性指向函數的原型對象,默認狀況下,全部的原型對象都會自動得到一個constructor屬性,這個屬性包含一個指向prototype屬性所在函數的指針。

圖片描述
圖片描述
圖片描述

組合使用構造函數模式和原型模式

function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructor : Person,
sayName : function(){
  alert(this.name);
}
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Count,Van"
alert(person2.friends); //"Shelby,Count"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true

動態原型模式

function Person(name, age, job){
//屬性
this.name = name;
this.age = age;
this.job = job;
// 方法
if (typeof this.sayName != "function"){
  Person.prototype.sayName = function(){
    alert(this.name);
  };
}
}
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName();

寄生構造函數模式

function Person(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
  alert(this.name);
};
return o;
}
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName(); //"Nicholas"

穩妥構造函數模式

function Person(name, age, job){
//建立要返回的對象
var o = new Object();
//能夠在這裏定義私有變量和函數
//添加方法
o.sayName = function(){
  alert(name);
};
//返回對象
return o;
}

繼承

原型鏈

圖片描述
圖片描述

  • 能夠經過兩種方式來肯定原型和實例之間的關係,第一種方式是使用instanceof操做符,只要這個操做符來測試實例與原型鏈中出現過的構造函數,結果就會返回truecode

    alert(instance instanceof Object); //true
    alert(instance instanceof SuperType); //true
    alert(instance instanceof SubType); //true
  • 第二種方式是使用isPrototypeOf()方法,只要是原型鏈中出現過的原型,均可以說是原型鏈所派生的實例的原型,所以isPrototypeOf()方法也會返回true

    alert(Object.prototype.isPrototypeOf(instance)); //true
    alert(SuperType.prototype.isPrototypeOf(instance)); //true
    alert(SubType.prototype.isPrototypeOf(instance)); //true

借用構造函數

function SuperType(){
this.colors = ["red", "blue", "green"];
}
function SubType(){
// 繼承了 SuperType
SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green"
  • 對於原型鏈而言,借用構造函數有一個很大的優點,便可以在子類型構造函數中向超類型構造函數傳遞參數

    function SuperType(name){
      this.name = name;
    }
    function SubType(){
      //繼承了 SuperType,同時還傳遞了參數
      SuperType.call(this, "Nicholas");
      //實例屬性
      this.age = 29;
    }
    var instance = new SubType();
    alert(instance.name); //"Nicholas";
    alert(instance.age); //29

組合繼承

  • 指的是將原型鏈和借用構造函數的技術組合到一塊

    function SuperType(name){
      this.name = name;
      this.colors = ["red", "blue", "green"];
    }
    SuperType.prototype.sayName = function(){
      alert(this.name);
    };
    function SubType(name, age){
      //繼承屬性
      SuperType.call(this, name);
      this.age = age;
    }
    //繼承方法
    SubType.prototype = new SuperType();
    SubType.prototype.constructor = SubType;
    SubType.prototype.sayAge = function(){
      alert(this.age);
    };
    var instance1 = new SubType("Nicholas", 29);
    instance1.colors.push("black");
    alert(instance1.colors); //"red,blue,green,black"
    instance1.sayName(); //"Nicholas";
    instance1.sayAge(); //29
    var instance2 = new SubType("Greg", 27);
    alert(instance2.colors); //"red,blue,green"
    instance2.sayName(); //"Greg";
    instance2.sayAge(); //27

原型式繼承

var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"

寄生式繼承

  • 思路和構造函數和工廠模式相似,即建立一個僅用於封裝繼承過程的函數,函數在內部以某種方式來加強對象

    function createAnother(original){
      var clone = object(original); //經過調用函數建立一個新對象
      clone.sayHi = function(){ //以某種方式來加強這個對象
        alert("hi");
      };
      return clone; //返回這個對象
    }
    var person = {
      name: "Nicholas",
      friends: ["Shelby", "Court", "Van"]
    };
    var anotherPerson = createAnother(person);
    anotherPerson.sayHi(); //"hi"

寄生組合式繼承

  • 不管什麼狀況下都會調用兩次超類型構造函數,一次是在建立子類型原型的時候,另外一次實在子類型構造函數內部

    function SuperType(name){
      this.name = name;
      this.colors = ["red", "blue", "green"];
    }
    SuperType.prototype.sayName = function(){
      alert(this.name);
    };
    function SubType(name, age){
      SuperType.call(this, name); // 第二次調用 SuperType()
      this.age = age;
    }
    SubType.prototype = new SuperType(); // 第一次調用 SuperType()
    SubType.prototype.constructor = SubType;
    SubType.prototype.sayAge = function(){
      alert(this.age);
    };

圖片描述

相關文章
相關標籤/搜索