JS原型与原型链

本文深入探讨JavaScript中的原型和原型链概念,包括函数的prototype属性、对象的__proto__属性以及它们之间的关系。通过实例解析了原型链的工作原理,展示了如何沿着原型链查找对象的属性和方法。此外,还强调了Object作为原型链的顶层以及构造函数、原型和实例对象之间的关联。最后,通过图解和内存结构图辅助理解原型链的构建和查找过程。
摘要由CSDN通过智能技术生成

目录

一、原型

函数的prototype属性:

对象的__proto__属性:

内存结构图:

二、原型链:

内存结构图

注意

 构造函数/原型/实例对象的关系(图解)

 构造函数/原型/实例对象的关系2(图解)

总结

一、原型

原型:每当定义一个实例对象(函数function也是Function的实例对象)时,就会生成一个__proto__属性,被称为隐式原型;这个__proto__属性指向的是这个对象的构造函数的prototype,被称为显式原型。每一个对象都会从原型中“继承”属性。

函数的prototype属性:

在定义函数时自动添加的, 默认值是一个空Object对象

对象的__proto__属性:

创建对象时自动添加的, 默认值为构造函数的prototype属性值

首先看一个例子,创建一个Student类,并创建类的实例对象student:

class Student{
    constructor(name, score) {
        this.name = name;
        this.score = score;
    }

    introduce() {
        console.log(`我是${this.name},考了${this.score}分。`)
    }
}

const student = new Student('张三', 99)
console.log('student', student); // student Student { name: '张三', score: 99}
student.introduce(); // 我是张三,考了99分。

但是直接在控制台输入student,会发现只有name和score属性,没有introduce方法,但是有一个[[Prototype]]属性,用两个中括号括起来。

  把[[Prototype]]展开,会发现introduce方法在[[Prototype]]中。

 [[Prototype]]属性被称为student对象的显式原型。当我们要去找一个对象的属性或者方法时,如果在当前对象上找不到,就会沿着原型链去当前对象的显式原型[[Prototype]]属性上去找。

 原型对象中有一个属性constructor, 它指向函数对象。

可通过.__proto__属性访问原型,注意__proto__两边分别有两条下划线。

 

 而Student()构造函数也有一个prototype属性,Student()构造函数的prototype属性实际上就等于student对象的__proto__属性。

下面用一张图来说明:

 因此,构造函数的prototype属性就等于实例对象的__proto__属性,构造函数的prototype属性被称为显式原型,实例对象的__proto__属性被称为隐式原型。

内存结构图:

二、原型链:

获取对象时,如果这个对象身上本身没有这个属性时,它就会去他的原型__proto__上去找,如果还找不到,就去原型的原型上去找…一直找到最顶层(Object.prototype)为止,Object.prototype对象也有__proto__属性值为null。

这里需要注意的是,Object是原型链的最顶层,所有构造函数的prototype都指向Object.prototype

再来看一个例子,创建一个Person类,再创建一个Teacher类继承自Person类,并创建实例对象teacher:

class Person {
    constructor(name) {
        this.name = name;
    }

    drink(){
        console.log('喝水');
    }
}

class Teacher extends Person {
    constructor(name, subject) {
        super(name);
        this.subject = subject;
    }

    teach() {
        console.log(`我是${this.name}, 教${this.subject}。`)
    }
}

const teacher = new Teacher('哈默', '前端开发')
console.log('teacher', teacher);
teacher.teach();
teacher.drink();

控制台输出如下,teacher可以执行teach()和drink()方法。

展开teacher对象,发现找不到这两个方法,于是去找对象的原型,即__proto__属性,找到teach()方法,再展开下一层__proto__属性,找到drink()方法。

 下面用一张图说明:

 可以看到,teacher实例对象本身是没有teach()方法的,这时就会去teacher对象的__proto__隐式原型指向的Teacher.prototype显式原型上去找,此时找到了teach()方法并执行;同时,Teacher.prototype上仍然没有找到drink()方法,而Teacher.prototype也是一个对象,有自己的__proto__隐式原型,那么就去Teacher.prototype.__proto__上去找,Teacher.prototype.__proto__会指向Person()构造函数的显式原型Person.prototype,此时找到了drink()方法并执行,这就是原型链。

内存结构图

fn.test1();从fn出发,找到Fn的实例对象,找到test1,nice
fn.test2();从fn出发,找到Fn的实例对象,找不到test2,再从__proto__出发,找到test2();nice
fn.tostring();从fn出发,找到Fn的实例对象,找不到tostring(),再从__proto__出发,找不到tostring;再次从__prototype__,出发,在obj对象的原型中找到,but始终找不到啊


这里需要注意的是,Object是原型链的最顶层,所有构造函数的prototype都指向Object.prototype
 

注意

(1)通过__proto__形成原型链而非protrotype。

(2)__proto__属性是对象所独有的。

(3)prototype属性是函数所独有的。但是由于JS中函数也是一种对象,所以函数也拥有__proto__属性。

 构造函数/原型/实例对象的关系(图解)

 构造函数/原型/实例对象的关系2(图解)

构造函数的实例对象自动拥有构造函数原型对象的属性(方法)  利用的就是原型链

 1. 每个函数function都有一个prototype,即显式原型

2. 每个实例对象都有一个__proto__,可称为隐式原型

3. 对象的隐式原型的值为其对应构造函数的显式原型的值

总结:

  * 函数的prototype属性: 在定义函数时自动添加的, 默认值是一个空Object对象

  * 对象的__proto__属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值

  * 程序员能直接操作显式原型, 但不能直接操作隐式原型(ES6之前)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值