JavaScript學習總結(二)--JavaScript原型 繼承

工廠函數模式

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 0;
    }
    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);
      }
      return 0;
    }
    var person1 = new Person('Nicholas', 29, 'software engineer');
    var person2 = new Person('greg', 27, 'doctor');
    alert(person1.constructor == Person) // true
  • 構造函數始終都應該以一個大寫之母開頭,而非構造函數則應該以小寫之母開頭。javascript

  • 建立Person的新實例,必須使用new操做符。java

    • 使用new這種方式調用構造函數會經歷4個步驟
      1.建立一個新對象
      2.將構造函數的做用域賦給新對象(所以 this就指向了這個新對象)
      3.執行構造函數中的代碼 爲這個新對象添加屬性
      4.返回新對象
  • 構造函數與普通函數的區別app

    • 任何函數經過new操做符來調用,那它就是構造函數
  • 構造函數的缺點函數

    • 就是每一個方法都要在每一個實例上從新建立一遍。
    • person1和person2都有一個名爲sayName()的方法,但那兩個方法不是同一個Function的實例。
    • 每定義一個函數,也就是實例化了一個對象。
  • 從邏輯上講,能夠這樣this

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = new Function('alert(this.name)'); //與聲明函數在邏輯上是等價的
  }
  alert(person1.sayName == person2.sayName) // false
  • 把函數定義轉移到構造函數外部
function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = sayName;
  }

  function sayName() {
    alert(this.name);
  }
  var person1 = new Person('Nicholas', 29, 'software engineer');
  var person2 = new Person('greg', 27, 'doctor')
// 咱們把sayName()定義在外部,person1 和person2 共享了在全局做用域中定義的同一個sayname()函數。
// 若是對象須要定義不少方法,那麼就要定義不少個全局函數,因而這個自定義的引用類型沒有分裝性可言
// 可使用原型模式

原型模式

使用原型對象的好處是可讓全部對象實例共享它所包含的屬性和方法prototype

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屬性所在函數的指針。
    // Person.prototype  constructor指向Person.
    // 而經過這個構造函數,咱們能夠原型對象添加其餘屬相和方法。

簡單的原型模式語法

function Person() {
    }
    Person.prototype = {
      name: 'nicholas',
      age: 29,
      job: 'software engineer',
      sayName: function() {
        alert(this.name);
      }
    }
  
  var friend = new Person();
  • 原型對象的缺點
    • 不能爲構造函數傳遞初始化參數
    • 最大的問題是 是由其共享本性所致使的。
    • 原型中全部屬性是被不少實例共享的。

原型鏈

原型鏈是做爲實現繼承的主要方法。指針

  • 其基本思想就是利用原型讓一個引用類型繼承另外一個引用類型的屬性和方法、
  • 構造函數。 原型和實例之間的關係。
  • 每一個構造函數都有一個原型對象,原型對象包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。
  • 那麼,假如咱們讓原型對象等於另外一個類型的實例,此時的原型對象將包含一個指向另外一個原型的指針,相應地,另外一個原型中包含着一個指向另外一個構造函數的指針、
  • 假如另外一個原型又是另外一個類型的實例,那麼上述關係依然成立,如此,就構成了實例與原型的鏈條。這就是所謂的原型鏈、
function SuperType() {
    this.property = true;
  }
  SuperType.prototype.getSuperValue = function() {
    return this.property;
  };
  function SubType() {
    this.subproperty =false;
  }
  // 繼承了supertype
  SubType.prototype = new SuperType();
  SubType.prototype.getSubValue = function() {
    return this.subproperty;
  }
  var instance = new SubType();
  alert(instance.getSuperValue()) //true

借用構造函數繼承

使用apply() 和call() 方法也能夠在未來新建立的對象上執行構造函數code

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'
// 1.傳遞參數
  function SuperType(name) {
    this.name = name;
  }
  function SubType() {
    // 繼承了SuperType同時還傳遞了參數
    SuperType.call(this, 'nicholas');
    // 實例屬性
    this.age = 29;
  }
  var instance = new SubType();
  alert(instance.name);
  alert(instance.age);
  • 借用構造函數的問題
    • 方法都在構造函數中定義,所以函數的複用就無從談起。

組合繼承

經過借用構造函數來實現對實例屬性的繼承。這樣,即經過在原型上定義方法實現了函數複用,有能保證每一個實例都有它本身的屬性、對象

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
相關文章
相關標籤/搜索