详解JavaScript 中的面向对象编程(继承、多态)

488 阅读4分钟

简介

在本文中,我们将探讨 JavaScript 一些面向对象编程的机制,以便利用他解决 JavaScript 中关于 面向对象编程 一些常见面试问题:

  • 如何在 JavaScript 中实现面向对象编程的?
  • 你能在 JavaScript 中实现继承吗?

面向对象

对象 对象是包含属性方法 的唯一实例。 例如,“狗”是一个现实生活中的对象,它具有颜色、品种、会跑等一些特征,对象的特征在面向对象编程中称为属性或方法。对象是类的实例。对象在 JavaScript 中无处不在,几乎每个元素都是 Object,无论是函数、数组还是字符串。

以下我以某荣耀的角色举例:

image.png

在 JavaScript 中常用的两种创建对象的方式:

  • 通过“{ }”语法创建对象
  • 构造函数
  • class类

例:通过“{ }”语法创建对象

const role = {
  name: 'xx',
  // 皮肤编号
  skin: 0,
  // 技能,默认三个
  skill: [0, 1, 2],
  setNmae(name) {
    this.name = name;
  },
  setSkin(num) {
    this.skin = num;
  },
  setSkill(arr) {
    this.skill = arr;
  }
};
console.log(role.setNmae('李白'));
console.log(role.name); // 李白

例:构造函数

function Role(name, skin = 0, skill = [0, 1, 2]) {
  this.name = name;
  this.skin = skin;
  this.skill = skill;
  this.setNmae = ne => {
    this.name = ne;
  };
}

const role1 = new Role('李白');
const role2 = new Role('猴子');

console.log(role1.name); // 李白
console.log(role2.name); // 猴子
role2.setNmae('001')
console.log(role2.name); // 001

例:class类

class Role {
  constructor(name, skin = 0, skill = [0, 1, 2]) {
    this.name = name;
    this.skin = skin;
    this.skill = skill;
  }

  setNmae(name) {
    this.name = name;
  }
}

const role1 = new Role('李白');
const role2 = new Role('猴子');

console.log(role1.name); // 李白
console.log(role2.name); // 猴子
role2.setNmae('001')
console.log(role2.name); // 001

继承

JavaScript 中的原型继承: 有要几个基础要点知识

  • 在经典继承现象下,我们创建了一个新类,它实际上是复制了另一个类的属性或方法。
  • 在JavaScript中不使用经典继承,而是使用原型链实现继承。
  • 在原型链继承中,一个对象通过原型链接使用另一个对象的属性或方法。
  • 所有 JavaScript 对象都从原型链继承属性和方法(如 Date 对象从 Date.prototype 继承属性等)。

什么是原型链?
首先认识下prototype和__proto__属性

prototype
每个构造函数都有prototype属性,它指向原型对象,可以通过它给原型增加属性或方法。

function Role() {}

// prototype指向Role原型,添加了name属性
Role.prototype.name = '0001';
const role1 = new Role();
const role2 = new Role();

console.log(role1.name); // 0001
console.log(role2.name); // 0001

在每个js对象建立时候都会与之关联另一对象,称为原型,会从原型那继承属性和方法。 image.png

__proto__
每js对象都有__proto__属性,它指向对象原型。

function Role() {}

const role1 = new Role();

console.log(role1.__proto__ === Role.prototype); // true

image.png

原型链: 当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。原型链最终指向的是Object.prototype,他的__proto__为null

例子:

function Role() {
  this.name1 = '角色1';
}

function Role1() {
  this.name2 = '角色2';
}

Role.prototype = new Role1();
const role = new Role();
// 在自身role找到 ‘角色2’
console.log(role.name1); // 角色1
// 在自身role找不到,通过 __proto__ 去原型找 ‘角色2’
console.log(role.name2); // 角色2

继承方法1: 原型链继承

通过一个构造函数new出来的实例,那么这个实例就具有该构造函数的属性。

function Role() {
  this.name = '角色1';
}
const role = new Role();
console.log(role.name); // 角色1

通过把 prototypeRole1 的属性存储到 Role 中:

function Role() {
  this.name1 = '角色1';
}
function Role1() {
  this.name2 = '角色2';
}
Role.prototype = new Role1();
const role = new Role();
console.log(role.name2); // 角色2

在字面量对象中:

const Role = {
  name: '01',
};

const Role1 = {
  name1: '02',
};-   这个__proto__有点过时,而且由于与JavaScript相关的一些历史原因而存在过时的方法。

Role.__proto__ = Role1;
console.log(Role.name); // 01
console.log(Role.name1); // 02

这个__proto__有点过时,而且由于与JavaScript相关的一些历史原因而存在过时的方法。

继承方法2: Object.setPrototypeOf()

  • 在这种方法中,我们将使用新的 JavaScript 方法来实现 JavaScript 原型继承。
  • 在这里,我们将使用 Object.setPrototypeOf() 方法需要两个参数,第一个是要设置原型的对象,第二个是对象的新原型。
  • 此后,我们声明了两个对象,并使用这两个对象,我们将其中一个对象设置为另一个对象的原型对象。
const Role = {
  name: '01',
};

const Role1 = {
  name1: '02',
};

Object.setPrototypeOf(Role, Role1);
console.log(Role.name); // 01
console.log(Role.name1); // 02

继承方法3: class xxx extends xxx

class Role {
  constructor() {
    this.name = '01';
  }
}

class Role1 extends Role {
  constructor() {
    super();
    this.name1 = '02';
  }
}

const role = new Role1();
console.log(role.name); // 01
console.log(role.name1); // 02

多态

多态性的特点:

  • 可以重复使用相同的方法名称。
  • 相同的方法将根据调用它的对象执行不同的操作。

继承多态性: 在此示例中,我们将创建三个具有相同名称和不同操作的函数。

class firstClass {
	add() {
		console.log("First Method")
	}
}
class secondClass extends firstClass {
	add() {
		console.log(30 + 40);
	}
}
class thirdClass extends secondClass {
	add() {
		console.log("Last Method")
	}
}
let ob = new firstClass();
let ob2 = new secondClass();
let ob3 = new thirdClass();
ob.add(); // First Method
ob2.add(); // 70
ob3.add(); // Last Method

在代码中,我们有一个firstClass类,在这个类中,我们有“add”方法,我们在第二个secondClass类中继承了这个类。我们使用相同方法名称定义创建了不同的类。这个例子向我们展示了相同的方法将根据调用它的对象执行不同的操作。