原型与原型链

本文主要讲解原型Prototype与原型链Prototype Chain,通过一个案例了解相关知识。

1.对原型、原型链的理解

(1)原型(Prototype)

定义原型是JavaScript中对象的一个内置属性([[Prototype]],通常通过__proto__访问,但建议使用Object.getPrototypeOf()),每个构造函数都有一个prototype属性,它包含了所有通过该函数创建的实例共享的属性和方法。

在下面例子中,Person.prototypePerson函数的原型对象,它定义了sayHello方法。所有通过new Person()创建的实例都会继承这个方法。

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

Person.prototype.sayHello = function() { 
    console.log('Hello, my name is ' + this.name); 
}; 

let person1 = new Person('Alice', 30); 
let person2 = new Person('Bob', 25); 
person1.sayHello(); // 输出: Hello, my name is Alice 
person2.sayHello(); // 输出: Hello, my name is Bob

console.log(Object.getPrototypeOf(person1)); // 获取对象的原型 

(2)原型链(Prototype Chain)

定义:原型链是通过对象之间的原型关系实现继承的一种机制,它定义了对象之间的继承关系。它是由多个原型对象通过__proto__属性(在ES6中推荐使用Object.getPrototypeOf()方法)连接而成的一种链式结构。当一个对象需要访问某个属性或方法时,如果该对象本身不包含该属性或方法,JavaScript会沿着原型链向上查找,直到找到该属性或方法为止。

原型链的顶端是Object.prototype,这是所有JavaScript对象最终都会继承的原型对象。

继续上面的例子,当调用person1.sayHello()时,JavaScript会首先查找person1对象上是否有sayHello方法。如果没有找到,它会查找person1的原型(即Person.prototype)上是否有该方法。因为Person.prototype上定义了sayHello方法,所以该方法会被调用。

综上所述:在JavaScript中,原型和原型链是实现基于原型的继承的重要基础。通过原型和原型链,我们可以实现对象之间的属性和方法的共享和继承。

2.原型修改、重写

(1)原型修改

修改原型意味着向现有的原型对象添加新的属性或方法,或者修改现有属性或方法的值,这会影响到所有通过该构造函数创建的实例。

// 接着上面的例子
// 修改原型  
Person.prototype.greet = function() {  
    console.log('Hi, I am ' + this.name);  
};  
  
// 修改后的原型会影响之前的实例  
person1.greet(); // 输出: Hi, I am Alice  
  
// 创建一个新实例也会继承修改后的原型  
let person3 = new Person('哈哈');  
person3.greet(); // 输出: Hi, I am 哈哈

(2)原型重写

重写原型意味着你完全替换一个对象的原型对象,而不是仅仅修改它。这可以通过将新的对象直接赋值给构造函数的prototype属性来实现。

注意:重写原型时要特别小心,因为这可能会破坏现有的实例。

// 继续上面例子 
// 原型重写
Person.prototype = {  
    greet: function() {  
        console.log('I am ' + this.name + ',' + this.age + 'years old.');  
    },  
    // 添加constructor属性指向构造函数,以保持一致性  
    constructor: Person  
};  

// 注意:person1 仍然引用旧的原型对象,因为它是在原型重写之前创建的  
person1.greet(); // Hi, I am Alice

// 但新创建的实例会继承新的原型  
let person4 = new Person('Bob',18);  
person4.greet(); // 输出: I am Bob,18years old.

3.原型链指向

(1)对象的__proto__属性

每个对象都有一个__proto__属性,它指向该对象的原型对象,这是实现原型链的基础。

(2)原型对象的constructor属性

原型对象通常会有一个constructor属性,它指向创建该原型对象的构造函数,这有助于在原型链中追踪对象的创建来源。

(3)原型链的终点

原型链最终会指向Object.prototype,这是JavaScript中所有对象的最终原型。Object.prototype本身没有原型,即Object.prototype.__proto__null标志着原型链的结束。

(4)属性/方法的查找

当尝试访问一个对象的属性或方法时,如果该对象本身没有该属性或方法,JavaScript会沿着原型链向上查找,直到找到该属性、方法或到达原型链的末端(即Object.prototype)。如果在Object.prototype中也没有找到,则返回undefined(对于属性)或抛出错误(对于方法)。

// 原型链指向
console.log(person4.__proto__);
console.log(person4.__proto__.__proto__);
console.log(person4.__proto__.__proto__.__proto__);// null
console.log(person4.constructor);
console.log(Object.getPrototypeOf(person4.__proto__.__proto__));// null

4.原型链的终点

上面提到过,原型链终点是Object.prototype.__proto__,当Object.prototype.__proto__null标志着原型链的结束。

console.log(Object.getPrototypeOf(person4.__proto__.__proto__));// null

5.判断属性是否属于原型链上的属性

使用hasOwnProperty()方法判断是否属于原型链的属性。

// 判断属性是否属于原型链的属性
console.log(person4.hasOwnProperty('name'));// true
console.log(person4.hasOwnProperty('age'));// true
console.log(person4.hasOwnProperty('greet'));// false
console.log(person4.hasOwnProperty('constructor'));// false
console.log(person4.__proto__.hasOwnProperty('greet'));// true  
console.log(person4.__proto__.__proto__.hasOwnProperty('constructor'));// true

总结:

原型是包含共享属性和方法的对象,是对象之间共享功能的桥梁。

原型链是对象之间通过原型连接起来的链式结构,它决定了对象如何查找属性和方法。

原型和原型链在JavaScript中是实现继承、方法共享和扩展对象功能的关键机制。它们的应用贯穿了JavaScript面向对象编程的各个方面。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端绘梦师

你的鼓励是我最大的动力!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值