简介
在本文中,我们将探讨 JavaScript 一些面向对象编程的机制,以便利用他解决 JavaScript 中关于 面向对象编程 一些常见面试问题:
- 如何在 JavaScript 中实现面向对象编程的?
- 你能在 JavaScript 中实现继承吗?
面向对象
对象 : 对象是包含属性和方法 的唯一实例。 例如,“狗”是一个现实生活中的对象,它具有颜色、品种、会跑等一些特征,对象的特征在面向对象编程中称为属性或方法。对象是类的实例。对象在 JavaScript 中无处不在,几乎每个元素都是 Object,无论是函数、数组还是字符串。
以下我以某荣耀的角色举例:
在 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对象建立时候都会与之关联另一对象,称为原型,会从原型那继承属性和方法。
__proto__
每js对象都有__proto__属性,它指向对象原型。
function Role() {}
const role1 = new Role();
console.log(role1.__proto__ === Role.prototype); // true
原型链: 当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。原型链最终指向的是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
通过把 prototype
把 Role1
的属性存储到 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
类中继承了这个类。我们使用相同方法名称定义创建了不同的类。这个例子向我们展示了相同的方法将根据调用它的对象
执行不同的操作。