属性(方法)查找方式:先找 构造函数内部,是否具有对应的属性,如果有直接输出,如果构造函数没有, 再找原型
1.原型继承
原型继承:将父类对象挂载到子类原型上面
优点:原型继承既能继承到属性,也能继承到原型上的方法。
缺点:继承的属性的值都是继承时确定的,无法进行传参修改
<script>
//创建一个人类
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex
Person.prototype.eat = function () {
console.log(this.name + '正在吃饭')
}
}
//创建学生的构造函数
function Student(name, age, sex) {
}
//原型继承 将父类对象挂载到儿类原型上面
Student.prototype = new Person('小明', 18, '男')
Student.prototype.show = function () {
console.log('学生名字:' + this.name + '年龄:' + this.age + '性别:' + this.sex)
}
var s = new Student('小红', 16, '女')
s.eat()
s.show()
console.log(s)
//优点:原型继承既能继承到属性,也能继承到原型上的方法。
//缺点:所有属性的值,只和创建Person对象时保持一致(但是继承的属性的值都是继承时确定的,无法进行传参修改)
2.冒泡继承
冒泡继承:通过改变this的指向性Call和apply方法,实现的继承方法
优点: 冒充继承可以传参修改属性
缺点:无法继承原型,只是调用了一次函数
<script>
//创建一个人类
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex
Person.prototype.eat = function () {
console.log(this.name + '正在吃饭')
}
}
//创建老师类
function Teacher(name, age, sex) {
//冒泡继承 通过改变this的指向性,实现的继承方法
Person.call(this, name, age, sex)//call改变this指向
}
Teacher.prototype.show = function () {
console.log('老师名字:' + this.name + '年龄:' + this.age + '性别:' + this.sex)
}
var t = new Teacher('王一', 30, '男')
t.show()
// t.eat()
console.log(t)
//优点: 冒充继承可以传参修改属性
//缺点:无法继承原型,只是调用了一次函数
3.组合继承
<script>
//创建一个人类
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex
Person.prototype.eat = function () {
console.log(this.name + '正在吃饭')
}
}
//组合继承 最优解决方案
function User(name, age, sex) {
//构造函数内部采用冒充继承
Person.call(this, name, age, sex)
}
//构造函数外部采用原型继承(不传参,只继承原型上的方法)
User.prototype = new Person()
User.prototype.show = function () {
console.log('名字:' + this.name + '年龄:' + this.age + '性别:' + this.sex)
}
var u = new User('王五', 40, '男')
u.show()
u.eat()
console.log(u)
</script>
实例:
1、创建一个人类然后继承学生类以及教师类,分别通过三种不同的继承方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//创建一个人类
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex
Person.prototype.eat = function () {
console.log(this.name + '正在吃饭')
}
}
//创建学生的构造函数
function Student(name, age, sex) {
}
//原型继承 将父类对象挂载到儿类原型上面
Student.prototype = new Person('小明', 18, '男')
Student.prototype.show = function () {
console.log('学生名字:' + this.name + '年龄:' + this.age + '性别:' + this.sex)
}
var s = new Student('小红', 16, '女')
s.eat()
s.show()
console.log(s)
//优点:原型继承既能继承到属性,也能继承到原型上的方法。
//缺点:所有属性的值,只和创建Person对象时保持一致(但是继承的属性的值都是继承时确定的,无法进行传参修改)
//创建老师类
function Teacher(name, age, sex) {
//冒泡继承 通过改变this的指向性,实现的继承方法
Person.call(this, name, age, sex)//call改变this指向
}
Teacher.prototype.show = function () {
console.log('老师名字:' + this.name + '年龄:' + this.age + '性别:' + this.sex)
}
var t = new Teacher('王一', 30, '男')
t.show()
// t.eat()
console.log(t)
//优点: 冒充继承可以传参修改属性
//缺点:无法继承原型,只是调用了一次函数
//组合继承 最优解决方案
function User(name, age, sex) {
//构造函数内部采用冒充继承
Person.call(this, name, age, sex)
}
//构造函数外部采用原型继承(不传参,只继承原型上的方法)
User.prototype = new Person()
User.prototype.show = function () {
console.log('名字:' + this.name + '年龄:' + this.age + '性别:' + this.sex)
}
var u = new User('王五', 40, '男')
u.show()
u.eat()
console.log(u)
</script>
</body>
</html>
2、自己写一个原型链继承,独立完成原型链图
<script>
//定义一个作家的构造函数
function Writer(name, production, age) {
this.name = name;
this.production = production;
this.age = age
}
Writer.prototype.writ = function () {
console.log(this.name + '正在写文章')
}
//定义一个人
function Man(name, production, age) {
}
Man.prototype = new Writer('小明', '好兄弟', 20);
Man.prototype.move = function () {
console.log(this.name + '正在走' + '作品:' + this.production + '有:' + this.age)
}
var m = new Man('小米', '天天向上', 15);
m.move();
m.writ();
var n = new Man('小王', '天数据', 20);
n.writ();
n.move();
</script>