淺談 OOP JavaScript原型
上一章我們談了構造函數,他的唯一特點就是比較了地址不相同,因為大家知道引用類型是比較的引用。我們來談談 原型。
原型
我們每創建一個函數都有一個原型(prototype)屬性,這個屬性是一個對象,他的特點是 共享 。也就是說不用在構造函數中定義對象實例,而是直接將這些添加到原型當中。
function Create () {} //聲明一個構造函數
Create.prototype.a = 'abc'; //在原型中添加屬性
Create.prototype.b = 10;
Create.prototype.c = function () { //在原型中添加方法
return this.a + this.b;
};
var create = new Create();
alert(create.c()); //返回abc10
我們這次再來比較一下原型中方法的地址是否一致:
var create = new Create();
var create1 = new Create();
alert(create.c == create1.c); //true
是不是還沒明白?我們用一張圖來告訴大家:
這個__proto__就相當于指針,指向了原型對象的constructor,而constructor就相當于將構造函數對象和原型對象相關聯。
那么我們要用構造函數對象去給重寫 屬性或者方法 會怎么樣呢?
var create = new Create();
create.a = 'EFD';
alert(create.a); //返回EFD
真的將原型對象里面的 a 給覆蓋了么?并沒有:
var create1 = new Create();
alert(create.a); //返回abc
原型模式的執行過程:
1.先去查找構造函數里面的屬性和方法 ,如果有就立即返回。
2.如果構造函數實例里面沒有,就去原型里面查找,如果有就立即返回。
因為我們在構造函數添加了屬性,所以它會自動去查找,構造函數里面的屬性也就立即返回了!
原型的字面量
在原型中,我們也可以使用字面量的方式去創建,可以讓屬性和方法體現出更好的封裝效果。
function Create(a,b){}; //聲明一個構造函數
Create.prototype = { //字面量方式
a:'abc',
b:10,
c:function () {
return this.a + this.b;
}
};
不知道大家有沒有發現,我們用字面量的方式是這樣的:Create.prototype ={};
大家都知道,用一個{}就等同于new Create();這樣,我們就相當于新聲明的一個對象,我們原型對象里面的constructor還會指向Create么?
var create = new Create();
alert(create.constructor == Create); //false
alert(create.constructor == Object); //true
(我們來解釋一下為什么用create.constructor,因為我們打印constructor就會將整個構造函數打印出來,因為上面講過它是將構造函數對象和原型對象相關聯的屬性。)
通過上面的例子可以看出,它已經指向了新的實例對象。
constructor的巧妙用法:
我們可以使用constructor來強制指回原來的實例對象:
function Create(a,b){};
Create.prototype = {
constructor:Create,
a:'abc',
b:10,
c:function () {
return this.a + this.b;
}
};
原型對象的重寫問題:
大家都知道,構造函數的屬性和方法重寫是無傷大雅的,但是原型對象中可以重寫么?
function Create(a,b){};
Create.prototype = {
constructor:Create,
a:'abc',
b:10,
c:function () {
return this.a + this.b;
}
};
Create.prototype = {
a:'EFD',
};
var create = new Create();
alert(create.c()); //create.c is not a function
不難看出,我們重寫了原型會將之前的原型指向切斷!!!
原型模式的缺點:
其實它的缺點也是它優點: 共享 。
我們在字面量里面給原型對象添加一個數組就很容易的看出來了:
function Create(a,b){};
Create.prototype = {
constructor:Create,
a:'abc',
b:10,
c:[第一個,第二個,第三個],
d:function () {
return this.a + this.b + this.c;
}
};
var create = new Create();
create.c.push('第四個');
alert(create.run()); //返回abc10第一個第二個第三個第四個
我們看得出這時候push添加已經生效了,在數組的末尾添加了“第四個”
我們再來實例一個對象就能看得出他的共享問題了:
var create1 = new Create();
alert(create1.run()); //返回abc10第一個第二個第三個第四個
這就是共享問題。下面新實例化一個對象也會將上面添加的字符串給共享到這里來。
這一章就到這里。 歡迎所有閱讀文章的人指正錯誤!
Brian Lee
來自:https://segmentfault.com/a/1190000007623594