JS 继承(二)组合继承
JS 继承(一)说明了一下简单的原型链继承,并且说明了它的两个缺点,现在解决它们。
function Person (name,age) {
this.name = name;
this.age = age;
this.friends = ['LiLei','HanMeiMei'];
}
function Man (name, age) {
this.name = name;
Person.call(this,name, age);
}
let m1 = new Man('tom', 12);
m1.friends.push('Green');
console.log("m1:", m1);
console.log("m1.__proto__:",m1.__proto__);
let m2 = new Man('LiLei',13);
console.log("m2:", m2);
console.log("m2.__proto__:",m2.__proto__);
运行结果:
image.png
看结果,简单原型链的那种继承方式的两个缺点都解决了,既可以给父类构造函数传参,父类构造函数里面的属性friends,name,age也私有化了,不再被共享,从而导致被其他实例影响了。
在Man构造函数中,Person.call(this,name, age)这句代码,非常重要,new操作的时候,除了会指向构造函数里面的代码并返回一个实例对象this外,还会把构造函数的作用域赋值给创建的实例对象,所以构造函数里面的this.xx = ‘xxx' 都是给实例对象添加属性并赋值,好比这样:
function PersonFn () {
let o = new Object();
o.a = 'aaa';
o.b = 'bbb';
return o;
}
每次执行PersonFn 都会生成一个全新的对象o;
ok, 说到这里,上面的那种继承写法,看起来似乎挺完美。
哦,对了,上面的运行结果中,m1.proto指向的原型对象因为当前并没有继承谁,所以是空的,但是每一个构造函数的原型对象都会有两个默认的属性constructor和proto,而proto默认继承Object原型对象。
回归正传,上面的代码好像没有写方法,下面把方法添加上:
function Person (name,age) {
this.name = name;
this.age = age;
this.friends = ['LiLei','HanMeiMei'];
}
Person.prototype.sayWords = function(des) {
console.log(des+' say words:', this.name,this.age, this.friends.toString());
}
function Man (name, age) {
this.name = name;
Person.call(this,name, age);
}
Man.prototype = new Person();
let m1 = new Man('tom', 12);
m1.friends.push('Green');
m1.sayWords("Person -> tom 1");
console.log("m1:", m1);
console.log("m1.__proto__:",m1.__proto__);
let m2 = new Man('LiLei',13);
m2.sayWords("Person -> LiLei 2");
console.log("m2:", m2);
console.log("m2.__proto__:",m2.__proto__);
运行结果:
image.png
Ok,现在看起来真的不错了。
这种继承方法就叫组合继承,是最常用的继承模式。
有时候真搞不懂,网上继承的方法一搜,好家伙,6,7种继承方式,取了一大堆的名字,各种概念,真的逼死人了,据科学家研究(我是道听途说),人脑的容量只有200M左右,这么小的容量,用来记那写莫名其妙的概念真他妈浪费,码农何必为难码农呢?呵呵...