在JavaScript中,`__proto__` 和 `prototype` 是两个密切相关但又有所区别的概念,它们共同构成了JavaScript原型链的基础。下面我将对这两个概念进行深入的解析。
### `__proto__`
- `__proto__` 是一个非标准但广泛支持的属性,它指向了对象内部原型(prototype)的链接。每个对象在创建时都会自动获得这个属性,并指向其构造函数的 `prototype` 对象。
- 需要注意的是,由于 `__proto__` 不是标准属性,虽然它在大多数JavaScript环境中都可用,但使用它可能会带来兼容性问题或未来的不确定性。因此,更推荐使用 `Object.getPrototypeOf()` 方法来获取对象的原型。
### `prototype`
- `prototype` 是函数对象的一个属性,它指向了一个对象,这个对象将被用作由该构造函数创建的所有实例的原型。
- 当使用构造函数创建新对象时,新对象的内部原型(`__proto__`)会被设置为构造函数的 `prototype` 属性的值。这样,新对象就可以继承构造函数原型对象上的属性和方法。
- `prototype` 属性主要用于实现基于原型的继承。
### 关系
- 简而言之,一个对象的 `__proto__` 指向了创建它的构造函数的 `prototype` 属性。
- 换句话说,当你访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript 引擎就会去查找对象的原型(即 `__proto__` 指向的对象),看是否有这个属性或方法。这个过程会一直沿着原型链向上查找,直到找到该属性或方法,或者到达原型链的顶端(通常是 `Object.prototype` 的原型,即 `null`)。
### 示例
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log("Hello, my name is " + this.name);
};
var person1 = new Person("Alice");
// person1 的 __proto__ 指向 Person.prototype
console.log(person1.__proto__ === Person.prototype); // true
// 通过原型链访问 sayHello 方法
person1.sayHello(); // 输出: Hello, my name is Alice
在这个示例中,`person1` 对象是通过 `Person` 构造函数创建的。`person1` 的 `__proto__` 属性指向了 `Person.prototype`,这使得 `person1` 能够继承 `Person.prototype` 上的 `sayHello` 方法。