紅寶書面向對象的程序設計-讀後總結

建立對象

對象字面量形式建立對象

var colors = {
    //...
};
複製代碼

工廠模式

function Person(name,age,job){
    var o = new Object();

    o.name = name;
    o.age = age;
    o.job = job;

    o.sayName = function (){
        console.log(this.name);
    }

    return o;
};


var person1 = Person('李雪峯','26','web前端開發');
var person2 = Person('hq','25','攝影師');
複製代碼

構造函數模式

function Animal(name,color){
    this.name = name;
    this.color = color;
    thia.sayName = function(){
        console.log(this.name);
    }
}

var dog = new Animal('旺財','黑色')
var dog2 = new Animal('阿拉斯加','黑白相間')

複製代碼

原型模式

function Animal(){};

Animal.prototype.name = "旺財";
Animal.prototype.age = 3;
Animal.prototype.sayName = function(){
    console.log(this.name);
};

var dog = new Animal();

dog.sayName();   //旺財

var dog2 = new Animal();

dog2.sayName();   //旺財

console.log(dog.sayName === dog2.sayName)   //true
複製代碼

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

function Animal(name,age,color){
    this.name = name;
    this.age = age;
    this.color = color;
    this.friends = ['旺旺','旺財','二哈']
}

Animal.prototype.sayName = function(){
    console.log('狗狗的名字叫:'+this.name);
}

var dog = new Animal('二狗子','3','黑色');

dog.friends.push('陳二狗');     //陳二狗被黑的最慘的一次

console.log(dog.friends)
console.log(dog.sayName())

var dog2 = new Animal('狗腿子','10','五光十色');
dog2.friends.push('走狗');
console.log(dog2.friends);
console.log(dog2.sayName())

console.log(dog.friends == dog2.friends)    //false
console.log(dog.sayName == dog2.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(){
            console.log(this.name);
        }
    }
}

var friend = new Person('李雪峯','26','web前端開發');
friend.sayName();
複製代碼

寄生構造函數模式

function Person(name,age,job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        console.log(this.name);
    }
    return o;
}

// 比工廠模式多了個new調用, 而且把Person叫作了構造函數
var friend = new Person('李學峯','26','web前端開發');
friend.sayName();

// 應用

function SpecialArray(){
    //建立數組
    var values = new Array();
    //添加值

    values.push.apply(values,arguments);
    //添加方法
    values.toPipedString = function(){
        return this.join('||');
    };

    //返回數組
    return values;
}

var colors = new SpecialArray('red','pink','orange','blue');

console.log(colors.toPipedString());    //red||pink||orange||blue

複製代碼

穩妥構造函數模式

  • 變量Person中保存的是一個穩妥對象,而除了調用sayName()
  • 沒有別的方式能夠訪問其數據成員.
function Person(name,age,job){
    // 建立要返回的對象
    var o = new Object();

    //能夠在這裏定義私有變量和函數
    o.sayName = function(){
        console.log(name);
    }

    return o;
}

var friend = Person('lxf','111','web');
friend.sayName();
複製代碼

繼承

  • 接口繼承和實現繼承.
  • ECMAScript只支持實現繼承,並且其實現繼承的主要是依靠原型鏈來實現的
  • 原型鏈的概念

原型鏈的概念: 其基本思想是利用原型讓一個引用類型繼承另外一個引用類型的屬性和方法前端

這裏要先說一下: 構造函數/原型/實例的關係web

每一個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針 constructor,而實例都包含一個指向原型對象的內部指針[[proto]](__proto__).數組

假如咱們讓原型對象等於另外一個類型的實例,結果就是,此時的原型對象將包含一個指向另外一個另外一個原型的指針bash

假如另外一個原型又是另外一個類型的實例,那麼上述關係依然成立,如此層層遞進,就構成了實例與原型的鏈條. 這就是所謂原型鏈的基本概念app

//實現一個原型鏈

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();
console.log(instance.getSuperValue)
複製代碼
  • 要注意這裏instance.constructor如今指向的是 SuperType,這是由於原來 SubType.prototype 中的constructor 被重寫的緣故
  • 實際上,不是SubType的原型的 constructor 屬性被重寫了,而是 SubType 的原型指向了另外一個對象 SuperType 的原型,而這個原型對象的 constructor 屬性指向的是 SuperType

