全面解析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
对象,并调用了 hello
和 bark
方法,通过原型链的查找,我们成功访问到了继承的方法。
示例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
属性共享,在原型链的查找中被访问到,因此它们三个的值是相等的。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:全面解析js中的原型,原型对象,原型链 - Python技术站