學習一波阮一峯的博客 戳這裏javascript
博客中是本身的理解,以及對大佬描述不清楚的地方進行了修正,也算是本身的一個再(xiao)產(tu)出(cao)吧html
上一篇:JavaScript面向對象之一(封裝)java
先來看個簡單的:bash
function Animal(){
this.type = 'animal;'
}
function Cat(name, color){
this.name = name
this.color = color
//這裏用call,我的以爲更好些
Animall.call(this)
}
var cat = new Cat('po', 'orange')
console.log(cat.type) //animal
複製代碼
建立了一個Animal和Cat構造函數,而後在Cat裏面調用Animal的構造函數,在將Cat實例化,就能夠訪問到Animal的屬性了。 這個例子顯然有問題,放在第一個就是用來找茬的。函數
什麼問題呢?假如我想使用在Animal上的公共方法,像這樣Animal.prototype.eat = function(){ console.log('animal eat') }
,用cat.eat()
是訪問不到的。post
爲何呢?由於咱們Cat和Animal的原型根本就沒有關聯起來呀。你看看我們上面的代碼,那個地方關聯過?學習
那下面咱們就將二者的原型關聯起來試試看ui
function Animal(){
this.type = 'animal;'
}
Animal.prototype.eat = function(){ console.log('animal eat') }
function Cat(name, color){
this.name = name
this.color = color
}
Cat.prototype = new Animal()
var cat = new Cat('po', 'orange')
console.log(cat.type) //animal
console.log(cat.eat()) //animal eat
複製代碼
這種方法好!能夠拿到屬性和方法,一箭雙鵰。可是,這裏有個陷阱(keng)!!!Cat.prototype = new Animal()
以後,咱們的Cat.prototype裏面的全部方法都消失了!這是怎麼回事?由於new,new作了四件事,這裏再次回顧一下:this
var temp = {}
temp.__proto__ = Animal.prototype
Animal.call(temp)
return temp
複製代碼
看到了嗎?new會使用一個空對象而且將其返回。這樣一來咱們的Cat.prototype就被清空了(包括自身的constructor)。因此咱們須要本身多作一件事Cat.prototype.constructor = Cat
。spa
若是咱們不這樣作,那麼Cat.prototype的構造函數會是什麼?咱們在去看看new作的第二件事,這個空對象指向了Animal.prototype,因此Cat.prototype自身若是沒有constructor屬性的話就會去Animal.prototype上面去找。Cat.prototype.constructor === Animal //true
因此,若是咱們替換了prototype,須要手動去糾正它。
既然上面這種方法有坑,並且的的確確讓你很容易漏掉,那咱們改進一下:
function Animal(){}
Animal.prototype.eat = function(){ console.log('animal eat') }
Cat.prototype = Animal.prototype
Cat.prototype.constructor = Cat
var cat = new Cat('po', 'orange')
console.log(cat.eat()) //animal eat
複製代碼
既然咱們想從Animal.prototype上面那東西,直接從上面拿不就好了?並且我還機智的填了上面會出現的坑。同時結果也是我想要的。
可是!!咱們的Cat.prototype和Animal.prototype指向的是同一個原型,這會致使我在Cat.prototype上作了什麼事,會同時發生在Animal.prototype上。這是爲何呢?MDZZ,這兩個就是同一個東西呀,原型是堆中一塊內存,Cat和Animal都指向這塊內存,操做的是同一個東西,怎麼會不影響?
與此同時,自覺得聰明的填坑Cat.prototype.constructor = Cat
,此時的Cat和Animal的原型是同一個,修改了constructor以後,致使Animal的constructor變成了Cat。這種方法果斷PASS。。。
var F = function(){}
F.prototype = Animal.prototype
Cat.prototype = new F()
Cat.prototype.constructor = Cat
複製代碼
咱們使用中間對象進行過分,巧妙的將Cat.prototype和Animal.prototype解耦,這樣就不會出現問題了。仔細觀察會發現這個和new作的事情有殊途同歸之處。
咱們進行封裝一下在使用
function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
extend(Cat,Animal);
var cat1 = new Cat('po' 'orange');
alert(cat1.eat()); // animal eat
複製代碼
這裏Child.uber = Parent.prototype
的意思相似於__proto__
。
這裏還有一種簡單粗暴的方式
function extend2(Child, Parent) {
var p = Parent.prototype;
var c = Child.prototype;
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
}
function Animal(){}
Animal.prototype.eat = function(){ console.log('animal eat') }
extend2(Cat, Animal);
var cat1 = new Cat('po' 'orange');
alert(cat1.eat()); // animal eat
複製代碼
直接遍歷父類的原型,一個個複製到子類原型上便可。
感慨一下,大佬仍是大佬呀。。。