<JavaScript> 原型与原型链(图形理解,简单易懂)看完不后悔,不看简直遗憾

本文深入探讨JavaScript中的函数对象、实例对象和原型对象,详细解析它们的产生由来和相互关系。通过实例解析了prototype、constructor和__proto__属性,阐述了对象访问成员的规则,并介绍了原型链的概念及其作用,强调了原型链在继承和属性共享中的核心地位。

目录

一.先了解相关概念:

1.什么是函数对象

2.什么是实例对象

3.什么是原型对象

二.产生由来

1.函数对象

2.原型对象

3.实例化对象

4.函数对象和原型对象之间的关系

(1)prototype

(2)constructor

(3)_proto_ 

(4)对象访问成员的过程

三.原型链

1.原型链总结:

2.原型链概述:

3.原型链推论:

4.重中之重!!!!!原型链的作用:


一.先了解相关概念:

1.什么是函数对象

        函数对象就是我们平时称呼的函数,构造函数也包含其中,在这里我们说一说构造函数与普通函数的区别.

        构造函数也是一个普通函数,和普通函数的主要区别在于调用方式不一样,作用也不一样(构造函数用来构建实例对象).在这里只提到这里,更多的大家可以自己去查阅资料哟!

                普通函数调用方式采用直接调用---'函数名()'

   <script>
        function person(){
            console.log(this);//Window
        }
        person()
    </script>

                构造函数的调用方式采用new关键字来调用---'new 函数名()'

    <script>
        function Person() {
            console.log(this);//Person{}
        }
        let p = new Person();
    </script>

2.什么是实例对象

        上面我们说到构造函数用来构建实例对象,那么我们就可以说new出来的对象或者{}就是实例对象.

3.什么是原型对象

        原型对象是指所有的函数对象都一定有一个对应的原型对象,构造函数在创建的过程中,系统自动创建出来与构造函数相关联的一个空的对象.

二.产生由来

1.函数对象

        在这里我们需要了解的是,Function函数对象是自动产生的第一个对象,也就是源头---Function函数对象.

        除了Function函数对象之外的所有函数对象,都是由Function函数对象创建的,除了我们用户自己写的函数,Function函数自动就会创建很多函数对象,例如Object,Window,Date等等,其中Object是Function自动创建的第一个函数对象.

2.原型对象

        所有的函数对象都一定有一个原型对象与之对应,所有的原型对象都是由Object函数对象创建的.

讲到这里我们通过图片更加直观的了解它们的关系

function person(){

}


3.实例化对象

        实例化对象都是被对应的函数对象创建的

function Person(id, name) {
				this.id = id;
				this.name = name;
			}	
var p1 = new Person(1, "张三");
var p2 = new Person(2, "李四");


 注意哟实参传给形参,变量和对应的值是保存在实例对象里面,不是函数对象哟!!!!!!

这里为了方便大家看就不画在上面的图里面了,是下面这样滴!


4.函数对象和原型对象之间的关系

(1)prototype

 所有的函数对象中都有一个名字叫prototype的引用类型变量,该引用类型变量是函数对象的成员,
 该引用类型变量的值是对应的原型对象的引用值,即prototype指向原型对象

      

 图中咋们把prototype旁边的空间当作引用类型变量prototype开辟的内存空间,

其中'101','111','1111'是保存的对应原型对象的引用值,通俗一点就是地址!!!!!!! 指向对应的原型对象.


(2)constructor

  有的原型对象中都有一个名为constructor引用类型变量,该引用类型变量是原型对象的成员,
  该引用类型变量的值是对应的函数对象的引用值,即constructor指向函数对象

同样的道理,图中咋们把constructor旁边的空间当作引用类型变量constructor开辟的内存空间,

其中'222','2222','22222'是保存的对应函数对象的引用值,通俗一点就是地址!!!  指向对应的函数对象


(3)_proto_

对象如何查看原型-->隐式属性__proto__

所有对象中都有一个名为__proto__引用类型变量,该引用类型变量是对象的成员.
那么问题来了~~~你知道对象中的__proto__的值是哪个对象的引用值?即指向哪个对象?

分三种情况:

注意!!!!黑色箭头表示谁创建了谁!!!


  • Function函数对象中__proto__指向Function原型对象。


  • Object原型对象中__proto__值为null


  • 除Function函数对象和Object原型对象之外。对象中的__proto__指向 ,谁创建了__protot__所属的对象,就指向谁的原型。
  • 例如p1和p2Person函数对象创建的,所以p1和p2的_proto_都指向创建它们的(Person函数对象)的原型((Person原型对象)).


  • 例如Object的函数对象和用户自己构建的Person函数的函数对象都是由Function创建的所以,这两个函数对象中的_proto_指向创建它们的(Function函数对象)的原型((Function原型对象)).


  •  例如Function原型对象和用户自己构建的Person函数的原型对象都是由Object函数对象创建的所以,这两个原型对象中的_proto_指向创建它们的(Object函数对象)的原型((Object原型对象)).

 