引用紅寶書中的圖片說明函數

prototype

經過實現原型鏈,本質上擴展了前面介紹的原型搜索機制,當以讀取模式訪問一個實例屬性時首先會在 實例中搜索該屬性.測試

若是,沒有找到該屬性,則會繼續搜索實例的原型.ui

在經過原型鏈實現繼承的狀況下,搜索過程就得沿着原型鏈繼續向上.this

上邊的例子中的搜索順序spa

  • 搜索實例
  • 搜索SubType.prototype
  • 搜索SuperType.prototype
  • 若是找不到屬性或方法的狀況下,搜索過程老是要一環一環的前行到原型鏈額末端纔會停下來

引用紅寶書中的圖片說明

完整的原型鏈

肯定原型和實例的關係

第一種:

  • 使用 instanceof 操做符

這個操做符來測試實例與原型中出現過的構造函數,結果就會返回true

console.log(instance instanceof Object);    //true
console.log(instance instanceof SubType);    //true
console.log(instance instanceof SuperType);    //true
複製代碼

因爲原型鏈的關係,能夠輸 instance 是 Object | SuperType | SubType 中任何類型的實例

第二種:

  • isPrototypeOf()方法

一樣,只要是原型鏈中出現過的原型,均可以說是該原型鏈所派生的實例的原型

console.log(Object.isPrototypeOf(instance));    // true
console.log(SuperType.isPrototypeOf(instance)); // true
console.log(SubType.isPrototypeOf(instance));   // true
複製代碼

原型鏈的問題

  • 一個是經過原型來實現繼承時,包含引用類型值的原型,會共享
  • 一個是: 在建立子類型的實例時,不能向超類型的構造函數中傳遞參數

借用構造函數

  • apply() 和 call()
function SuperType(nane){
    this.name = name;
    this.colors = ['red','pink','orange','green'];
}

function SubType(nane,age){
    SuperType.call(this);   // 不傳遞參數的狀況
    //SuperType.call(this,name); //傳遞參數
    //SuperType.apply(this,arguments);  // 傳遞參數

    // 實例屬性
    this.age = age;
}

var instance1 = new SubType();
instance1.colors.push('blue');

console.log(instance1.colors);

var instance2 = new SubType();
console.log(instance2.colors)
複製代碼
  • 問題

方法都在構造函數中定義,一次函數複用就無從談起.

組合繼承

function SuperType(name){
    this.name = name;
    this.colors = ['red','blue','pink'];
}

