返回

透过JS原型对象的迷雾:深度解析__proto__、constructor和prototype属性

前端

在JavaScript的广阔世界中,对象和函数是构建代码的基石。然而,隐藏在对象和函数背后的原型对象,却鲜为人知,却对理解JavaScript的运行机制至关重要。今天,我们将深入探究JavaScript的原型对象,揭开__proto__、constructor和prototype属性的神秘面纱,并详细解析对象和函数之间的微妙关系。准备好接受这些知识的洗礼了吗?让我们开始吧!

首先,我们需要牢记两点:

  • __proto__和constructor属性是对象所独有的。
  • prototype属性是函数所独有的。

但由于在JS中,函数也是一种对象,因此函数也拥有__proto__属性。听起来有些绕口,但理解起来并不复杂。

__proto__属性:__proto__属性指向对象的原型对象,它是一个所有对象都拥有的内部属性。对象通过__proto__属性来访问其原型对象上的属性和方法。原型对象也是一个对象,因此它也有自己的__proto__属性,如此循环往复,最终指向null,这便是原型链的顶端。

constructor属性:constructor属性指向创建该对象的函数。通过constructor属性,对象可以访问创建它的函数的属性和方法。

prototype属性:prototype属性指向函数的原型对象。prototype对象是一个函数创建的所有实例对象共享的对象。换句话说,它充当所有该函数创建的对象的父对象。prototype对象也是一个对象,因此它也有自己的__proto__属性,同样指向函数本身。

这些属性之间有着千丝万缕的联系,共同构成了JavaScript的原型链。原型链是一种查找属性的机制,当一个对象找不到某个属性时,它会沿着原型链向上查找,直到找到该属性为止。

原型链中的对象之间共享属性和方法,这使得JavaScript的继承机制得以实现。子对象可以继承父对象的属性和方法,而无需重新定义。这不仅减少了代码的冗余,而且提高了代码的可维护性。

现在,让我们通过几个实例来进一步理解这些属性:

const person = {
  name: 'John Doe',
  age: 30
};

console.log(person.__proto__); // Object {}
console.log(person.constructor); // function Object() { [native code] }
console.log(Object.prototype); // {}

const student = new Person('Jane Doe', 20);

console.log(student.__proto__); // Person {}
console.log(student.constructor); // function Person() { [native code] }
console.log(student.prototype); // undefined

在第一个例子中,person对象是一个普通对象,它的__proto__属性指向Object.prototype对象,这是一个所有JavaScript对象都共享的原型对象。person对象的constructor属性指向Person()函数,这是一个创建对象的函数。

在第二个例子中,student对象是一个Person()函数创建的实例对象。它的__proto__属性指向Person.prototype对象,这是一个Person()函数创建的所有实例对象共享的原型对象。student对象的constructor属性指向Person()函数。student对象没有prototype属性,因为只有函数才有prototype属性。

通过这些示例,我们对__proto__、constructor和prototype属性有了更深入的理解。这些属性共同作用,形成了JavaScript的原型链。原型链使对象可以继承父对象