JavaScript中的原型、原型鏈、原型模式

今天,咱來聊聊JavaScript中的原型跟原型鏈設計模式

原型跟原型模式

這一塊的知識,主要是設計模式方面的。
首先,咱們知道JavaScript是面向對象的。既然是面向對象,那它天然也有相應的類跟對象等概念。
在JavaScript中,function這個東西仍是比較特殊的,它既能用來聲明方法,還能用來聲明一個相似C#/.NET中的類,而後new一下獲得一個對象。
舉例函數

//js中的function使用方式一:
function testFunc() {
    cosnole.log(123456);
}
testFunc();//123456;

//js中的function使用方式二:在這裏用到了構造函數模式
function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayName = function () {
        alert(this.name);
    }
}
var person1 = new Person('qwe', 26);//function還能夠new一個出來,獲得一個對象。
person1.sayName();

console.log(person1.constructor === Person);//true

var person2 = new Person('fgh', 26);
person2.sayName();
console.log(person1.sayName === person2.sayName);//false,這裏是個重點,person1跟person2的sayName方法是不同的,是各自的方法

//方式二還能夠這樣用
Person('qwe', 26);
window.sayName();

思考:
既然person1.sayName===person2.sayName返回false,兩個對象person1和person2各自的sayName方法雖然自己不一樣,實現的效果是同樣的,那可不可讓每一個對象調用的是同一個公共的方法sayName呢?答案是能夠的。
這裏有個優化方案優化

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayName = sayName;
}
function sayName() {
    alert(this.name);
}
var person1 = new Person('qwe', 26);
var person2 = new Person('jkl', 26);
console.log(person1.sayName === person2.sayName);//true    這裏是調用的公共的方法,不是各自本身的方法

以上的方案的確實現了想要的結果,但咱們知道JavaScript是面向對象的,面向對象的三要素有個封裝。但以上的方案並無體現出封裝的思想。更好的方式是經過原型模式來解決。ui

function Person() {
}
Person.prototype.name = "uip";//這裏的Person是屬性,不是構造函數,這個Person還有個屬性prototype,原型模式即是經過這個來實現的
Person.prototype.age = 26;
Person.prototype.sayName = function () {
    alert(this.name);
}
//另一種寫法
Person.prototype = {
    name: 'uio',
    age = 26,
    sayName = function () {
        alert(this.name);
    }
}

var person1 = new Person();
person1.sayName();

以上即是原型模式,也並不是沒有缺點,雖然不用在構造函數裏面傳遞參數來初始化,但獲得的對象屬性都是同樣的。這即是最大的問題。
怎麼辦呢?
構造函數模式能夠經過構造函數來傳遞參數進行初始化,原型模式能夠共享某些屬性跟方法。那可不能夠合二爲一,將二者結合起來,豈不更好?
兩者結合,代碼以下:this

function Person(name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype = {
    sayName: function () {
        alert(this.name);
    }
}
var person1 = new Person('sdaf', 26);
person1.sayName();
var person2 = new Person('ssdf', 26);
person2.sayName();
console.log(person1.sayName === person2.sayName);//true,看到這裏,相信便會體會到這個模式精妙之處了吧。sayName是共有的方法,你們共享。

原型鏈的問題

如下三句話特別重要,須要深入理解。
一、每一個函數都有個prototype屬性,prototype是函數獨有的屬性。
二、每一個對象都有個__proto__屬性。__proto__是對象獨有的屬性。
二、每一個函數的portotype的是Object的實例
在JavaScript中,繼承即是經過原型鏈實現的。prototype

function Person(name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype = {
    sayName: function () {
        alert(this.name);
    }
}
var person1 = new Person('sdaf', 26);

console.log(person1.__proto__ === Person.prototype);//true
console.log(Person.prototype.__proto__ == Object.prototype);//true   
//在這裏說明一下,Person的基類是Object,Person的prototype是Object的實例,因此是個對象,它有__proto__這個屬性,而這個屬性等價於Object的prototype屬性。
//這樣一環扣一環,構成了一道鏈,即是所謂的原型鏈
console.log(Ojbect.prototype.__proto__ === null);//true

實戰

既然明白以上的知識,怎麼優雅地運用到實際工做中呢?
在搞Vue項目時,咱們幾乎不可避免地會經過EventBus進行組件通訊。
每次都須要var bus=new Vue();
在這裏即可以經過原型模式來優化。設計

Vue.prototype.$bus = new Vue(); // EventBus用於無關係組件間的通訊。

在其餘組件,即可以直接經過this.$bus發佈訂閱事件了。code

相關文章
相關標籤/搜索