原型/继承/6种继承方法实现对比

83 阅读3分钟

面向对象

什么是对象,面向对象的优势

JS是脚本化语言,一行一行执行,一边运行一边解析,过程化语言;

面向对象:将开发内容独立化拆分出一个主体,对主体进行逻辑设计

例如上课

过程:上课:start(开始上课)- ask(询问) - before(回顾)- main(课内容)- over(完成)

面向对象: 以课程为主体,课程有上面这些方法;以这个对象为基础,可以生成多个课程实例,

对象的理解

  • 对象是对单个物体的简单抽象
  • 对象是基础/模板,对象也是容器,可以存放属性,方法,上面的过程 变为 对对象属性和方法的填充

对象的优势

  • 逻辑迁移更灵活,不需要去修改每个实例,只需要去修改对象模板;

  • 代码复用性高,

  • 高度模块化

     function Course() {
      this.teacher = 'yy'
      this.class = 'oop'
      this.startCourse = function(name) {
          return `开始${name}课程`
      }
      // ……初始化
    }
    
    const course1 = new Course()
    // 构造实例的函数对象 => 构造函数 => 严谨化构造一个对象
    

构造函数 - 生成对象,相当于对象模板

js对象本质 基于构造函数 + 原型链的传递方式

问:实例化生成对象之间的关系

对象彼此之间是独立的

问:constructor存在的意义 - 构造一类

  • 每个实例对象被创建,会自动拥有一个证明身份的属性,constructor
  • constructor来自于原型对象,指向构造函数的引用

问:使用构造函数创建对象有什么问题

当属性是方法时,每次都会创建一个新函数,造成资源浪费 => 函数放在原型上 Course.prototype.startCourse = function(){...}

原型对象

course1__proto__ = Course.prototype;

Course.prototype,相当于父类的属性和方法 实例对象可以通过原型对象,course1.__proto__访问

生成的实例对象对应__proto__属性;构造函数对应prototype属性

微信图片_20240421151926.jpg

Course()一方面是构造函数,所以course1__proto__ = Course.prototype;

Course()同时也是一个函数,是一个函数对象的实例,所以Course__proto__ = Function.prototype;

Object()同上,是一个构造函数,也是一个函数对象 Object__proto__ = Function.prototype;

继承

1.重写原型,原型对象中的属性和方法都可以被继承(可以调用)

function Game () {
   this.name = 'LOL';
   this.skin = ['s'];
}
Game.prototype.getName = function() {
   return this.name
}

function LOL() {}
LOL.prototype = new Game();
LOL.prototype.constructor = LOL;

const lol1 = new LOL();
const lol2 = new LOL();
lol1.skin.push('ss');
lol2.skin = ['s','ss'];

重写原型缺点

  • 父类属性 赋值给 子类原型属性,就变成子类实例共享了,一旦修改都会有影响
  • 实例化时,无法向父类传参

2.构造函数继承(借助call)解决共享属性+传参问题

  function Game () {
    this.name = 'LOL'
    this.skin = ['s']
}

function LOL(arg) {
    Game.call(this, arg)
}
const lol1 = new LOL()
const lol2 = new LOL()
lol1.skin.push('ss')

构造函数继承问题

原型链上的方法无法读取继承

3.组合继承(前两种组合)

function LOL(arg) {
    Game.call(this, arg)
}
LOL.prototype = new Game();
LOL.prototype.constructor = LOL;

组合继承问题,父类构造函数会被执行两次

4.原型式继承

有一个对象作为基础,不用创建构造函数

let parent = {
   name: 'parent',
   friends:['aa','bb'],
   getName: function(){...}
}
let child = Object.create(parent)

5.寄生组合继承

function LOL(arg) {
    Game.call(this, arg)
}
LOL.prototype = Object.create(Game.prototype);
LOL.prototype.constructor = LOL;

如何实现一个私有变量?

对象->独立的模块;闭包->可以引用内部作用域

==> 既可以隔离,又有和外部关联的桥梁

function createStack() {
    // 独立作用域
    const items = []
    return {
        push(item) {
            items.push(item)
        }
        setItem() {}
        getItem() {
            return items
        }
    }
}