javascript原型式繼承

以前的文章裏有提到過javascript類式繼承,那種繼承方式極大的方便了其餘語言(非javascript)程序員使用javascript來實現繼承,可是有缺點,就是創建了一個非必要的構造函數,那這篇文章咱們來談一談具備javascript自身特點的原型式繼承。javascript

咱們先來看一看下面的代碼:java

var Car = {
    color: 'red',
    size: 'big',
    getAttr: function() {
        return this.color
    }
}

var car1 = Object.create(Car)
car1.color = 'blue'
car1.brand = 'BYD'
console.log(car1.color) //blue
console.log(car1.brand) //BYD
console.log(Car.color) //red
console.log(Car.brand) //undefined

var car2 = Object.create(Car)
car2.getAttr = function() {
    return this.size
}
console.log(car2.getAttr()) //big
console.log(Car.getAttr()) //red
console.log(car1.getAttr()) //blue

上面的代碼就是原型式繼承最簡單的方式,「子類」繼承了「父類」的屬性,修改「子類」的屬性也沒有影響到「父類」,「子類」之間也是相安無事互不干擾,完美實現了繼承。這樣繼承的好處就是比類式繼承少了一層構造函數程序員

固然create這個方法是es5中出現的,ie6 7 8是不支持的哦,下面是一個兼容的方法,讓低版本ie也來實現create。函數

 

if (!Object.create) {
    Object.create = function(o) {
        function F() {}
        F.prototype = o
        return new F()
    }
}

上述代碼的意思就是,首先聲明一個構造函數,該構造函數的原型指向須要繼承的對象,最後返回實例化後的構造函數,其實這個函數也很好的詮釋了原型式繼承的原理,「父類」的屬性存在於「子類」的原型上,若是「子類」本身重寫了屬性或者方法,那就直接用「子類」自身的屬性或者方法,而且不會影響到「父類」,若是調用了「子類」沒有的屬性或者方法,那麼因爲原型鏈,咱們順藤摸瓜就找到了「父類」的屬性或方法,若是再沒有就game over了。this

其實兩種繼承方式大同小異,玩的都是原型鏈,只是原型式繼承更符合javascript的語言特色,類式繼承更偏向於「類」的概念。es5

 

2017.12.1更新
以前理解有點誤差,也好久沒有看之前寫的博客了,發現不是很對,這裏須要修改下,Object.create就是使用指定的原型對象及其屬性去建立一個新的對象。
完整的原型繼承應該是:spa

//
var Foo = function () {
  this.x = 1
  this.y = 2
}
Foo.prototype.add = function ()  {
  return this.x + this.y
}
//
var Bar = function () {
  // 調用父類的構造函數,this指向本身
  Foo.call(this)  
}
Bar.prototype = Object.create(Foo.prototype)
// 原型構造函數在上一步被幹掉了,再搞回來
Bar.prototype.constructor = Bar

這樣bar就擁有了foo的一切,並能夠在foo的基礎上進行擴展且不會影響到foo。prototype

那爲何使用Object.create把foo的原型複製給bar呢,不能使用new Foo()或者Foo.prototype的形式嗎?code

答案固然是否認的,若是使用new Foo(),表面上看上去沒有問題,可是此時foo函數會被調用,若是foo的構造函數中不僅是定義數據還有實際操做,好比alert,那就出現問題了。對象

使用Foo.prototype就更不能夠了,這樣就會變成了bar的原型就直接引用了foo的原型,若是這時候修改bar的原型就至關於修改了foo的原型。

相關文章
相關標籤/搜索