JS面向对象的核心概念:封装、继承和多态——什么是封装?什么是继承和多态。什么是对象原型,它是怎么通过对象原型实现封装和继承的?什么又是原型链,又怎么通过原型链实现多态?
封装:将数据和行为封装在对象中,通过接口与外部交互,隐藏内部细节。继承:子类可以继承父类的属性和方法,避免重复代码。多态:子类可以重写父类的方法,同样的方法在不同对象上表现出不同的行为。对象原型:对象通过原型实现继承,每个对象都有一个原型,方法和属性通过原型链共享。原型链:对象通过原型链进行属性和方法的查找,沿着链条直到。
js通过对象原型和原型链实现面向对象的三个核心特性:封装、继承和多态。我们可以逐步理解这几个概念以及它们在JavaScript中的实现。
1. 封装(Encapsulation)
封装是面向对象编程中的一个核心概念,指的是将数据(属性)和操作数据的行为(方法)封装到对象中,隐藏对象的内部细节,只暴露公共接口给外部使用。
在JavaScript中,封装可以通过对象来实现。我们把相关的属性和方法定义在一个对象中,然后通过访问权限来控制哪些属性和方法可以被外部访问,哪些则不能。
JavaScript中的封装例子:
function Person(name, age) {
let privateAge = age; // 私有属性,通过封装隐藏
this.name = name; // 公有属性
this.getAge = function() { // 公有方法
return privateAge;
}
this.setAge = function(newAge) { // 公有方法
if (newAge > 0) {
privateAge = newAge;
}
}
}
const john = new Person('John', 25);
console.log(john.name); // 输出 'John'
console.log(john.getAge()); // 输出 25
john.setAge(30);
console.log(john.getAge()); // 输出 30
// 尝试直接访问 privateAge 会失败
console.log(john.privateAge); // undefined
在这个例子中,privateAge
是一个私有变量,不能被外部直接访问。通过封装,我们只暴露了 getAge
和 setAge
方法,控制了对 privateAge
的访问。这就是封装的作用——保护数据和隐藏实现细节。
2. 继承(Inheritance)
继承是面向对象编程中的另一重要概念,指的是一个对象可以继承另一个对象的属性和方法。继承的主要目的是为了重用代码,避免重复定义相同的功能。
JavaScript通过**原型继承(prototype inheritance)**实现继承,每个对象都有一个内部的原型(__proto__
),通过原型可以访问父对象的属性和方法。
JavaScript中的继承例子:
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + ' makes a noise.');
}
function Dog(name) {
Animal.call(this, name); // 调用父类构造函数,继承父类属性
}
Dog.prototype = Object.create(Animal.prototype); // 继承父类方法
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function() { // 重写父类方法
console.log(this.name + ' barks.');
}
const dog = new Dog('Buddy');
dog.speak(); // 输出 'Buddy barks.'
在这个例子中,Dog
类继承了 Animal
类,使用 Animal.call(this, name)
来继承 Animal
的属性(即 name
),并通过 Object.create(Animal.prototype)
继承 Animal
的方法(即 speak()
)。通过继承,Dog
可以访问并重用 Animal
的属性和方法。
3. 多态(Polymorphism)
多态允许子类在继承父类的基础上,对父类的某些方法进行重写,从而提供不同的实现。简单来说,多态是指“同样的方法在不同对象上表现出不同的行为”。
在JavaScript中,方法重写是实现多态的方式。子类可以重写父类的方法,调用时会根据实际的对象类型执行对应的实现。
JavaScript中的多态例子:
const animal = new Animal('generic animal');
const dog = new Dog('Buddy');
animal.speak(); // 输出 'generic animal makes a noise.'
dog.speak(); // 输出 'Buddy barks.'
在这个例子中,animal.speak()
调用了 Animal
类的 speak()
方法,而 dog.speak()
调用了 Dog
类重写的 speak()
方法。这就是多态——同样的 speak()
方法,针对不同的对象类型表现出不同的行为。
4. 对象原型(Prototype)
在JavaScript中,对象原型是实现继承的基础。每个对象都有一个隐藏的属性 [[Prototype]]
,通常可以通过 __proto__
来访问。通过原型,JavaScript对象可以继承另一个对象的属性和方法。
当我们访问一个对象的属性或方法时,JavaScript引擎会先在对象本身查找该属性或方法。如果没有找到,它会沿着原型链查找,直到找到或走到原型链的尽头。
通过对象原型实现继承:
function Parent() {
this.name = 'parent';
}
Parent.prototype.sayHello = function() {
console.log('Hello from ' + this.name);
}
const child = new Parent();
child.sayHello(); // 输出 'Hello from parent'
在这个例子中,Parent
的实例 child
继承了 Parent.prototype
上的方法 sayHello()
。这就是通过原型实现的继承。
5. 原型链(Prototype Chain)
原型链是指对象通过 __proto__
链接到另一个对象(通常是构造函数的 prototype
),并且这个被链接的对象也可以有它自己的原型,形成一条原型链。原型链的顶端是 Object.prototype
,它没有原型。
当我们访问一个对象的属性或方法时,如果该属性或方法不在对象本身,它会沿着原型链依次向上查找,直到找到该属性或方法,或者查找到 Object.prototype
为止。
原型链的例子:
function A() {}
A.prototype.sayHi = function() {
console.log('Hi from A');
}
function B() {}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
B.prototype.sayHi = function() {
console.log('Hi from B');
}
const b = new B();
b.sayHi(); // 输出 'Hi from B'
在这个例子中,B.prototype
继承了 A.prototype
,因此 B
的实例 b
有一个原型链:b -> B.prototype -> A.prototype -> Object.prototype
。当我们调用 b.sayHi()
时,首先在 B.prototype
中找到方法 sayHi
,因为它被重写了,所以多态地执行 B
类的 sayHi()
方法。
总结:
- 封装:将数据和行为封装在对象中,通过接口与外部交互,隐藏内部细节。
- 继承:子类可以继承父类的属性和方法,避免重复代码。
- 多态:子类可以重写父类的方法,同样的方法在不同对象上表现出不同的行为。
- 对象原型:对象通过原型实现继承,每个对象都有一个原型,方法和属性通过原型链共享。
- 原型链:对象通过原型链进行属性和方法的查找,沿着链条直到
Object.prototype
。
更多推荐
所有评论(0)