(4)对象访问成员的过程

        在我们的javascript代码中经常可以看到这样形式的代码,p1.show(),这表示访问实例对象中p1中的show,如果p1实例对象中由show,则找到,若p1中没有show则需要遵守一下对象访问规则:

对象访问成员的过程:

  • 当前对象中如果有该成员就该到该成员,访问结束。
  • 当前对象中如果没有该成员,则到__proto__指向的对象中找成员,找到就结束。
  • 如果还是没有找到,又通过__proto__指向的对象中去找。

我们举个简单的例子,同样执行p1.show() 


咋们通过观察show是在Object原型对象中的,和p1实例对象中并没有show,那么我们就用上述的方法来进行访问:

p1.show()    对象访问成员show的过程:

  • 访问p1.show()当前对象p1是否有成员show,若有则访问结束,很明显,在p1实例对象中没有找到
  • 在p1实例对象中没有找到,则到p1中的_proto_指向的对象(Person原型对象)中去找,也没有找到
  • 在Person原型对象中的_proto_指向的对象(Object原型对象)中去找,找到了,结束查找.

那么如果Object原型对象中也没有找到,就会报错,因为Object的_proto_的值为null,没有办法继续查找了.

大家可以自己去试试,通过观察发现,不管怎么找,如果在中途没有找到成员,终究最后都会找到Object的原型对象上面.

得出结论!!!!!重点来了

        Object的原型对象中的成员,可以所有对象访问, Object是原型链的尽头.  Object原型对象通过Object.prototype得到。

        示例Object.prototype.show() {....}, 所有对象就可以访问show函数

三.原型链

1.原型链总结:

这就是传说中的原型链,简单总结下:

  1. 所有的函数对象中都有一个名字叫prototype的引用类型变量,该引用类型变量是函数对象的成员,该引用类型变量的值是对应的原型对象的引用值,即prototype指向原型对象
  2. 所有的原型对象中都有一个名为constructor引用类型变量,该引用类型变量是原型对象的成员,该引用类型变量的值是对应的函数对象的引用值,即constructor指向函数对象
  3.  所有对象中都有一个名为__proto__引用类型变量,该引用类型变量是对象的成员,对象中的__proto__的值是哪个对象的引用值?即指向哪个对象?分三种情况:
    (1)Function函数对象中__proto__指向Function原型对象。
    (2)Object原型对象中__proto__值为null
    (3)除Function函数对象和Object原型对象之外。对象中的__proto__指向 
      谁创建了__protot__所属的对象,就指向谁的原型。

2.原型链概述:

        当在实例化的对象中访问一个属性时,首先会在该对象内部(自身属性)寻找,如找不到,则会向其__proto__指向的原型中寻找,如仍找不到,则继续向原型中__proto__指向的上级原型中寻找直至找到或Object.prototype.__proto__为止(值为null),这种链状过程即为原型链。

        通过原型链可以实现JS的继承,把父类的原型对象赋值给子类的原型,这样子类实例就可以访问父类原型上的方法了。

3.原型链推论:

  • 一个对象中如果有prototype,则该对象一定是函数对象,如果对象为函数对象,则其中一定有prototype
  • 所有的函数对象中都有prototype属性,prototype总是指向对应的原型对象,原型对象和new 出来的对象中没有
  • 一个对象中如果有constructor,则该对象一定是原型对象,如果对象为原型对象,则其中一定有constructo
  • 所有的原型对象都是由Object函数对象创建的。
  • new 出的对象(实例对象)是由函数对象创建的。
  • 所有的对象中都自带属性__proto__,__proto__指向一个对象(谁创建了它就指向谁的原型。)
  • Object原型对象中__proto__特殊,它的值为null
  • Function函数对象中__proto__特列,它指向Function原型对象

在这里可以给大家提一下,很多人以为Math是函数对象,注意Math是实例对象,非函数对象哟!!!!!

4.重中之重!!!!!原型链的作用:

  • 继承,用来实现基于原型的继承与属性的共享
  • 避免了代码冗余,减少了内存占用,公用的属性和方法,可以放到原型对象中,这样,通过该构造函数实例化的所有对象都可以使用该对象的构造函数中的属性和方法!

惊天大消息➡

        不妨试试把封装的函数.方法,放在Object.prototype上,你会发现所有对象就可以访问到了!!!!

        试试吧!!!!!!!   但是要注意,访问成员(寻找封装的函数.方法)途中别来个名字相同的截胡哟!!!!!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值