关键词

全面解析js中的原型,原型对象,原型链

全面解析JS中的原型、原型对象、原型链

1. 原型

在Javascript中,每个函数都有一个内部属性 prototype,可以被称为原型。我们可以通过构造函数的 prototype 属性来为所有实例共享方法和属性。

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

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

const person1 = new Person('Tom', 18);
const person2 = new Person('Jerry', 20);

person1.sayHello(); // 输出:Hello, my name is Tom and I'm 18 years old.
person2.sayHello(); // 输出:Hello, my name is Jerry and I'm 20 years old.

2. 原型对象

在JavaScript中,所有的对象都有一个特殊的属性 __proto__,它指向了对象的原型。我们可以通过对象的 __proto__ 属性来访问原型对象。每个构造函数的 prototype 都是一个对象,它作为 Constructor 构造函数的原型对象。

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

const person1 = new Person('Tom', 18);

// 访问原型对象
console.log(Person.prototype); // 输出:{sayHello: ƒ, constructor: ƒ}
console.log(person1.__proto__); // 输出:{sayHello: ƒ, constructor: ƒ}

// 验证原型对象
console.log(Person.prototype === person1.__proto__); // 输出:true

3. 原型链

当我们访问一个对象的属性时,如果对象本身没有该属性,javascript会沿着对象的 __proto__ 属性向上查找,一直到 __proto__ 为 null,该属性不存在。这个查找的过程就是原型链。

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

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

const person1 = new Person('Tom', 18);

person1.sayHello(); // 输出:Hello, my name is Tom and I'm 18 years old.
console.log(person1.toString()); // 输出:[object Object]

在上面的代码中,当我们调用 person1.sayHello() 的时候,由于 person1 没有 sayHello 方法,javascript会在 person1.__proto__ 中查找,找到了 Person.prototype 中的 sayHello 方法并执行了;而当我们调用 person1.toString() 方法的时候,javascript会一直往上查找,最后找到了 Object.prototype 中的 toString 方法并执行了。

示例1

function Animal(name) {
  this.name = name;
}

Animal.prototype.hello = function() {
  console.log(`I'm ${this.name}.`);
}

function Dog(name, color) {
  this.color = color;
  Animal.call(this, name); // 调用父类构造函数,通过call或apply方法改变this的指向
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {
  console.log(`I'm a ${this.color} dog.`);
}

const dog1 = new Dog('Toby', 'brown');
dog1.hello(); // 输出:I'm Toby.
dog1.bark(); // 输出:I'm a brown dog.

在上面的代码中,我们定义了一个 Animal 构造函数用于创建动物,并给所有动物都添加了一个 hello 方法。接着我们定义了一个 Dog 构造函数用于创建狗,继承了 Animal 构造函数,并给狗添加了一个 bark 方法。最后我们创建了一个 dog1 对象,并调用了 hellobark 方法,通过原型链的查找,我们成功访问到了继承的方法。

示例2

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

const person1 = new Person('Tom');

console.log(person1.constructor); // 输出:[Function: Person]
console.log(person1.__proto__.constructor); // 输出:[Function: Person]
console.log(Person.prototype.constructor); // 输出:[Function: Person]

在上面的代码中,我们定义了一个 Person 构造函数用于创建人,并创建了一个 person1 对象。接着我们访问了三个 constructor 属性,并打印了它们的值。由于 constructor 属性会随着 prototype 属性共享,在原型链的查找中被访问到,因此它们三个的值是相等的。

本文链接:http://task.lmcjl.com/news/9116.html

展开阅读全文