目录
  1. 1. 原型链继承
    1. 1.1. 特点
    2. 1.2. 缺点
  2. 2. 构造函数继承
    1. 2.1. 特点
    2. 2.2. 缺点
  3. 3. 组合继承
    1. 3.1. 特点
    2. 3.2. 缺点
  4. 4. 拷贝继承
  5. 5. new一个对象背后做了些什么?
JS也能玩继承

原型链继承

  1. 定义父类型构造函数
  2. 给父类型的原型添加方法
  3. 定义子类型的构造函数
  4. 创建父类型的对象赋值给子类型的原型
  5. 将子类型原型的构造属性设置为子类型
  6. 给子类型原型添加方法
  7. 创建子类型的对象: 可以调用父类型的方法
// 父类型
function Supper(){
this.supProp = 'Supper property'
}
Supper.prototype.showSupperPropProp = function(){
console.log(this.supProp)
}

// 子类型
function Sub(){
this.subProp = 'Sub property'
}

// 子类型的原型为父类型的一个实例对象
Sub.prototype = new Supper()
Sub.prototype.constructor = Sub //修正constructor属性
Sub.prototype.showSubProp = function () {
console.log(this.subProp)
}

// Sub对象实例化
var sub = new Sub()
// 调用父类的 showSupperPropProp 方法
sub.showSupperPropProp()
// 调用Sub的原型的方法
sub.showSubProp()

console.log(sub) // Sub

注意:

  1. 给原型添加方法一定要放在替换原型的语句之后
  2. 在通过原型链实现继承时,不能使用对象字面量创建原型方法

特点

  • 子类的实例也是父类的实例
  • 可以方便的基础父类型的原型中的方法,但是属性的继承无意义

缺点

  • 只执行一次,无法给属性传值
  • 属性的继承无意义

构造函数继承

  1. 定义父类型构造函数
  2. 定义子类型构造函数
  3. 在子类型构造函数中调用父类型构造
function Person(name, age) {
this.name = name
this.age = age
}
function Student(name, age, price) {
Person.call(this, name, age) // 相当于: this.Person(name, age)
this.price = price
}

var s = new Student('Tom', 20, 14000)
console.log(s.name, s.age, s.price)

console.log(s) // Tom 20 14000

基本思想:

  • 在子类型构造函数的内部调用超类型构造函数(通过使用apply()call()方法也可以在(将来)新创建的对象上执行构造函数)
  • 在子类的内部调用父类,通过call改变父类中this的指向;等于是复制父类的实例属性给子类

特点

  • 创建子类实例时,可以向父类传递参数
  • 可以实现多继承
  • 可以方便的继承父类型的属性,但是无法继承原型中的方法

缺点

  • 实例并不是父类的实例,只是子类的实例
  • 无法继承原型中的方法
  • 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

那么一个是一个不能搞属性,不能搞方法,怎么让他同时都能搞呢?就要提到下面这个方法——组合继承

组合继承

原型链+借用构造函数的组合继承

  1. 利用原型链实现对父类型对象的方法继承

  2. 利用super()借用父类型构建函数初始化相同属性

 // 定义父类Person
function Person(name, age) {
this.name = name
this.age = age
}
// 为Person原型添加方法
Person.prototype.setName = function (name) {
this.name = name
}
// 定义子类 Student
function Student(name, age, price) {
Person.call(this, name, age) // 为了得到属性
this.price = price
}
// 子类型的原型为父类型的一个实例对象
Student.prototype = new Person() // 为了能看到父类型的方法
Student.prototype.constructor = Student //修正constructor属性

// 为子元素原型添加方法
Student.prototype.setPrice = function (price) {
this.price = price
}

var s = new Student('Tom', 24, 15000)
s.setName('Bob')
s.setPrice(16000)
console.log(s.name, s.age, s.price) // Bob 24 16000

特点

  • 既是子类的实例,也是父类的实例
  • 可传参
  • 函数可复用

缺点

  • 两次调用父类构造函数:(第一次是在创建子类原型的时候,第二次是在子类构造函数内部)
  • 造成子类继承父类的属性
    • 一组在子类实例上
    • 一组在子类原型上
    • 即在子类原型上创建不必要的多余的属性

拷贝继承

Person的构造中有原型prototype

prototype就是一个对象,那么里面,age,sex,height,play都是该对象中的属性或者方法

function Person() {
}
Person.prototype.age=10;
Person.prototype.sex="男";
Person.prototype.height=100;
Person.prototype.play=function () {
console.log("玩的好开心");
};
var obj2={};


for(var key in Person.prototype){
obj2[key]=Person.prototype[key];
}
console.dir(obj2);
obj2.play(); // 玩的好开心

new一个对象背后做了些什么?

  • 创建一个空对象
  • 给对象设置__proto__, 值为构造函数对象的prototype属性值 this.__proto__ = Fn.prototype
  • 执行构造函数体(给对象添加属性/方法)
文章作者: Jachie Xie
文章链接: https://xjc5772.github.io/2020-03/25/%E5%AD%A6%E4%B9%A0/%E5%89%8D%E7%AB%AF%E5%AD%A6%E4%B9%A0/JS/JS%E7%BB%A7%E6%89%BF/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 XJC&Blog
打赏
  • 微信
  • 支付宝

评论