js的继承

1
2
3
4
5
6
7
8
9
10
11
function Parent() {
this.name = 'hh'
}

Parent.prototype.getname = function () {
console.log(this.name);
}

function Child() {

}

原型链继承

1
2
3
4
5
Child.prototype = new Parent();

let child1 = new Child();

// 就是创建一个子构造函数原型上继承new一个父构造函数,再用子构造函数构建一个对象

优点:方法复用,

缺点:属性共用

构造函数继承

1
2
3
4
5
6
7
function Child() {
// 当使用这个构造函数创建实例的时候,prototype属性指向的原型对象就成为实例的原型对象
Parent.call(this);
}

// 等于复制父元素的基本属性给子元素
let child1 = new Child();

优点:实例属性相互独立,

缺点:父类方法不能复用,继承不了父类原型上的属性

组合继承

1
2
3
4
5
6
7
8
9
10
11
12
13
function Child(name, link) {
Parent.call(this, name); // 核心 第二次
this.link = link;
}

Child.prototype = new Parent(); // 核心 第一次

// 没修复前指向Parent
// 修复构造函数指向的
Child.prototype.constructor = Child

// 就把前两个结合一起用了,但是会复用两次父构造函数
let boy1 = new Child();

寄生组合继承

1
2
3
4
5
6
7
8
9
10
11
function Child(name,like) {
Parent.call(this,name,like) // 核心
this.like = like;
}
Child.prototype = Object.create(Parent.prototype) // 核心 通过创建中间对象,子类原型和父类原型,就会隔离开。不是同一个啦,有效避免了上一个的缺点。

<!--这里是修复构造函数指向的代码-->
Child.prototype.constructor = Child

let boy1 = new Child(); // constructor是Child
let p1 = new parent(); // constructor是Parent

Object.create()本质

1
2
3
4
5
6
function object(o) {
// 其中,o 是新创建对象的原型(对象)
function F() {}
F.prototype = o
return new F()
}
  1. 创建一个空对象{}
  2. 指定该对象原型为 o
  3. 返回该对象

new本质

1
2
3
4
5
6
7
8
9
10
function mynew(Func, ...args) {
// 1.创建一个新对象
const obj = {}
// 2.新对象原型指向构造函数原型对象
obj.__proto__ = Func.prototype
// 3.将构建函数的this指向新对象
let result = Func.apply(obj, args)
// 4.根据返回值判断
return result instanceof Object ? result : obj
}

参考

组合继承优化1

1
2
3
4
5
6
7
8
9
10
11
12
function Child(name, link) {
Parent.call(this, name); // 核心
this.link = link;
}

// 如果修复了就会导致父类实例的构造函数也一起改变
Child.prototype.constructor = Child

Child.prototype = Parent.prototype; // 核心 子原型和父原型一样

let boy1 = new Child();
let p1 = new parent(); // constructor都是Child