@moshangxc
2018-08-29T14:53:58.000000Z
字数 5139
阅读 711
js
继承
ECMAScript只支持实现继承,实现继承主要的依靠原型链来实现的。下面介绍几种JS实现继承的方式,以及各自的优缺点。
实现原理:利用原型让一个引用类型继承另一个引用类型的属性和方法.本质为重写原型对象。
function Sup(){
this.name = "sup";
this.items = [1, 2, 3];
}
Sup.prototype.geName = function(){
console.log(this.name);
}
function Sub(){
this.age = 25;
}
Sub.prototype = new Sup();
Sub.prototype.getAge =function(){
console.log(this.age);
}
var instance = new Sub();
instance.getName();
存在问题
1.继承包含引用类型值的原型,引用类型的原型属性会被所以实例共享。耦合度较高。
2.创建子类型的实例时不能向父类的构造函数传递 参数。
验证demo
var a = new Sub();
console.log(a.items); //[1, 2, 3]
a.items.push(4);
var b = new Sub();
console.log(b.items); //[1, 2, 3, 4]
function Sup(name){
this.name = name;
this.items = [1, 2, 3];
}
Sup.getItems = function(){
console.log(this.items);
}
function Sub(name){
Sup.call(this, name);
}
var a = new Sub();
a.items.push(4);
console.log(a.items); //[1, 2, 3, 4]
var b = new Sub();
console.log(b.items); //[1, 2, 3]
可以解决上诉的问题,但同时也存在缺陷。
父类原型链上定义的方法对子类是不可见的,若要继承方法,则父类的方法都应定义在构造函数内部,方法都是在构造函数中定义,不能复用
function Sup(name){
this.name = name;
this.items = [1, 2, 3];
}
Sup.prototype.getItems = function(){
console.log("items: ", this.items);
}
Sup.prototype.getName = function(){
console.log("name: ", this.name);
}
function Sub(name, age){
Sup.call(this, name);
this.age = age;
}
Sub.prototype = new Sup();
Sub.prototype.constructor = Sub;
Sub.prototype.getAge = function(){
console.log("age: ", this.age);
}
var a = new Sub("lilei", 25);
a.items.push(4);
a.getName(); //lilei
a.getAge(); //25
a.getItems(); //[1, 2, 3, 4]
var b = new Sub("hanmeimei", 24);
b.getName(); //hanmeimei
b.getAge(); //24
b.getItems(); //[1, 2, 3]
那么问题来了,又存在哪些缺陷呢?
构造函数和原型链上定义了重复的属性
function object(sup){
function F(){}
F.prototype = sup;
return new F();
}
function createObj(obj){
var clone = object(obj);
clone.getName = function(){
console.log(this.name);
}
clone.getFriends = function(){
console.log(this.friends);
}
return clone;
}
var obj = {
name : 'lily',
friends: ['lucy', 'lilei', 'hanmeimei']
}
var obj1 = createObj(obj),
obj2 = createObj(obj);
obj1.name = 'jim';
obj1.friends.push('lady gaga');
// obj2.friends = ['katy perry', 'rianna', 'adele'];
obj1.getName(); //jim
obj1.getFriends(); //['lucy', 'lilei', 'hanmeimei', 'lady gaga']
obj2.getName(); //lily
obj2.getFriends(); //['lucy', 'lilei', 'hanmeimei', 'lady gaga']
存在问题:含有应用类型的值始终会共享
具体原因上节课领导已经分析过,好好回忆一下下,是不是忘了(´・・)ノ(._.`)
function inherit(Sup, Sub){
function F(){}
F.prototype = Sup.prototype;
var obj = new F();
obj.constructor = Sub;
Sub.prototype = obj;
}
function Sup(name){
this.name = name;
this.items = [1, 2, 3];
}
Sup.prototype.getItems = function(){
console.log("items: ", this.items);
}
Sup.prototype.getName = function(){
console.log("name: ", this.name);
}
function Sub(name, age){
Sup.call(this, name);
this.age = age;
}
inherit(Sup, Sub);
Sub.prototype.getAge = function(){
console.log("age: ", this.age);
}
Sub.prototype.getName = function(){
console.log("nameForSub: ", this.name);
}
function Sub1(name, age){
Sup.call(this, name);
this.age = age;
}
inherit(Sup, Sub1);
Sub1.prototype.getAge = function(){
console.log("age: ", this.age);
}
var a = new Sub("lilei", 25);
a.items.push(4);
a.getName(); //nameForSub: lilei
a.getAge(); //age: 25
a.getItems(); //items: [1, 2, 3, 4]
var b = new Sub("hanmeimei", 24);
b.getName(); //nameForSub: hanmeimei
b.getAge(); //age: 24
b.getItems(); //items: [1, 2, 3]
var c = new Sub1("jim", 23);
c.getName(); //name: jim
c.getAge(); //age: 23
c.getItems(); //items: [1, 2, 3]
inherit函数能不能换成如下写法,有什么区别?
function inherit(Sup, Sub){
Sub.prototype = Sup.prototype;
}
继承方式 | 描述 | 好处 | 缺陷 |
---|---|---|---|
原型链 | 重写子类原型链为基类的实例对象 | 易理解 | 1.无法给基类构造函数传递参数 2. 所有实例共享引用类型的属性 |
借用构造函数 | 子类构造函数中调用基类构造函数,作用域指向当前对象 | 解决原型链存在的问题 | 基类原型链上定义的方法属性对子类是不可见的 |
组合继承 | 原型链和借用构造函数组合 | 以上缺陷可以解决 | 存在重复定义的属性和方法 |
寄生式继承 | 构建临时构造函数,重写原型,返回新的对象 | 没想到,应用场景不多(~ o ~)~zZ | 不适用于自定义类型,引用类型属性会共享 |
寄生式继承 | 是否必填 | 解决综上问题 | 不易理解,待消化 |
以上内容仅个人理解,如有错误还请谅解 (〃'▽'〃)
//代码附录
//1.
function inherit(Sup, Sub){
function F(){}
F.prototype = Sup.prototype;
var obj = new F();
obj.constructor = Sub;
Sub.prototype = obj;
}
function Sup(name){
this.name = name;
this.items = [1, 2, 3];
}
Sup.prototype.getItems = function(){
console.log("items: ", this.items);
}
Sup.prototype.getName = function(){
console.log("name: ", this.name);
}
function Sub(name, age){
Sup.call(this, name);
this.age = age;
}
inherit(Sup, Sub);
Sub.prototype.getAge = function(){
console.log("age: ", this.age);
}
Sub.prototype.getName = function(){
console.log("nameForSub: ", this.name);
}
function Sub1(name, age){
Sup.call(this, name);
this.age = age;
}
inherit(Sup, Sub1);
Sub1.prototype.getAge = function(){
console.log("age: ", this.age);
}
var a = new Sub("lilei", 25);
a.items.push(4);
a.getName();
a.getAge();
a.getItems();
var b = new Sub("hanmeimei", 24);
b.getName();
b.getAge();
b.getItems();
var c = new Sub1("jim", 23);
c.getName();
c.getAge();
c.getItems();
//2.
function inherit(Sup, Sub){
Sub.prototype = Sup.prototype;
}
function Sup(name){
this.name = name;
this.items = [1, 2, 3];
}
Sup.prototype.getItems = function(){
console.log("items: ", this.items);
}
Sup.prototype.getName = function(){
console.log("name: ", this.name);
}
function Sub(name, age){
Sup.call(this, name);
this.age = age;
}
inherit(Sup, Sub);
Sub.prototype.getAge = function(){
console.log("age: ", this.age);
}
Sub.prototype.getName = function(){
console.log("nameForSub: ", this.name);
}
function Sub1(name, age){
Sup.call(this, name);
this.age = age;
}
inherit(Sup, Sub1);
Sub1.prototype.getAge = function(){
console.log("age: ", this.age);
}
var a = new Sub("lilei", 25);
a.items.push(4);
a.getName();
a.getAge();
a.getItems();
var b = new Sub("hanmeimei", 24);
b.getName();
b.getAge();
b.getItems();
var c = new Sub1("jim", 23);
c.getName();
c.getAge();
c.getItems();