在 JavaScript 中,原型(prototype)是一个非常重要的概念,它为对象提供了继承和共享属性的机制。每个 JavaScript 对象都有一个与之关联的原型对象,通过原型对象,可以实现属性和方法的共享,从而减少内存占用。
所有的 JavaScript 对象都会从一个 prototype(原型对象)中继承属性和方法。
JavaScript 中的 prototype 是实现原型链和继承机制的核心。在 JavaScript 中,几乎所有对象都是基于原型的,这意味着对象可以继承另一个对象的属性和方法。prototype 属性是实现这种继承的关键。
什么是prototype?
prototype 是函数对象特有的属性,它指向一个对象,这个对象包含所有实例共享的属性和方法。当你创建一个新的函数时,JavaScript 会自动为这个函数添加一个 prototype 属性,这个属性是一个对象,它默认有一个 constructor 属性指向这个函数本身。
原型链
当你创建一个新对象时,这个对象内部会有一个指向其构造函数的 prototype 属性的链接。这个链接就是原型链。当你访问一个对象的属性时,如果这个对象本身没有这个属性,JavaScript 会沿着原型链向上查找,直到找到这个属性或者到达原型链的顶端(Object.prototype)。如果原型链顶端也没有这个属性,那么就会返回 undefined。
如何使用prototype
你可以通过修改函数的 prototype 属性来添加或修改继承的属性和方法。
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log("你好呀, 我的名字是 " + this.name);
};
const person1 = new Person("ai风林火山");
person1.sayHello(); // 输出:你好呀, 我的名字是 ai风林火山
在这个例子中,Person 函数的 prototype 属性被用来添加一个 sayHello 方法,所有 Person 的实例都可以访问这个方法。
prototype与__proto__
- prototype 是函数对象特有的属性,它指向原型对象。
- __proto__ 是对象特有的属性,它指向创建这个对象的构造函数的原型对象。
注意事项
- 尽量避免使用 __proto__,因为它不是标准的方法,并且可能在未来的 ECMAScript 版本中被弃用。
- 使用 Object.getPrototypeOf() 来获取一个对象的原型。
- 使用 Object.create() 来创建一个具有指定原型的新对象。
通过理解 prototype 和原型链,你可以更深入地理解 JavaScript 中的继承和工作原理。
下面是一个使用prototype实现原型链和继承的简单实例:
// 定义一个父类(构造函数)
function Zoon(name) {
this.name = name;
}
// 在父类的prototype上添加一个方法
Zoon.prototype.eat = function() {
console.log(this.name + '正在吃饭。');
};
// 定义一个子类(构造函数)
function Dog(name, age) {
// 调用父类的构造函数,设置name属性
Zoon.call(this, name);
this.age = age;
}
// 设置子类的prototype为父类的一个实例
Dog.prototype = Object.create(Zoon.prototype);
// 重置子类的constructor属性,使其指向子类本身
Dog.prototype.constructor = Dog;
// 在子类的prototype上添加一个方法
Dog.prototype.bark = function() {
console.log(this.name + ' 正在吠叫。');
};
// 创建一个Dog的实例
var myDog = new Dog('雪郎仔仔', '哈士奇');
// 调用继承自Zoon的方法
myDog.eat(); // 输出:雪郎仔仔 正在吃饭。
// 调用Dog自己的方法
myDog.bark(); // 输出:雪郎仔仔 正在吠叫。
在这个例子中,Zoon是一个父类,它有一个eat方法。Dog是一个子类,它继承了Zoon,并且添加了自己的bark方法。通过Object.create(Zoon.prototype),我们创建了Dog.prototype,它是Zoon.prototype的一个新对象,这样就保持了原型链的完整性。然后,我们将Dog.prototype.constructor重置为Dog,以确保constructor属性正确地指向子类。最后,我们创建了一个Dog的实例,并成功地调用了继承自Zoon的eat方法和Dog自己的bark方法。