面对对象编程

119 阅读4分钟

一、对象是什么,为什么要面对对象?

1.对象的特点

  • 逻辑迁移更加灵活,代码复用率高,高度的模块化

2.对象的理解

  • 对象是对单个物体的抽象
  • 对象时一个容器,封装了属性和方法 ** 属性: 对象的状态 ** 方法: 对象的方法

3.两种对象

// 简单对象
const Person = {
    name: 'haiyanng',
    age: '18',
    getFullName: function(surname) {
        return `${surname}${this.name}`
    }

}
// 函数对象
const Person = function() {
    this.name = 'haiyang';
    this.age = '18';
    this.getFullName = function(surname) {
        return `${surname}${this.name}`
    }
}

二、构造函数(Constructor)-用于构造对象

1、构造函数的理解

  • 对象模板-将一类事物共同的特征,抽象为一个对象
  • 类即对象模板
  • js本质上不是基于类,而是基于构造函数和原型链
  • constructor + prototype

2、函数对象本质就是构造函数

  • 函数体内使用的this,指向所要生成的实例
  • 生成对象用new进行实例化
  • 可以做初始化传参
const Person = function(name,age) {
    this.name = name;
    this.age = age;
    this.getFullName = function(surname) {
        return `${surname}${this.name}`
    }
}

面试题:

  • 如果构造函数不实例化,可以使用吗? --- 无法使用
  • 如果项目中需要使用,通常如何解决? ---让其初始化不被外界感知
const Person = function(name,age) {
    const _isClass = this instanceof Person;   // 是否有实例化
    if(!_isClass) {
        return new Person(name,age)
    }
    this.name = name;
    this.age = age;
    this.getFullName = function(surname) {
        return `${surname}${this.name}`
    }
}
const person = Person('yao', '19')

启发:如果做底层封装,可以不让外界感知内部的构造函数和类型,只返回api

3、在实例化的时候,new都做了什么?

  • 创建了一个空对象,作为对象实例
  • 将实例的的原型对象指向构造函数的prototype
  • this指向新的实例对象
  • 执行构造函数的内容

面试题: 实例属性在多个实例中是相互独立的吗? -独立,实例属性会重复挂载到到不同的实例对象上,因为执行构造函数的初始化代码时,this的指向不同

4、constructor

    function Person() {};
    const person1 = new Course();
    const person2 = new Course();
  • 构造函数: 用来创建对象并初始化一部分属性的函数 - Person
  • 每个对象在创建时,都会有一个construtor属性
  • constructor继承自对象的构造函数的原型对象,指向所继承的构造函数

面试题: 使用构造函数创建对象有没有什么性能上的问题? -有,会重复挂载所有可能有的实例属性和方法。比较耗费资源

5、原型对象prototype

实例对象会重复挂载,原型对象各个实例与其构造函数共享

    function Course() {};
    const course1 = new Course();
    const course2 = new Course();
  • 每个构造函数都会被赋予一个属性prototype,该属性等于实例对象的原型对象
  • 实例对象: course1是实例对象,根据原型对象创建出来的实例对象,每个都有一个原型对象__proto__ 每个都有一个构造函数constructor,构造函数constructor由继承而来,指向当前的构造函数
  • 原型对象:Course.prototype,实例的原型对象指向构造函数的原型对象,即person1.proto === Person.prototype
    function Person(name) {
        this.name = name;
    }
    
    // 方法挂载于prototype上
    Person.prototype.setAge = function(age) {
        this.age = age;
        return `${this.name}今年${age}了!`;
    }

    const person1 = new Person('xiaoming');
    const person2 = new Person('xiaohong');
    person1.setAge('18')  // xiaoming今年18了!
    person1    // {name: 'xiaoming',age: 18}
    person2    // {name: 'xiaohong'}

六、继承

1、原型链继承:让子对象冒充实例继承,可继承对象的所有实例属性方法和原型上所有的属性方法

  • 实现
// 本质:重写原型对象方式。将父对象的所有属性方法,都作为子对象原型对象的属性和方法。
function Father() {
    this.name = "ziaoming";
}
Father.prototype.setAge = function(age) {
     this.age = age;
     return `${this.name}今年${age}了!`;
}
function Son() {}
Son.prototype = new Father()
Son.prototype.constructor = Son;

const son1= new Son();
  • 缺点 1.所有属性和方法(包括原型对象和实例上的属性和方法)都在原型链上,所以所有的属性和方法都是共享的 2.无法通过子对象传参

2、构造函数继承

  • 实现
function Father(name) {
    this.name = name;
}
Father.prototype.setAge = function(age) {
     this.age = age;
     return `${this.name}今年${age}了!`;
}
function Son(name) {
    Father.call(this,name)
}
const son1= new Son('xiaoming');
  • 缺点 原型链上的共享方法无法被读取继承

3、组合继承

  • 实现
function Father(name) {
    this.name = name;
}
Father.prototype.setAge = function(age) {
     this.age = age;
     return `${this.name}今年${age}了!`;
}
function Son(name) {
    Father.call(this,name)
}
Son.prototype = new Father()
Son.prototype.constructor = Son;
const son1= new Son('xiaoming');
  • 缺点 调用两次父类构造函数:函数内部调用一次,new调用一次

4、寄生组合继承

function Father(name) {
    this.name = name;
}
Father.prototype.setAge = function(age) {
     this.age = age;
     return `${this.name}今年${age}了!`;
}
function Son(name) {
    Father.call(this,name)
}
Son.prototype = Object.create(Father.prototype);
Son.prototype.constructor = Son;
const son1= new Son('xiaoming');

5、如何实现多重继承(同时继承两个构造函数)

function Father(name) {
    this.name = name;
}
function Mother(age) {
    this.age = age;
}
function Son(name,age) {
    Father.call(this,name);
    Mother.call(this,age)
}
Son.prototype = Object.create(Father.prototype);
Object.assign(Son.prototype, Mother.prototype)
Son.prototype.constructor = Son;
const son1= new Son('xiaoming');