JavaScript原型
JavaScript原型[编辑 | 编辑源代码]
介绍[编辑 | 编辑源代码]
在JavaScript中,原型(Prototype)是对象继承机制的核心概念。每个JavaScript对象都有一个内部属性Prototype
(可通过__proto__
访问),它指向另一个对象或null
。原型链允许对象继承其他对象的属性和方法,从而实现代码复用和面向对象编程。
JavaScript的函数对象还有一个特殊的属性prototype
,它仅在函数作为构造函数(通过new
调用)时生效,用于设置新创建对象的原型。
原型链[编辑 | 编辑源代码]
当访问一个对象的属性时,JavaScript引擎会先检查对象自身是否有该属性。如果没有,则沿着Prototype
链向上查找,直到找到该属性或到达原型链末端(null
)。
构造函数与prototype[编辑 | 编辑源代码]
当使用构造函数创建对象时,新对象的Prototype
会指向构造函数的prototype
属性。
// 构造函数
function Person(name) {
this.name = name;
}
// 在构造函数的prototype上添加方法
Person.prototype.sayHello = function() {
console.log(`Hello, my name is ${this.name}`);
};
// 创建实例
const alice = new Person('Alice');
alice.sayHello(); // 输出: "Hello, my name is Alice"
原型继承[编辑 | 编辑源代码]
JavaScript使用原型链实现继承。子构造函数的prototype
可以指向父构造函数的实例:
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
console.log(`${this.name} is eating.`);
};
function Dog(name, breed) {
Animal.call(this, name); // 调用父构造函数
this.breed = breed;
}
// 设置原型链
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 修复constructor引用
Dog.prototype.bark = function() {
console.log('Woof!');
};
const myDog = new Dog('Rex', 'Labrador');
myDog.eat(); // 输出: "Rex is eating."
myDog.bark(); // 输出: "Woof!"
Object.create()[编辑 | 编辑源代码]
Object.create()
方法可以创建一个新对象,使用现有对象作为新对象的原型:
const personPrototype = {
greet() {
console.log(`Hello, I'm ${this.name}`);
}
};
const carl = Object.create(personPrototype);
carl.name = 'Carl';
carl.greet(); // 输出: "Hello, I'm Carl"
ES6类与原型[编辑 | 编辑源代码]
ES6的class
语法是原型的语法糖:
class Person {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hello, my name is ${this.name}`);
}
}
// 等同于
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log(`Hello, my name is ${this.name}`);
};
原型相关方法[编辑 | 编辑源代码]
Object.getPrototypeOf()[编辑 | 编辑源代码]
获取对象的原型:
const obj = {};
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true
Object.setPrototypeOf()[编辑 | 编辑源代码]
设置对象的原型(不推荐在生产环境中使用,影响性能):
const obj = {};
const prototypeObj = { foo: 'bar' };
Object.setPrototypeOf(obj, prototypeObj);
console.log(obj.foo); // "bar"
instanceof 操作符[编辑 | 编辑源代码]
检查构造函数的prototype
是否出现在对象的原型链中:
function Foo() {}
const f = new Foo();
console.log(f instanceof Foo); // true
console.log(f instanceof Object); // true
实际应用案例[编辑 | 编辑源代码]
1. 方法共享:通过原型共享方法,节省内存 2. polyfill实现:为旧浏览器添加新功能 3. 库/框架扩展:扩展原生对象功能
方法共享示例[编辑 | 编辑源代码]
function Car(model) {
this.model = model;
}
// 所有实例共享同一个方法
Car.prototype.drive = function() {
console.log(`${this.model} is driving`);
};
const car1 = new Car('Toyota');
const car2 = new Car('Honda');
car1.drive(); // "Toyota is driving"
car2.drive(); // "Honda is driving"
// 方法只存储一次
console.log(car1.drive === car2.drive); // true
性能考虑[编辑 | 编辑源代码]
1. 原型链越长,属性查找时间越长 2. 避免在运行时修改原型(特别是Object.prototype) 3. 对于频繁访问的属性,可考虑直接存储在对象上
常见误区[编辑 | 编辑源代码]
1. 混淆__proto__
和prototype
:
-prototype
是函数对象的属性 -__proto__
是实例对象的属性(指向其原型)
2. 认为原型继承是类的拷贝(实际上是引用/委托)
3. 忘记设置constructor引用:
function Parent() {}
function Child() {}
// 错误方式:会丢失constructor
Child.prototype = Parent.prototype;
// 正确方式
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
数学表示[编辑 | 编辑源代码]
原型链可以表示为:
总结[编辑 | 编辑源代码]
JavaScript原型是语言的核心特性,理解原型链对于掌握JavaScript面向对象编程至关重要。通过原型: - 实现对象间的继承 - 共享方法和属性 - 构建灵活的代码结构
现代JavaScript虽然提供了class
语法,但其底层仍然是基于原型的实现机制。