下面就是详细讲解“一文彻底理解JavaScript原型与原型链”的完整攻略:
一、JavaScript中的原型
JavaScript中的原型(prototype)是指每个函数都有一个prototype属性,它是一个指向对象的指针。prototype指针所指向的对象被称为原型对象。
1.1 构造函数与原型
当一个函数用来作为构造函数时,它所创建的对象都有一个隐式的原型指向它的prototype属性所指向的原型对象。例如:
function Person(name, age) {
this.name = name;
this.age = age;
}
var person1 = new Person('小明', 18);
上面的代码中,Person函数是一个构造函数,用来创建person1对象。因为Person函数有一个prototype属性,所以person1对象隐式地有了一个指向Person.prototype指向的原型对象的__proto__属性。我们可以通过以下代码验证:
console.log(Person.prototype === person1.__proto__); // true
1.2 原型对象的作用
原型对象的作用是为实例对象添加属性或方法。每当我们创建一个新对象时,这个对象都会自动包含一个指向原型对象的__proto__属性。这个属性包含了原型对象中所有可访问的方法和属性。
例如,我们可以在Person构造函数的原型对象中添加一个函数greet,这个函数可以在person1对象中使用,代码如下:
Person.prototype.greet = function() {
console.log('Hello, I am ' + this.name + ', I am ' + this.age + ' years old.');
}
person1.greet(); // Hello, I am 小明, I am 18 years old.
1.3 特殊的__proto__属性
原型对象有一个特殊的__proto__属性,它指向原型链中的上一级原型对象。例如:
function Animal() {}
function Dog() {}
Dog.prototype = new Animal();
var dog1 = new Dog();
console.log(dog1.__proto__ === Dog.prototype); // true
console.log(Dog.prototype.__proto__ === Animal.prototype); // true
我们可以看到,dog1的__proto__属性指向Dog.prototype,而Dog.prototype的__proto__属性指向Animal.prototype。这就形成了原型链。
二、JavaScript中的原型链
原型链是由一个个原型对象组成的链表,形成一个父子关系的层次结构。在JavaScript中,每个对象都有一个__proto__属性,通过这个属性可以找到它的原型对象,原型对象也有一个__proto__属性,指向它的父级原型对象,通过这样的方式就建立了一个由原型对象组成的层次结构,被称为原型链。
2.1 原型链的访问规则
当我们访问一个对象的一个属性时,JavaScript引擎会首先查找这个对象本身的属性,如果找不到,就会去它的__proto__属性指向的原型对象中查找该属性。如果在这个原型对象中也找不到,JavaScript就会继续查找原型对象的__proto__属性指向的父级原型对象,一直查找到最顶层的Object类型为止。
例如,我们可以在Animal构造函数的原型对象中添加一个greet函数,然后在Dog构造函数中添加一个run函数。代码如下:
function Animal() {}
Animal.prototype.greet = function() {
console.log('I am an animal.');
}
function Dog() {}
Dog.prototype.run = function() {
console.log('I can run fast!');
}
Dog.prototype.__proto__ = Animal.prototype;
var dog1 = new Dog();
dog1.greet(); // I am an animal.
dog1.run(); // I can run fast!
我们可以看到,dog1对象本身并没有greet和run方法,但是它可以通过原型链访问到Animal和Dog的原型对象,从而调用它们的方法。
2.2 instanceof运算符的实现原理
instanceof运算符可以判断一个对象是否是某个构造函数的实例。这个运算符的实现原理是通过逐级查找对象的__proto__指向的原型对象,直到找到构造函数的原型对象为止。
例如:
console.log(dog1 instanceof Dog); // true
console.log(dog1 instanceof Animal); // true
console.log(dog1 instanceof Object); // true
我们可以看到,因为dog1的原型链中有Dog.prototype、Animal.prototype和Object.prototype,所以它既是Dog的实例,也是Animal和Object的实例。
三、示例说明
3.1 实现原型继承
原型继承是一种常用的面向对象编程技术。它通过在构造函数的原型对象上添加新的属性和方法来实现继承。
例如,我们可以通过以下代码实现一个Person对象继承自Animal对象:
function Animal(name) {
this.name = name;
}
Animal.prototype.greet = function() {
console.log('I am an animal.');
}
function Person(name, age) {
Animal.call(this, name);
this.age = age;
}
Person.prototype = Object.create(Animal.prototype);
Person.prototype.constructor = Person;
Person.prototype.introduce = function() {
console.log('Hello, I am ' + this.name + ', I am ' + this.age + ' years old.');
}
var person1 = new Person('小明', 18);
person1.greet(); // I am an animal.
person1.introduce(); // Hello, I am 小明, I am 18 years old.
我们可以看到,Person对象继承了Animal对象的属性和方法,并且还添加了自己的属性和方法。
3.2 实现多层原型链继承
原型链继承可以用来实现多层继承,它通过在父对象的原型对象上添加新的属性和方法,然后在子对象的原型对象上添加一个指向父对象原型对象的__proto__属性。
例如,我们可以通过以下代码实现一个Animal对象,再通过Dog对象继承Animal对象,在通过Golden对象继承Dog对象:
function Animal() {}
Animal.prototype.greet = function() {
console.log('I am an animal.');
}
function Dog() {}
Dog.prototype = new Animal();
Dog.prototype.bark = function() {
console.log('Woof!');
}
function Golden() {}
Golden.prototype = new Dog();
Golden.prototype.play = function() {
console.log('I love playing fetch!');
}
var golden1 = new Golden();
golden1.greet(); // I am an animal.
golden1.bark(); // Woof!
golden1.play(); // I love playing fetch!
我们可以看到,Golden对象通过多层原型链继承了Animal、Dog两个对象的属性和方法,并且还添加了自己的属性和方法。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一文彻底理解JavaScript原型与原型链 - Python技术站