js的继承

112 阅读3分钟

1.面向对象

面向对象和面向过程

面向过程,关注点在于过程,将我们要解决的问题进行流程化,关注于我们每一步要解决什么问题,再将流程串联起来

面向对象:要将我们解决的问题抽象,抽象出来,更关注于对象本身以及他要去处理的事情以及属性

prototype显示原型

2.原型链继承

function Person(){
    this.name="zhaobo"
}
Person.prototype.eating = function(){
    console.log(this.name + ' 在吃饭')
}
​
function Student(){
    this.sno = 18103420
}
Student.prototype.studying = function(){
    console.log(this.sno + ' 在学习')
}
let stu = new Student()
stu.eating()
stu.studying()

可以发现student类想要调用eating方法的话,直接调用会出现stu.eating is not defined

student.prototype里面拿不到所谓的eating 方法

需要改进一下

function Person() {
    this.name = "zhaobo"
}
Person.prototype.eating = function() {
    console.log(this.name + '吃东西');
}
​
function Student() {
    this.sno = 18103420
}
// Student.prototype = new Person()
let p = new Person()
Student.prototype = p
Student.prototype.studying = function() {
    console.log(this.name + 'studying');
}
let stu = new Student()
​
stu.eating()

那我们在给Student.prototype上挂载studying方法之前将Student.prototype指向new Person

Student.prototype = new Person()

那么内存关系图就变成了如下:

相当于原来的原型对象是有自己单独的原型对象的,现在我把它指向new Person这个对象的,之后在Student.prototype上加方法就相当于加在了new Person().proto 上面

然后在调用过程中先在隐式原型proto上找,

但是这种方法的有三个不好的地方

1.不能够打印stu对象的,继承的某些属性是看不到的

因为我们只能打印stu对象上可以枚举的属性,比如这里继承的name属性我们就获取不到

2.获取引用的话,会直接影响 我在stu1对象里面修改完以后,stu2也能获取到,因为两个指向Person对象。

let stu1 = new Student()
let stu2 = new Student()
stu1.eating()
stu1.friends.push('zzzz')
console.log(stu1.friends)
console.log(stu2.friends)
    // 原型链继承
console.log(stu1);
console.log(stu2);

3.在实现继承的时候,并没有传递参数

而且直接在new 的对象上下面这样的操作,会给对象添加一个属性name1

stu1.name1 = 'znnnn'

那么我们用借用构造函数来解决上面用原型链

3.借用父类对象继承

function Person(name, age, friends) {
    this.name = name
    this.age = age
    this.friends = friends
}
Person.prototype.eating = function() {
    console.log(this.name + '在吃饭');
}
​
function Student(name, age, friends, sno) {
    Person.call(this, name, age, friends)
    this.sno = sno
}
Student.prototype = new Person()
Student.prototype.studying = function() {
​
}
let st = new Student('zhaobo', 22, ['zb,zl'], 18103420)
console.log(st);
​
借用构造函数也是有弊端
1.Person函数至少被调用了两次  一次是new Person的时候,一次是Person.call调用
2.stu的原型对象上会多出一些属性,但是这些属性没有存在的必要

4.父类原型赋值给子类

这种方法相当于找了一个中间的代理对象,将要继承的对象

let obj = {
    name:'zhaobo',
    age:22
}
let info = Object.create(obj)
//原型式继承函数
function createObject1(o){
    let newObj = {}
    Object.setPrototypeOf(newObj,o)
    return newObj
}
function createObject2(o){
    function fn(){
        fn.prototype = o
        let newObj = new fn()
        return newObj
    }
}
let info = Object.create(obj)

5.寄生组合式继承

function createObject(o) {
  function Fn() {}
  Fn.prototype = o
  return new Fn()
}
​
function inheritPrototype(SubType, SuperType) {
  SubType.prototype = Objec.create(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)

\