您现在的位置是:网站首页 > 原型与原型链文章详情
原型与原型链
陈川
【
JavaScript
】
25411人已围观
4007字
在JavaScript中,理解原型与原型链是深入掌握对象继承机制的核心。对象的属性和方法通过原型链动态查找,这种设计既灵活又高效。
原型的概念
每个JavaScript对象(除null
)都有一个隐藏属性[[Prototype]]
,指向它的原型对象。通过__proto__
(非标准)或Object.getPrototypeOf()
可访问它。构造函数通过prototype
属性为实例提供共享原型:
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log(`Hello, ${this.name}!`);
};
const alice = new Person('Alice');
alice.sayHello(); // 输出: Hello, Alice!
这里Person.prototype
成为alice
的原型,sayHello
方法被所有实例共享。
原型链的运作机制
当访问对象属性时,JavaScript会沿原型链向上查找:
console.log(alice.toString()); // 输出: [object Object]
尽管alice
没有toString
方法,但通过原型链找到Object.prototype.toString
。完整的链条如下:
alice → Person.prototype → Object.prototype → null
手动修改原型链的例子:
const parent = { familyName: 'Smith' };
const child = Object.create(parent);
console.log(child.familyName); // 输出: Smith
此时原型链为:
child → parent → Object.prototype → null
构造函数与原型的关系
构造函数通过new
操作符创建实例时,实例的[[Prototype]]
会指向构造函数的prototype
属性:
function Car(model) {
this.model = model;
}
Car.prototype.getModel = function() {
return this.model;
};
const tesla = new Car('Model S');
console.log(Object.getPrototypeOf(tesla) === Car.prototype); // true
原型继承的实现
实现继承需要连接子类和父类的原型链:
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;
Dog.prototype.bark = function() {
console.log('Woof!');
};
const myDog = new Dog('Rex', 'Labrador');
myDog.eat(); // 输出: Rex is eating.
现代语法中的原型
ES6的class
本质仍是原型继承的语法糖:
class Shape {
constructor(color) {
this.color = color;
}
draw() {
console.log(`Drawing a ${this.color} shape.`);
}
}
class Circle extends Shape {
constructor(color, radius) {
super(color);
this.radius = radius;
}
getArea() {
return Math.PI * this.radius ** 2;
}
}
const redCircle = new Circle('red', 5);
redCircle.draw(); // 输出: Drawing a red shape.
原型链的边界情况
原型链的终点是null
,尝试越过终点访问属性会报错:
const obj = Object.create(null);
console.log(obj.toString); // undefined
手动构建多层原型链:
const level1 = { a: 1 };
const level2 = Object.create(level1);
level2.b = 2;
const level3 = Object.create(level2);
level3.c = 3;
console.log(level3.a); // 1 (来自level1)
console.log(level3.b); // 2 (来自level2)
性能与内存考量
原型链过长会影响属性查找速度。V8引擎会优化重复查找,但深度超过10层的原型链仍可能降低性能:
// 创建深度原型链
let current = {};
for (let i = 0; i < 20; i++) {
current = Object.create(current);
current[`prop${i}`] = i;
}
console.time('deep lookup');
console.log(current.prop19);
console.timeEnd('deep lookup'); // 比浅层查找耗时更长
原型污染与防御
直接修改内置原型可能引发意外行为:
Array.prototype.push = function() {
console.log('Array.push disabled!');
};
const arr = [1, 2];
arr.push(3); // 输出: Array.push disabled!
安全的原型扩展方式:
// 使用Symbol作为属性键避免冲突
const customMethod = Symbol('custom');
Array.prototype[customMethod] = function() {
console.log('Safe extension');
};
[][customMethod](); // 输出: Safe extension
原型相关的API
Object
方法提供了原型操作能力:
const proto = { x: 10 };
const obj = Object.create(proto, {
y: { value: 20, enumerable: true }
});
console.log(Object.getPrototypeOf(obj) === proto); // true
console.log(Object.getOwnPropertyNames(obj)); // ["y"]
// 修改原型
Object.setPrototypeOf(obj, { z: 30 });
console.log(obj.z); // 30
实际应用场景
利用原型实现插件系统:
function Core() {}
Core.prototype.plugins = [];
Core.prototype.use = function(plugin) {
this.plugins.push(plugin);
plugin(this);
};
function LoggerPlugin(core) {
core.log = function(message) {
console.log(`[LOG] ${message}`);
};
}
const app = new Core();
app.use(LoggerPlugin);
app.log('System started'); // 输出: [LOG] System started
上一篇: 文字阴影的高级用法
下一篇: constructor属性