js中的继承的实现方式

继承的目的是:重复利用另外一个对象的属性和方法.

目录

1 原型链继承

2 构造函数继承

3 组合继承 

4 原型继承

5 寄生式继承

6 寄生组合式继承


1 原型链继承

将父类的实例对象作为子类的原型 Student.prototype = new person()

// 父类: 公共属性和方法
function Person() {
  this.name = "why"
  this.friends = []
}

Person.prototype.eating = function() {
  console.log(this.name + " eating~")
}

// 子类: 特有属性和方法
function Student() {
  this.sno = 111
}

var p = new Person()
Student.prototype = p

Student.prototype.studying = function() {
  console.log(this.name + " studying~")
}


// name/sno
var stu = new Student()

// console.log(stu.name)
// stu.eating()

// stu.studying()


// 原型链实现继承的弊端:
// 1.第一个弊端: 打印stu对象, 继承的属性是看不到的
// console.log(stu.name)

// 2.第二个弊端: 创建出来两个stu的对象
var stu1 = new Student()
var stu2 = new Student()

// 直接修改对象上的属性, 是给本对象添加了一个新属性
stu1.name = "kobe"
console.log(stu2.name)

// 获取引用, 修改引用中的值, 会相互影响
stu1.friends.push("kobe")

console.log(stu1.friends)
console.log(stu2.friends)

// 3.第三个弊端: 在前面实现类的过程中都没有传递参数
var stu3 = new Student("lilei", 112)

2 构造函数继承

// 父类: 公共属性和方法
function Person(name, age, friends) {
  // this = stu
  this.name = name
  this.age = age
  this.friends = friends
}

Person.prototype.eating = function() {
  console.log(this.name + " eating~")
}

// 子类: 特有属性和方法
function Student(name, age, friends, sno) {
  Person.call(this, name, age, friends)
  // this.name = name
  // this.age = age
  // this.friends = friends
  this.sno = 111
}

var p = new Person()
Student.prototype = p

Student.prototype.studying = function() {
  console.log(this.name + " studying~")
}


// name/sno
var stu = new Student("why", 18, ["kobe"], 111)

// console.log(stu.name)
// stu.eating()

// stu.studying()


// 原型链实现继承已经解决的弊端
// 1.第一个弊端: 打印stu对象, 继承的属性是看不到的
console.log(stu)

// 2.第二个弊端: 创建出来两个stu的对象
var stu1 = new Student("why", 18, ["lilei"], 111)
var stu2 = new Student("kobe", 30, ["james"], 112)

// // 直接修改对象上的属性, 是给本对象添加了一个新属性
// stu1.name = "kobe"
// console.log(stu2.name)

// // 获取引用, 修改引用中的值, 会相互影响
stu1.friends.push("lucy")

console.log(stu1.friends)
console.log(stu2.friends)

// // 3.第三个弊端: 在前面实现类的过程中都没有传递参数
// var stu3 = new Student("lilei", 112)

强调: 借用构造函数也是有弊端:
 1.: Person函数至少被调用了两次
 2. stu的原型对象上会多出一些属性, 但是这些属性是没有存在的必要

3 组合继承 

构造函数继承实例属性 将父类的原型作为子类的原型,使用原型链实现对原型属性和方法的继承  Student.prototype = Object.create(Person.prototype)

// 父类: 公共属性和方法
function Person(name, age, friends) {
  // this = stu
  this.name = name;
  this.age = age;
  this.friends = friends;
}

Person.prototype.eating = function () {
  console.log(this.name + ' eating~');
};

// 子类: 特有属性和方法
function Student(name, age, friends, sno) {
  Person.call(this, name, age, friends);
  // this.name = name
  // this.age = age
  // this.friends = friends
  this.sno = sno;
}

// 直接将父类的原型赋值给子类, 作为子类的原型
Student.prototype = Person.prototype;

Student.prototype.studying = function () {
  console.log(this.name + ' studying~');
};

// name/sno
var stu = new Student('why', 18, ['kobe'], 111);
console.log(stu);
stu.eating();

问题

1. 构造函数会被调用两次: 一次在创建子类型原型对象的时候, 一次在创建子类型实例的时候.

2. 类型中的属性会有两份: 一份在原型对象中, 一份在子类实例中.

 4 原型继承

包含引用类型的属性值始终都会共享相应的值,这点跟原型链继承一样

var obj = {
  name: "why",
  age: 18
}


//将传入的对象作为创建的对象的原型
var info = Object.create(obj)

// 原型式继承函数
function createObject1(o) {
  var newObj = {}
  Object.setPrototypeOf(newObj, o)
  return newObj
}

function createObject2(o) {
  function Fn() {}
  Fn.prototype = o
  var newObj = new Fn()
  return newObj
}

// var info = createObject2(obj)
var info = Object.create(obj)
console.log(info)
console.log(info.__proto__)

5 寄生式继承

创建一个封装继承过程的函数, 该函数在内部以某种方式来增强对象,最后再将这个对象返回;

var personObj = {
    running: function() {
        console.log('running');
    },
};

function createStudent(name) {
    var stu = Object.create(personObj);
    stu.name = name;
    stu.studying = function() {
        console.log('studying~');
    };
    return stu;
}

var stuObj = createStudent('why');
var stuObj1 = createStudent('kobe');
var stuObj2 = createStudent('james');

6 寄生组合式继承

function createObject(o) {
    function Fn() {}
    Fn.prototype = o;
    return new Fn();
}

function inheritPrototype(SubType, SuperType) {
    // SubType.prototype = Object.create(SuperType.prototype);
    // 或者
    SubType.prototype = createObject(SuperType.prototype);
    Object.defineProperty(SubType.prototype, 'constructor', {
        enumerable: false,
        configurable: true,
        writable: true,
        value: SubType,
    });
}

function Person(name, age, friends) {
    this.name = name;
    this.age = age;
    this.friends = friends;
}

Person.prototype.running = function() {
    console.log('running~');
};

Person.prototype.eating = function() {
    console.log('eating~');
};

function Student(name, age, friends, sno, score) {
    // 原型式继承函数
    Person.call(this, name, age, friends);
    this.sno = sno;
    this.score = score;
}

inheritPrototype(Student, Person);

Student.prototype.studying = function() {
    console.log('studying~');
};

var stu = new Student('why', 18, ['kobe'], 111, 100);
console.log(stu);
stu.studying();
stu.running();
stu.eating();

console.log(stu.constructor.name);

猜你喜欢

转载自blog.csdn.net/m0_50789696/article/details/129250506