1. 构造函数继承(Call式继承)
借助call函数,继承的是属性(或者使用apply函数)
参数特别多的话就要使用apply+arguments(里面的Person)
function Person(name,age){
this.name = name
this.age =age
}
function Star(name,age){
/* this.name = '张三'
this.age =23 */
Person.call(this, name,age)// 这里后面的name和age传给了Person方法(是Star的实参,外面不传实参,直接在这里写实参也可以)
// Person.apply(this, [name, age])
// Person中的this指向call后面括号里的this,而括号里的this指向new Star创建的实例
}
const s =new Star()
方法不能往构造函数上面挂,存在内存的浪费,往原型对象上挂载(多个实例访问的是同一个原型对象)
// 如果是下面这种
function Person(name,age){
this.name = name
this.age =age
this.say=function(){ console.log('11') }
}
const p1 = Person(xx,xx)
const p2 = Person(yy,yy)
//这样p1和p2实例上面的say方法不相同,被重新创建了一份
// 如果是下面这样,那么重新new的实例指向的say是同一个地址,性能提高
Person.prototype.say=...
子类继承父类
2. 原型继承
通过改造原型链去继承父类构造函数原型上的方法
call/apply不会访问原型,只会继承属性,实例才会访问原型上的属性或者方法
function Person(name,age){
this.name = name
this.age =age
}
Person.prototype,say = function(){
console.log('hello world')
}
function Star(name,age){
}
// 原型继承 => 继承的是方法
// 直接把Star的原型指向Person的实例
Star.prototype = new Person()
// 误区 不能 Star.prototype = Person.prototype
// 这样的话,Star的原型指向了Person的原型,这样给Star的原型添加方法会影响Person的原型,二者指向同一地址
// 同时这样继承了Person的实例之后,发现Star.prototype.constructor指向了Star。(实际上是p1.constructor,实例没有去找原型的,就是p1.___proto__.constructor,注意p1 = new Person())
// 还需要
Star.prototype.constructor = Star
const zs = new Star('尼古拉斯', 30)
// 这样才能使用
Star.prototype.constructor ===Star// true
zs.constructor ===Star//true
zs.__proto__.constructor ===Star//true
说明:
虽然原型继承也继承了父类的属性,但是这里不会传递参数,而且子类Star构造函数可以随意给自己的prototype添加属性和方法而覆盖父类传过来的静态属性,原型继承主要继承的就是父类的方法,通过原型链找到父类的方法
3. 组合继承
属性会使用this挂载到构造函数上,方法会放在构造函数的原型上
function Person(name,age){
this.name = name
this.age =age
}
Person.prototype.say = function(){
console.log('hello world')
}
function Star(name,age){
Person.call(this, name, age)
}
// 原型继承 => 继承的是方法
// 直接把Star的原型指向Person的实例
Star.prototype = new Person()
Star.prototype.constructor = Star
4. 寄生组合继承(优化原型继承)--常用
之前原型继承中把父类构造函数的静态属性也继承过来了,但是根本就不需要new的这一过程,只想继承父类构造函数的原型上的方法。
利用Object.create()方法来进行优化,省去了不必要的new操作
- Object.create(xx)会创建一个新对象
- 并将这个新对象对象的__proto__指向传入的参数对象xx
可以这样改造
function Person(name,age){
this.name = name
this.age =age
}
Person.prototype.say = function(){
console.log('hello world')
}
function Star(name,age){
this.hobby='唱歌'
}
// Star.prototype = new Person()
Star.prototype = Object.create(Person.prototype)
Star.prototype.constructor = Star
const zs = new Star('尼古拉斯', 30)
5. ES6的extends继承
先介绍下class
// 原来写法
/* function Person(name, age){
this.name = name
this.age = age
}
Person.prototype.sayhi=function(){}
Person.prototype.jump=function(){} */
// class关键字创建两个类,可以直接new
// 好处:构造函数的属性和方法比较分散,需要分开写,而class创建的类是一个整体
// 人类
// 注意person后面没有小括号
class Person{
// constructor类似于之前的构造函数
constructor(name, age){
// 1.实例属性/方法
this.name = name
this.age = age
//### 写在这里的可以接受constructor的参数
this.state ={
age: 18
}
}
// 1.实例属性/方法,等价于###处的代码。写在这里的无法接收参数(不要用const声明)
state = {
age:18
}
handldClick = () => {}
// 固定写法,函数之间没有逗号,不能改成function或者箭头函数
// 底层:这两个方法加在了Person的prototype上
// 2.原型方法(es6不能定义原型属性,原型属性本来就应该不一样)
sayhi(){
console.log('你好')
}
jump(){
console.log('会跳')
}
// 3.静态属性/方法
static version = 888
static eat(){
console.log('eat')
}
}
// 老师类
class Teacher{
constructor(name, age, lesson){
this.name = name
this.age = age
this.lesson = lesson
}
sayhi(){
console.log('你好')
}
jump(){
console.log('会跳')
}
}
const p =new Person('zs', 20)
const t =new Teacher('li', 20, 'en')
console.log(p, t)
我们发现t实例和p实例出现了重复的属性和方法。借助extends和super关键字来完成继承
注意这里底层原理是寄生式组合继承
class Person{
constructor(name, age){
this.name = name
this.age = age
}
sayhi(){
console.log('你好')
}
jump(){
console.log('会跳')
}
}
class Teacher extends Person{
// 不写constructor,默认会调用call继承父类Person的name和age属性
teach(){
console.log('会教书')
}
}
const t = new Teacher()
// 老师类
class Teacher extends Person{
constructor(name, age, lesson){
// super关键字继承父类构造函数的属性(进行实例的属性初始化)
/* 注意:
1.super关键字必须要有
2.顺序不能反了,必须先继承父类(先super),在写自己的属性
*/
super(name, age)
this.lesson = lesson
}
teach(){
console.log('会教书')
}
}
做了三件事
- Person.call(this, name, age)借调父类属性
- Teacher.prototype = Object.create(Person.prototype)借调父类方法
- Teacher.prototype.constructor = Teacher将原型的constructor指回自身构造函数