以前的文章里有提到过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的原型。