返回

刨根问底,搞懂原型链里的prototype和__proto__!

前端

JavaScript 原型链:深入解析 prototype 和 proto

什么是原型链?

JavaScript 中,原型链是一种对象继承机制,允许对象从其原型对象继承属性和方法。每个对象都有一个原型对象,而原型对象又有自己的原型对象,如此层层相连,形成一个原型链。

prototype 属性

每个函数都有一个 prototype 属性,它指向一个对象,该对象包含该函数创建的所有对象的共享属性和方法。当我们创建一个新对象时,它的 prototype 属性将被设置为其构造函数的 prototype 属性。

例如:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};

const person1 = new Person('John', 30);
const person2 = new Person('Jane', 25);

person1.greet(); // Hello, my name is John and I am 30 years old.
person2.greet(); // Hello, my name is Jane and I am 25 years old.

在这个示例中,Person 函数的 prototype 属性是一个包含 greet 方法的对象。当我们创建 person1 和 person2 对象时,它们的 prototype 属性都被设置为 Person.prototype,因此它们都可以访问 greet 方法。

proto 属性

每个对象都有一个 proto 属性,它指向该对象的原型对象。当我们访问一个对象的属性或方法时,JavaScript 会首先在该对象中查找。如果找不到,它会沿着原型链向上查找,直到找到该属性或方法。

例如:

const person1 = new Person('John', 30);

console.log(person1.__proto__ === Person.prototype); // true
console.log(person1.__proto__.__proto__ === Object.prototype); // true

在这个示例中,person1.proto 指向 Person.prototype,而 Person.prototype.proto 指向 Object.prototype。因此,person1 可以访问 Person.prototype 和 Object.prototype 中的所有属性和方法。

原型链在继承中的作用

原型链在 JavaScript 中实现继承。当一个对象从另一个对象继承时,它会继承该对象的原型链。例如:

function Employee(name, age, salary) {
  Person.call(this, name, age);
  this.salary = salary;
}

Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;

const employee1 = new Employee('John', 30, 10000);

employee1.greet(); // Hello, my name is John and I am 30 years old.
console.log(employee1.salary); // 10000

在这个示例中,Employee 函数继承了 Person 函数。Employee.prototype 被设置为 Object.create(Person.prototype),这创建一个新的对象,该对象包含 Person.prototype 中的所有属性和方法。然后,Employee.prototype.constructor 被设置为 Employee,这确保新创建的 Employee 对象的 prototype 属性指向 Employee.prototype。

因此,employee1 对象可以访问 Person.prototype 和 Employee.prototype 中的所有属性和方法,包括 greet 方法和 salary 属性。

为什么要设计 prototype 和 proto 属性?

prototype 和 proto 属性是 JavaScript 中实现原型链和继承的关键机制。它们允许对象从其原型对象继承属性和方法,从而实现代码重用和继承。

prototype 属性允许我们为所有由某个构造函数创建的对象定义共享属性和方法。这使得我们可以在创建新对象时轻松地添加新的属性和方法,而无需修改构造函数。

proto 属性允许我们访问对象的原型对象。这使得我们可以在运行时检查对象的原型对象,并访问原型对象中的属性和方法。

常见问题解答

  1. 原型链和继承链有什么区别?

    • 原型链了对象查找属性和方法的顺序。继承链了对象从其父对象继承属性和方法的顺序。
  2. prototype 和 proto 属性之间的关系是什么?

    • prototype 属性指向一个对象的原型对象,而 proto 属性指向该对象的原型对象。
  3. 我可以修改对象的 prototype 属性吗?

    • 可以,但这样做可能会影响所有使用该 prototype 对象的对象。
  4. proto 属性和 Object.getPrototypeOf() 方法有什么区别?

    • proto 属性是一个指向对象的原型对象的属性,而 Object.getPrototypeOf() 方法返回指向对象的原型对象的引用。
  5. JavaScript 中的类和原型链有什么关系?

    • 在 JavaScript 中,类只是语法糖,它允许我们使用更类似于其他面向对象语言的语法来定义对象。类幕后仍然使用原型链。