千峰逆战班,千峰斯坦僧接班人之一打卡第二天其二。
我要成为这次疫情期间,最闲得码农!!!!
一、为什么要有JS继承
假如每一个实例对象,都要有自己的属性和方法的副本。这不仅无法做到数据共享,也是极大的资源浪费。(这就和我们现实中会继承父母的资产一样,你是可以选择不继承的,但是浪费钱啊)
二、JS继承的三种方式
1.原型继承
//构建一个父类
function Person(name) {
this.name = name
}
//父类原型对象上添加一个函数sayHi
Person.prototype.sayHi = function () {
console.log('hello world')
}
// 实例化对象p,并传入参数的属性name值为Jack
var p = new Person(‘Jack’)
console.log(p)
/*
p = {
name: 'Jack',
__proto__: Person.prototype {
sayHi: function () {},
__proto__: Object.prototype
}
}
*/
// 构建一个子类
function Student(age) {
this.age = age
}
// 让 子类 继承 父类
Student.prototype = new Person('Jack')
var s1 = new Student(18)
console.log(s1)
/*
s1 = {
age: 18,
__proto__: Student.prototype === p {
name: 'Jack',
__proto__: Person.prototype {
sayHi: function () {},
__proto__: Object.prototype
}
}
}
*/
原型链继承总结:子类.prototype = 父类的实例;
//原型链继承是改变了子类的原型指向(这就像我和爸爸之间的关系,我的原型链(proto)指向了我的爸爸,你要问我有什么,我把我所有的属性和方法展示给你看,然后我的身上还有一个 proto ,从那里可以查询到我爸爸有啥)
缺点:
- 继承下来的属性并没有在该子类身上,而是在其 proto 上
- 要用的属性和方法虽然被继承,但是在多个位置,不便于寻找
- (不便于寻找)对书写,维护和阅读代码不太友好
2.构造函数继承
//前提:需要使用call函数改变函数内部 this 指向的方法
// 1. 一个父类
function Person(name, gender) {
this.name = name
this.gender = gender
}
Person.prototype.sayHi = function () {
console.log('hello world')
}
// 2. 一个子类
function Student(age, name, gender) {
this.age = age
// 这里的 this 指向 的是 Student 的当前实例(s1)
// 调用 Person 函数, 把函数内部的 this 指向了 Student 的实例
// 也就是现在让 Person 函数内部的 this 指向了 s1
// Person 里面的代码
// this.name 相当于是 s1.name
// 利用父类构造函数体, 向子类身上添加成员
Person.call(this, name, gender)
}
var s1 = new Student(18, 'Rose', '男')
console.log(s1)
构造函数继承总结:父类.call(this,属性,方法)
//构造函数继承方式是利用父类构造函数体, 向子类身上添加成员(我爸会钓鱼,我不会,所以我要继承他的钓鱼方法就要让他教我【爸爸.call(我,钓鱼)】)
优点:
- 不用一个个在 proto 上找属性和方法了
- 要用几个属性,在call函数里传参就行(你想学几个技能,就让你爸教给你几个)
缺点: - 只能继承父类的属性和方法,不能继承父类原型的属性和方法(因为你只找到你爸爸教你技能,所以你爷爷会啥你不清楚)
- 父类的方法被继承,每new对象时都会有同样的函数空间出现,所以继承父类方法会造成资源浪费
//因为构造函数继承支持多重继承,所以你要继承哪个父类,就 哪个父类.call(this,属性)(这意思就是你要向谁学习技能,就让他.call(你,技能))
3.组合继承
//组合继承:把原型链继承和构造函数继承融合在一起。
// 1. 父类构造函数
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayHi = function () {
console.log('hello world')
}
// 2. 子类构造函数
function Student(gender, name, age) {
this.gender = gender
// 构造函数继承
// call 方法的参数
// 第一个是要改变的this 指向
// 从第二个参数开始依次给函数传递参数
Person.call(this, name, age) // 这里的 this 就是 Student 的实例
// 调用一个 Person 函数, 并且把 Person 里面的 this 改变成 Student 的实例
}
// 原型继承
// 能继承属性和方法的
// s1 的 sayHi 方法是依靠这个 原型继承 继承下来的
Student.prototype = new Person()
var s1 = new Student('男', 'Jack', 18)
console.log(s1)
组合继承总结:父类.call(this,属性,属性),再子类.prototype = 父类的实例
优点:
- 将属性继承下来了,不用再一个个到_proto_找了(构建函数继承的优点)
- 方法也继承下来了(原型链继承的优点)
注意:组合继承方式的子类里面调用继承方式不能调换,因为构建函数是根据参数决定继承哪些属性或方法,如果不写,等同于不继承
好好学习,天天向上。中国加油,武汉加油,千峰加油!