哈喽,我是前端菜鸟JL😄 下面分享一下继承这个专题
前置知识
构造函数的属性
funcion A(name) {
this.name = name; // 实例基本属性 (该属性,强调私有,不共享)
this.arr = [1]; // 实例引⽤属性 (该属性,强调私⽤,不共享)
this.say = function () { // 实例引⽤属性 (该属性,强调复⽤,需要共享)
console.log('hello')
}
}
注意:数组和⽅法都属于‘ 实例引⽤ 属性’,但是数组强调私有、不共享的。⽅法需要复⽤、共享。
在构造函数中,⼀般很少有数组形式的引⽤属性,⼤部分情况都是: 基本属性 + ⽅法。
什么是原型对象 每个函数都有prototype,它就是原型对象,而通过new实例化出来的对象有个__proto__属性,指向原型对象
let a = new A()
a.__proto__ = A.prototype
// prototype的结构如下
A.prototype = {
constructor: A,
...其他原型上的属性和方法
}
原型对象的作用
主要用途:为每个实例对象存储分享的方法和属性
它仅仅是⼀个普通对象⽽已。并且所有的实例是共享同⼀个原型对象,因此有别于实例⽅法或属性,原型对象仅有⼀份。⽽实例有很多份,且实例属性和⽅法是独⽴的。
在构造函数中:为了属性(实例基本属性)的私有性、以及⽅法(实例引⽤属性)的复⽤、共享。我们提倡:
- 将属性封装在构造函数中
- 将方法定义在原型对象上
function A(name) {
this.name = name // 属性定义在构造函数上,强调私有,不共享
}
A.prototype.say = function() { // 方法定义在原型对象上,强调共享,复用
console.log('111')
}
继承
本质:复制,即重写原型对象,代之以一个新类型的实例
原型链继承
function Fn() {
this.name = 'Jack'
}
function fn () {}
fn.prototype = new Fn() // 重点
let test = new fn()
console.log(test.name) // 'Jack'
缺点:多实例共享属性或方法,改动一个实例属性就会影响到其他实例
借用构造函数继承
function Fn() {
this.name = 'Jack'
}
function fn () {
Fn.call(this) // 重点,利用构造函数改变this指向
// Fn.apply(this)
}
let test = new fn()
console.log(test.name) // 'Jack'
缺点:
只能继承父类的实例属性和方法,不能继承原型属性和方法
无法实现复用,每个子类都有父类实例函数的副本,影响性能
组合继承
实现:原型继承+借用构造函数继承
function Fn() {
this.name = 'Jack'
}
Fn.prototype.say = function() { console.log('Mack') }
function fn() {
Fn.call(this)
}
fn.prototype = new Fn()
const test = new fn()
console.log(test.say())
优点: 可以继承父类原型属性和方法
缺点:存在性能问题,Fn被调用两次
原型式继承
ES5之前
const Fn = { name: 'Jack' }
function createFn(Fn) {
function fn() {}
fn.prototype = Fn
return new fn()
}
const test = createFn(Fn)
ES6之后
const Fn = { name: 'Jack' }
const test = Object.create(Fn)
优点:对一个对象进行浅拷贝创建另一个对象,同时继承该对象的原型属性 缺点:由于是浅拷贝,所有实例共享,如果是引用值,存在污染可能。
寄生继承
实现:在原型式继承的基础上,增强对象,返回构造函数
function createFn(Fn) {
const clone = object(Fn) // 通过调用object()函数创建一个新对象 new Object(Fn)
clone.sayHi = function() { // 添加方法增强对象
console.log('hi')
}
return clone // 返回这个对象
}
const person = { name: 'Jack' }
const test = createFn(person)
test.sayHi() // hi
缺点:(同原型式继承) 多实例共享相同属性,存在篡改可能 无法传递参数
寄生组合式继承(最常用,也是最成熟的方法,现在库实现)
实现:借用构造函数继承+原型式继承
function Fn() { this.name = 'Jack' }
Fn.prototype.say = function() { console.log('111') }
function fn() {
Fn.call(this)
this.age = 18
}
// 重点
fn.prototype = Object.create(Fn.prototype)
fn.prototype.constructor = fn
const test = new fn()
ES6继承
extends
class Test {
constructor() {
this.name = 'aaa'
}
}
class test extends Test {
constructor() {
super()
}
}
const test1 = new test()
test1.name // 'aaa'
ES5和ES6主要区别
- ES5主要是先创建子类实例this,然后通过apply(this, argments)添加父类的方法
- ES6则是先通过super调用父类构造函数,创建父类this,包含父类的属性和方法,然后子类继承父类this,同时可以通过constructor修饰ths,添加一些属性等。
结语
希望能给你带来帮助✨~
分享不易,点赞鼓励🤞