JavaScript面向对象之二(构造函数继承)

学习一波阮一峰的博客 戳这里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 = Catspa

若是咱们不这样作,那么Cat.prototype的构造函数会是什么?咱们在去看看new作的第二件事,这个空对象指向了Animal.prototype,因此Cat.prototype自身若是没有constructor属性的话就会去Animal.prototype上面去找。Cat.prototype.constructor === Animal //true

因此,若是咱们替换了prototype,须要手动去纠正它。

直接继承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
复制代码

直接遍历父类的原型,一个个复制到子类原型上便可。

感慨一下,大佬仍是大佬呀。。。

相关文章
相关标签/搜索