JavaScript 面向对象与原型
什么是面向对象?
面向对象编程(Object-oriented programming, OOP)是一种编程模式,它以“对象”作为程序的基本单元,通过对象之间的交互实现程序功能。面向对象编程思想中,将程序拆分成若干个模块,每个模块相当于一个对象,包含自身属性和方法。
JavaScript作为一门面向对象的语言,与其他语言不同,它没有类的概念。在JavaScript中,对象是由“原型”构建而来的。
原型
原型(Prototype)是JavaScript面向对象编程的基础。我们可以将原型理解为每个对象都拥有的一个属性,在JavaScript中,每种数据类型都拥有一个原型。原型即该数据类型的模板,它包含了该类型所有的方法和属性,同时又与该类型的所有对象共享。
构造函数
在JavaScript中,我们可以使用构造函数来定义一个类,并且在构造函数中设置原型对象中的属性和方法。下面是一个简单的示例:
function Person(name, age) {
// 在构造函数内部定义属性
this.name = name;
this.age = age;
}
// 在构造函数的原型对象中定义方法
Person.prototype.sayHello = function() {
console.log(`Hello, my name is ${this.name}, I'm ${this.age} years old.`);
}
// 创建一个实例对象
const person = new Person('Alice', 20);
person.sayHello(); // Hello, my name is Alice, I'm 20 years old.
在这个示例中,我们定义了一个Person构造函数,它接收两个参数,分别代表一个人的名字和年龄。在Person构造函数中,我们通过this.name = name
和this.age = age
这样的方式来定义实例对象的属性。同时,我们通过Person.prototype.sayHello = function() {...}
的方式在构造函数的原型对象中定义了一个sayHello
方法,该方法可以在实例对象上进行调用。
需要注意的是,构造函数的命名习惯是使用大写字母开头,这样可以方便的与实例对象进行区分。
原型链
实际上,每个JavaScript对象都有一个原型。这个原型又是一个JavaScript对象,它的原型又是另一个JavaScript对象,以此类推,直到原型链的顶端为止。原型链的顶端是由所有对象共享的,通常是Object的原型对象。
在查找一个对象的属性时,JavaScript会先在该对象本身的属性中查找,如果没有找到,则会往上沿着原型链查找,直到找到或到达原型链的顶端。这就是JavaScript中“原型链”的概念。
我们可以通过Object.getPrototypeOf()
方法查看一个对象的原型,例如:
const obj = {};
console.log(Object.getPrototypeOf(obj)); // 输出:[object Object]
原型继承
通过原型继承,一个对象可以继承另一个对象的属性和方法。在JavaScript中,我们可以通过Object.create()
方法创建一个新对象,并将其原型设置为指定对象的原型。下面是一个简单的示例:
const person = {
name: 'Alice',
age: 20,
sayHello() {
console.log(`Hello, my name is ${this.name}, I'm ${this.age} years old.`);
}
};
const student = Object.create(person);
student.major = 'Computer Science';
console.log(student.name); // Alice
console.log(student.age); // 20
console.log(student.major); // Computer Science
student.sayHello(); // Hello, my name is Alice, I'm 20 years old.
在这个示例中,我们先创建了一个包含name
、age
和sayHello
属性的对象person
,然后通过Object.create()
方法创建了一个新的对象student
,将其原型设置为person
的原型。在student
对象上,我们还添加了一个major
属性。
通过student.name
、student.age
、student.sayHello()
都可以访问到person
对象的属性和方法。
示例说明
示例1
假设我们在开发一个游戏,每个角色都有贡献值和攻击力,现在需要定义一个角色类,包含角色的基本属性和方法。
function Role(contribute, attack) {
this.contribute = contribute;
this.attack = attack;
}
Role.prototype.setContribute = function(contribute) {
this.contribute = contribute;
}
Role.prototype.getContribute = function() {
return this.contribute;
}
Role.prototype.setAttack = function(attack) {
this.attack = attack;
}
Role.prototype.getAttack = function() {
return this.attack;
}
const role1 = new Role(100, 10);
role1.setContribute(50);
console.log(role1.getContribute()); // 50
console.log(role1.getAttack()); // 10
在这个示例中,我们定义了一个Role
构造函数,它包含contribute
和attack
属性,并定义了一些设置和获取属性的方法。在role1
实例上,我们先通过new Role(100, 10)
的方式创建了一个对象,并将其属性设置为100
和10
。然后,通过setContribute(50)
的方式修改了contribute
属性,最后通过getContribute()
和getAttack()
方法输出了属性。
示例2
我们再来一个稍微复杂一点的示例,假设现在有一个形状的类,可以通过setSides()
方法设置边数,通过getSides()
方法获取边数,同时有一个子类Square
,它继承自Shape
,并具有计算面积的能力。
function Shape(sides) {
this.sides = sides;
}
Shape.prototype.setSides = function(sides) {
this.sides = sides;
}
Shape.prototype.getSides = function() {
return this.sides;
}
function Square(sides, length) {
Shape.call(this, sides); // 继承Shape类的属性
this.length = length;
}
Square.prototype = Object.create(Shape.prototype); // 继承Shape类的方法
Square.prototype.getArea = function() {
return this.length * this.length;
}
const square1 = new Square(4, 10);
console.log(square1.getSides()); // 4
console.log(square1.getArea()); // 100
在这个示例中,我们定义了Shape
和Square
两个类。Shape
类包含sides
属性和设置和获取属性的方法。Square
类继承了Shape
类,并且在其原型对象中添加了一个getArea()
方法,用于计算正方形的面积。
在square1
实例上,我们先通过new Square(4, 10)
的方式创建了一个正方形对象,并将其属性设置为4
和10
。然后,通过getSides()
方法获取了边数,并通过getArea()
方法计算出正方形的面积。
这里需要注意的是,在Square
类中,我们通过Shape.call(this, sides)
的方式继承了Shape
类的属性,使用Object.create(Shape.prototype)
的方式继承了Shape
类的方法。这样,我们就可以在Square
对象上调用Shape
中定义的属性和方法。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript 面向对象与原型 - Python技术站