1. 基本概念
JavaScript 中的每个对象都有一个内部属性 [[Prototype]](可以通过 __proto__ 访问),指向它的原型对象。这样就形成了一个原型链,直到 null。
2. 原型关系图
// 构造函数
function Person(name) {
this.name = name;
}
// 原型方法
Person.prototype.sayHello = function() {
console.log(`Hello, I'm ${this.name}`);
}
// 创建实例
const person = new Person('John');
关系图:
person.__proto__ === Person.prototype
Person.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
Person.__proto__ === Function.prototype
Function.prototype.__proto__ === Object.prototype
3. 详细代码示例
// 1. 构造函数方式
function Animal(name) {
this.name = name;
}
Animal.prototype.makeSound = function() {
console.log('Some sound');
}
// 2. 类方式(ES6+)
class Dog extends Animal {
constructor(name) {
super(name);
}
bark() {
console.log('Woof!');
}
}
// 3. 创建实例
const dog = new Dog('Max');
// 4. 原型链检查
console.log(dog.__proto__ === Dog.prototype); // true
console.log(Dog.prototype.__proto__ === Animal.prototype); // true
console.log(Animal.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true
// 5. instanceof 检查
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
console.log(dog instanceof Object); // true
4. 原型继承的几种方式
// 1. 原型链继承
function Parent() {
this.name = 'parent';
}
function Child() {
this.type = 'child';
}
Child.prototype = new Parent();
// 2. 构造函数继承
function Child2() {
Parent.call(this);
this.type = 'child2';
}
// 3. 组合继承
function Child3() {
Parent.call(this);
this.type = 'child3';
}
Child3.prototype = new Parent();
Child3.prototype.constructor = Child3;
// 4. 寄生组合继承
function Child4() {
Parent.call(this);
this.type = 'child4';
}
Child4.prototype = Object.create(Parent.prototype);
Child4.prototype.constructor = Child4;
// 5. ES6 class 继承
class Parent5 {
constructor() {
this.name = 'parent';
}
}
class Child5 extends Parent5 {
constructor() {
super();
this.type = 'child5';
}
}
5. 实用方法和属性
// 1. 检查属性是否存在于原型链中
function hasPrototypeProperty(obj, name) {
return name in obj && !obj.hasOwnProperty(name);
}
// 2. 获取原型
const proto = Object.getPrototypeOf(obj);
// 3. 设置原型
Object.setPrototypeOf(obj, prototype);
// 4. 创建没有原型的对象
const noProto = Object.create(null);
// 5. 检查原型链
function isInPrototypeChain(parent, child) {
return child instanceof parent;
}
6. 实际应用示例
// 1. 扩展内置对象
Array.prototype.first = function() {
return this[0];
}
const arr = [1, 2, 3];
console.log(arr.first()); // 1
// 2. 实现继承
class Component {
constructor(props) {
this.props = props;
}
render() {
throw new Error('Must implement render');
}
}
class Button extends Component {
render() {
return `<button>${this.props.text}</button>`;
}
}
// 3. 混入模式
const shareMethods = {
share() {
console.log('Sharing...');
}
};
Object.assign(Component.prototype, shareMethods);
要点:
- 原型的基本概念:
-
每个函数都有 prototype 属性
-
每个对象都有 proto 属性
-
原型链的终点是 null
- 继承的实现方式:
-
原型链继承
-
构造函数继承
-
组合继承
-
寄生组合继承
-
ES6 class 继承
- 原型链查找机制:
-
先查找对象自身属性
-
没有则查找原型
-
沿着原型链向上查找
-
直到 null
- 性能考虑:
-
原型方法共享,节省内存
-
原型链过长会影响查找性能
-
避免在原型上存储引用类型数据
- 实际应用场景:
-
继承实现
-
方法共享
-
扩展内置对象
-
混入模式