SuperType.prototype.sayName = function(){
    console.log(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 (){
    console.log(this.age);
}


var instane1 = new SubType('lixuefeng','26');

instane1.colors.push('green','222');

console.log(instane1.sayName())
console.log(instane1.sayAge())
console.log(instane1.colors)

var instane2 = new SubType('zhangyu','23');
instane2.colors.push('122','#fff');

console.log(instane2.sayName())
console.log(instane2.sayAge())
console.log(instane2.colors)
複製代碼

組合繼承避免了原型鏈和借用構造函數的缺陷,融合了他們的優勢,instanceofisPrototypeOf() 也可以用於識別組合繼承建立的對象

原型式繼承

function object(o){
    function F(){};
    F.prototype = o;
    return new F();
}

// 應用
var person = {
    name : 'lixuefeng',
    friends:['red','pink','blue']
};

var anotherPerson = object(person);
anotherPerson.name = 'Greg';
anotherPerson.friends.push('Rob');

var yetAnotherPerson = object(person);
yetAnotherPerson.name = '你你你';
yetAnotherPerson.friends.push('#fff');

console.log(person.friends)
複製代碼
  • ECMAScript5 經過Object.create()方法規範化了原型式繼承.
  • 這個方法接受連個參數:
    • 一個用做新對象原型的對象
    • (可選的)一個爲新對象定義額外屬性的對象.
    • 在傳入一個參數的狀況下,Object.create()object()方法的行爲相同

一個參數的時候

var person = {
    name : 'lixuefeng',
    friends:['red','pink','blue']
};

var anotherPerson = Object.create(person);
anotherPerson.name = 'Greg';
anotherPerson.friends.push('Rob');

var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = '你你你';
yetAnotherPerson.friends.push('#fff');

console.log(person.friends)
複製代碼

兩個個參數的時候

var person = {
    name : 'lixuefeng',
    friends:['red','pink','blue']
};

var anotherPerson = Object.create(person,{
    name:{
        value:'<<離人愁>> ==> 李元傑'
    }
});

console.log(anotherPerson.name)
複製代碼

寄生式繼承

function createAnother(original){
    var clone = Object.create(original);    // 經過調用函數建立一個新對象 返回一個傳入對象的新的實例賦值給 clone

    clone.sayHi = function(){               // 以某種方式來加強這個對象
        console.log('hi');
    };

    return clone;                           // 返回這個對象
}

var person = {
    name : 'xxname',
    friends:['red','blue','van']
};

var anotherPerson = createAnother(person);
anotherPerson.sayHi();      // hi
anotherPerson.friends.push('11','sss')
console.log(anotherPerson.friends)
console.log(anotherPerson.name)
複製代碼

寄生組合式繼承

  • 構造函數模式+原型模式繼承的缺點
function SuperType(name){
    this.name = name;
    this.colors = ['red','blue','pink','orange'];
}

SuperType.prototype.sayName = function(){
    console.log(this.name);
}

function SubType(name,age){
    SuperType.call(this,name);      // 這裏調用一次 SuperType()
    //SuperType.apply(this,arguments)

    this.age = age;
}

SubType.prototype = new SuperType();    // 這裏調用一次 SuperType()
SubType.prototype.constructor = SubType;

SubType.prototype.sayAge = function (){
    console.log(this.age);
}

var instance =new SubType('小明','100');
instance.colors.push('#333');

console.log(instance.sayName());
console.log(instance.sayAge());
console.log(instance.colors);

var instance2 = new SubType('小藍','122312');
instance2.colors.push('#fff','#ff0000');

console.log(instance2.sayName());
console.log(instance2.sayAge());
console.log(instance2.colors);

複製代碼
  • 在第一次調用 SuperType 構造函數時,SubType.prototype會獲得兩個屬性:

    • name
    • colors
    • 他們都是 SuperType 的實例屬性,只不過如今位於 SubType的原型中
  • 當調用SubType構造函數時,又會調用一次 SuperType構造函數,這一次又在新對象上建立了實例屬性 namecolors 因而,這兩個屬性就屏蔽了原型中的兩個同名屬性

兩次調用SuperType構造函數的結果

寄生構造模式能夠解決這個問題

function inheritPrototype(subType,superType){
    var prototype = Object.create(superType.prototype);       // 建立對象
    prototype.constructor = subType;                        // 加強對象
    subType.prototype = prototype;                          // 指定對象
}

function SuperType(name){
    this.name = name;
    this.colors = ['red','blue','pink','orange'];
}

SuperType.prototype.sayName = function(){
    console.log(this.name);
}

function SubType(name,age){
    SuperType.call(this,name);      // 這裏調用一次 SuperType()
    //SuperType.apply(this,arguments)

    this.age = age;
}

//SubType.prototype = new SuperType();    // 這裏調用一次 SuperType()
//SubType.prototype.constructor = SubType;

inheritPrototype(SubType,SuperType);

SubType.prototype.sayAge = function (){
    console.log(this.age);
}

var instance =new SubType('小明','100');
instance.colors.push('#333');

console.log(instance.sayName());
console.log(instance.sayAge());
console.log(instance.colors);

var instance2 = new SubType('小藍','122312');
instance2.colors.push('#fff','#ff0000');

console.log(instance2.sayName());
console.log(instance2.sayAge());
console.log(instance2.colors);
複製代碼

這個例子只調用了一次 SuperType構造函數,而且所以避免了在 SubType.prototype 上面建立沒必要要的,多餘的屬性。於此同時,原型鏈還能保持不變。

所以,還可以正常使用 instanceofisPrototypeOf()

寄生組合式繼承是引用類型最理想的繼承範式

記錄理解,有不對的地方,歡迎指出

最後推薦一下我的的公衆號搜索 有趣好玩Games 推薦一些有趣好玩的小遊戲手機遊戲等

相關文章
相關標籤/搜索