js原型和原型链
1. 原型(Prototype)
每个 JavaScript 对象都有一个内部属性 [[Prototype]]
,这个属性指向它的原型对象。原型对象本身也是一个对象,通常我们通过 prototype
属性来访问对象的原型。
例如:
- 函数的原型:
每个函数对象都有一个
prototype
属性,该属性指向一个对象,这个对象就是函数的原型。例如,Array
构造函数的原型对象包含了数组实例的方法,如push
、pop
等。 -
function MyConstructor() {} console.log(MyConstructor.prototype); // 输出:MyConstructor { constructor: ƒ }
2. 原型链(Prototype Chain)
原型链是通过对象的 [[Prototype]]
属性形成的一种链式结构。当我们访问一个对象的属性或方法时,JavaScript 会先在对象本身查找,如果没有找到,就会查找对象的原型([[Prototype]]
)。如果在原型中还没有找到,它会继续查找原型的原型,直到找到 null
为止。
- 对象的原型是另一个对象,这个对象也有自己的原型,依此类推,直到原型链的顶端,即
null
。
3. 原型链的工作原理
当访问一个对象的属性时,JavaScript 会按照以下顺序查找:
- 如果对象本身有该属性,就直接返回该属性的值。
- 如果对象本身没有该属性,它会查找该对象的原型(即
[[Prototype]]
)。 - 如果原型上没有该属性,它会继续查找原型的原型。
- 这一过程一直持续,直到找到该属性或达到原型链的顶端(即
null
),如果都找不到,就返回undefined
。
4. 示例
让我们看一个简单的例子,理解原型链的概念:
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); // 继承Animal的原型
Dog.prototype.constructor = Dog; // 修正构造函数指向
Dog.prototype.bark = function() {
console.log(this.name + ' barks.');
};
const dog = new Dog('Buddy');
dog.speak(); // 输出: Buddy makes a noise.
dog.bark(); // 输出: Buddy barks.
原型链分析:
dog
是一个Dog
实例,它的原型是Dog.prototype
。Dog.prototype
是通过Object.create(Animal.prototype)
创建的,所以dog
的原型链包含了Animal.prototype
。dog
可以访问到Animal.prototype
中的方法speak
,同时它也有自己的方法bark
。
在这个例子中,dog
会依次查找属性:
dog
是否有speak
属性?没有。dog
的原型链指向Dog.prototype
,Dog.prototype
上没有speak
。Dog.prototype
的原型链指向Animal.prototype
,Animal.prototype
上有speak
,所以dog.speak()
可以成功调用。
5. 重要概念:
- 继承: 原型链是 JavaScript 中实现继承的基本机制。通过设置对象的原型,可以使得一个对象“继承”另一个对象的属性和方法。
constructor
属性: 每个对象的原型都指向一个构造函数。构造函数有一个constructor
属性,指向其原型对象。
总结
- 原型是构造函数的
prototype
属性,它用于存放可以由该构造函数创建的所有实例共享的方法和属性。 - 原型链是一个对象链,通过对象的
[[Prototype]]
属性连接。查找对象的属性时,如果该对象没有,则会沿着原型链查找,直到查找到null
为止。
通过理解原型和原型链,可以更好地理解 JavaScript 中的继承、对象创建和属性查找机制