继承的目的是:重复利用另外一个对象的属性和方法.
目录
1 原型链继承
将父类的实例对象作为子类的原型 Student.prototype = new person()
// 父类: 公共属性和方法
function Person() {
this.name = "why"
this.friends = []
}
Person.prototype.eating = function() {
console.log(this.name + " eating~")
}
// 子类: 特有属性和方法
function Student() {
this.sno = 111
}
var p = new Person()
Student.prototype = p
Student.prototype.studying = function() {
console.log(this.name + " studying~")
}
// name/sno
var stu = new Student()
// console.log(stu.name)
// stu.eating()
// stu.studying()
// 原型链实现继承的弊端:
// 1.第一个弊端: 打印stu对象, 继承的属性是看不到的
// console.log(stu.name)
// 2.第二个弊端: 创建出来两个stu的对象
var stu1 = new Student()
var stu2 = new Student()
// 直接修改对象上的属性, 是给本对象添加了一个新属性
stu1.name = "kobe"
console.log(stu2.name)
// 获取引用, 修改引用中的值, 会相互影响
stu1.friends.push("kobe")
console.log(stu1.friends)
console.log(stu2.friends)
// 3.第三个弊端: 在前面实现类的过程中都没有传递参数
var stu3 = new Student("lilei", 112)
2 构造函数继承
// 父类: 公共属性和方法
function Person(name, age, friends) {
// this = stu
this.name = name
this.age = age
this.friends = friends
}
Person.prototype.eating = function() {
console.log(this.name + " eating~")
}
// 子类: 特有属性和方法
function Student(name, age, friends, sno) {
Person.call(this, name, age, friends)
// this.name = name
// this.age = age
// this.friends = friends
this.sno = 111
}
var p = new Person()
Student.prototype = p
Student.prototype.studying = function() {
console.log(this.name + " studying~")
}
// name/sno
var stu = new Student("why", 18, ["kobe"], 111)
// console.log(stu.name)
// stu.eating()
// stu.studying()
// 原型链实现继承已经解决的弊端
// 1.第一个弊端: 打印stu对象, 继承的属性是看不到的
console.log(stu)
// 2.第二个弊端: 创建出来两个stu的对象
var stu1 = new Student("why", 18, ["lilei"], 111)
var stu2 = new Student("kobe", 30, ["james"], 112)
// // 直接修改对象上的属性, 是给本对象添加了一个新属性
// stu1.name = "kobe"
// console.log(stu2.name)
// // 获取引用, 修改引用中的值, 会相互影响
stu1.friends.push("lucy")
console.log(stu1.friends)
console.log(stu2.friends)
// // 3.第三个弊端: 在前面实现类的过程中都没有传递参数
// var stu3 = new Student("lilei", 112)
强调: 借用构造函数也是有弊端:
1.: Person函数至少被调用了两次
2. stu的原型对象上会多出一些属性, 但是这些属性是没有存在的必要
3 组合继承
构造函数继承实例属性 将父类的原型作为子类的原型,使用原型链实现对原型属性和方法的继承 Student.prototype = Object.create(Person.prototype)
// 父类: 公共属性和方法
function Person(name, age, friends) {
// this = stu
this.name = name;
this.age = age;
this.friends = friends;
}
Person.prototype.eating = function () {
console.log(this.name + ' eating~');
};
// 子类: 特有属性和方法
function Student(name, age, friends, sno) {
Person.call(this, name, age, friends);
// this.name = name
// this.age = age
// this.friends = friends
this.sno = sno;
}
// 直接将父类的原型赋值给子类, 作为子类的原型
Student.prototype = Person.prototype;
Student.prototype.studying = function () {
console.log(this.name + ' studying~');
};
// name/sno
var stu = new Student('why', 18, ['kobe'], 111);
console.log(stu);
stu.eating();
问题
1. 构造函数会被调用两次: 一次在创建子类型原型对象的时候, 一次在创建子类型实例的时候.
2. 类型中的属性会有两份: 一份在原型对象中, 一份在子类实例中.
4 原型继承
包含引用类型的属性值始终都会共享相应的值,这点跟原型链继承一样
var obj = {
name: "why",
age: 18
}
//将传入的对象作为创建的对象的原型
var info = Object.create(obj)
// 原型式继承函数
function createObject1(o) {
var newObj = {}
Object.setPrototypeOf(newObj, o)
return newObj
}
function createObject2(o) {
function Fn() {}
Fn.prototype = o
var newObj = new Fn()
return newObj
}
// var info = createObject2(obj)
var info = Object.create(obj)
console.log(info)
console.log(info.__proto__)
5 寄生式继承
创建一个封装继承过程的函数, 该函数在内部以某种方式来增强对象,最后再将这个对象返回;
var personObj = {
running: function() {
console.log('running');
},
};
function createStudent(name) {
var stu = Object.create(personObj);
stu.name = name;
stu.studying = function() {
console.log('studying~');
};
return stu;
}
var stuObj = createStudent('why');
var stuObj1 = createStudent('kobe');
var stuObj2 = createStudent('james');
6 寄生组合式继承
function createObject(o) {
function Fn() {}
Fn.prototype = o;
return new Fn();
}
function inheritPrototype(SubType, SuperType) {
// SubType.prototype = Object.create(SuperType.prototype);
// 或者
SubType.prototype = createObject(SuperType.prototype);
Object.defineProperty(SubType.prototype, 'constructor', {
enumerable: false,
configurable: true,
writable: true,
value: SubType,
});
}
function Person(name, age, friends) {
this.name = name;
this.age = age;
this.friends = friends;
}
Person.prototype.running = function() {
console.log('running~');
};
Person.prototype.eating = function() {
console.log('eating~');
};
function Student(name, age, friends, sno, score) {
// 原型式继承函数
Person.call(this, name, age, friends);
this.sno = sno;
this.score = score;
}
inheritPrototype(Student, Person);
Student.prototype.studying = function() {
console.log('studying~');
};
var stu = new Student('why', 18, ['kobe'], 111, 100);
console.log(stu);
stu.studying();
stu.running();
stu.eating();
console.log(stu.constructor.name);