js继承的三种方式以及个人理解

1:原型链继承:

function Parent () {
    this.name = 'kevin';
}

Parent.prototype.getName = function () {
    console.log(this.name);
}

function Child () {

}

Child.prototype = new Parent();

var child1 = new Child();

console.log(child1.getName()) // kevin

个人理解:所有的Child实例都继承了Parent原型链,之前我的理解是child1.name = ‘DaMing’,应该了修改的原型链中的name值,所以我做了个尝试,结果发现

function Parent () {
    this.name = 'kevin';
}

Parent.prototype.getName = function () {
    console.log(this.name);
}

function Child () {

}

Child.prototype = new Parent();

var child1 = new Child();
child1.name = "DaMing"
var child2 = new Child();

console.log(child1.getName()) // DaMing
console.log(child2.getName()) // kevin

原型链上的Parent中的name值并没有发生改变,换种写法再试试

function Parent () {
    this.name = ['kevin', 'daisy'];
}

Parent.prototype.getName = function () {
    console.log(this.name);
}

function Child () {

}

Child.prototype = new Parent();

var child1 = new Child();
child1.name.push("DaMing")
var child2 = new Child();

console.log(child1.getName()) // ["kevin", "daisy", "DaMing"]
console.log(child2.getName()) // ["kevin", "daisy", "DaMing"]

  原型链上的name改成数组了,child1   push一个值进去,打印出来发现这下原型链上的name总算是改变了。这是为什么呢,我再试了下

function Parent () {
    this.name = ['kevin', 'daisy'];
}

Parent.prototype.getName = function () {
    console.log(this.name);
}

function Child () {

}

Child.prototype = new Parent();

var child1 = new Child();
child1.name = ["DaMing"]
var child2 = new Child();

console.log(child1.getName()) // ["DaMing"]
console.log(child2.getName()) // ["kevin", "daisy"]

  child1直接赋值给了name,原型链上的name又没有发生变化,好了,这下可以得出结论了:

  对实例对象属性直接赋值,即使当前实例没有此属性,会自动在实例对象里面新增此属性,并不会在原型链上找。

  但是如果是修改实例对象属性,实例对象属性上并没有此属性,那么就会往原型链上去找,所有push方法找到Parent上的name并做出了修改

第二种继承:(构造函数继承)

function Parent () {
    this.names = ['kevin', 'daisy'];
}

function Child () {
    Parent.call(this);
}

var child1 = new Child();

child1.names.push('yayu');

console.log(child1.names); // ["kevin", "daisy", "yayu"]

var child2 = new Child();

console.log(child2.names); // ["kevin", "daisy"]

  使用call改变Child中this指向,相当于把Parent中所有属性方法全部一股脑copy过来成为Child中的方法,这样写不会出现上面原型链继承的问题,因为Parent中有的,我Child中也有啊,我为啥还要跑原型链上去找呢,嗯,没问题

  但是把,仔细又一想,每次实例化Child对象,都是copy了Parent中所有方法属性,那有些方法可以共用,或者是需要所有实例对象都能修改的呢,怎么办,这样写好像就有点问题了。

 

来来来,第三种继承方式:

第三种继承:(组合继承)

原型链继承和经典继承双剑合璧。

function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function () {
    console.log(this.name)
}

function Child (name, age) {

    Parent.call(this, name);
    
    this.age = age;

}

Child.prototype = new Parent();
Child.prototype.constructor = Child;

var child1 = new Child('kevin', '18');

child1.colors.push('black');

console.log(child1.name); // kevin
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]

var child2 = new Child('daisy', '20');

console.log(child2.name); // daisy
console.log(child2.age); // 20
console.log(child2.colors); // ["red", "blue", "green"]

  

也是使用call方法,但是是把需要的私有的属性拿过来,不需要的还是放在原型链上,嗯,挺好的。

最后在把这种写法换成Es6的写法:

class Parent {
    constructor (name){
        this.name = name;
        this.colors = ['red', 'blue', 'green'];
    }
    getName () {
         console.log(this.name)
    }
}
class Child extends Parent{
    constructor (name, age) {
        super(name)
        this.age = age;
    }
}
let child1 = new Child('kevin', '18');

  

猜你喜欢

转载自www.cnblogs.com/huangbohang/p/9633401.html