原型和原型链,写的时候我把我自己讲懂了,分享给你们,希望你们也能懂~

本文详细解析了JavaScript中对象和函数的关系,说明了它们如何通过构造函数创建,以及原型(__proto__)和原型链在查找属性和方法中的作用。重点讨论了构造函数的原型与Function.prototype的关系,以及Object.prototype的特殊性。
摘要由CSDN通过智能技术生成

首先,我们要明确在JS中,引用类型只有Object。**也就是说Array、Function、Object等都可以称为对象。**但是想想我们使用一个构造函数的场景:

function Parent(name) {
    this.name = name;
}
var p = new Parent('zs');

是不是觉得很熟悉呢,当我们创建一个数组、函数、对象的时候,是不是也使用的这种语法?

let arr = new Array()
var sum = new Function("num1,num2","return num1+num2");
const o =new Object()

虽然这并不是我们常用的方法,但我们用的 var o1 ={}这种写法实际上执行的也是上述的逻辑。所以还可以推出一个结论:对象都是通过函数创建出来的。

Array就是一种key值为从0开始的有序数字的对象,value就是我们存在对应index索引下的值;

Function就是可以执行的函数对象,他最大的特点就是内部语句可执行。

这里我们就可以知道函数和对象的关系了:函数也是对象,对象都是通过函数创建的。

原型:一个函数可以看成一个类,原型是所有类都有的一个属性,原型的作用就是给这个类的每一个对象都添加一个统一的方法。

显式原型和隐式原型:

  • prototype,是函数特有的属性,显式原型,只有函数有prototype
  • _proto_,是对象具有的属性,隐式原型,每个对象都有隐式原型

constructor属性:每个函数自带prototype属性,prototype属性值是个对象,这个对象默认有constructor属性,指向这个函数本身。即:fun.prototype.constructor === fun


原型链是隐式原型的查找过程。只是查找路径上的某些对象是其他函数的显式原型。
在这里插入图片描述

这是原型链一个经典的图。我们先从上面简单的逻辑开始看。可以看出:

  1. 首先 function Foo(){},这是创建了一个类,或者说是一个构造函数。而一个函数,必定有个prototype属性指向Foo.prototype这个对象。

  2. f1、f2就是Foo的实例对象(上面写了…=new Foo())。实例对象有__ptoto__,它指向它的构造函数(我想称为父类可能好理解一些,但是这么叫起来不知道准不准确,但是下文还是会用到,方便理解)的protopype对象。也就是说 Foo.prototype === f1.__proto__。这两种写法指向的是同一个对象

  3. 由于函数.prototype.constructor === 这个函数,所以我们的构造函数和它的原型对象也有这层关系:Foo.prototype.constructor === Foo
    在这里插入图片描述

  • 这里是我打印的上述关系的图,从代码里可以看到:f1为Foo的一个实例对象,Foo身上只有一个属性名为Prototype的对象。这里面的constructor就是Foo。这也就是那个关系:Foo.prototype.constructor===Foo; f1.__proto__.constructor === Foo

  • 这个Prototype的对象身上也有个Prototype属性,我们点击看到的和上面的是不一样的。上面的Foo是构造函数,是函数,所以他里面的constructor有个name属性,指向Foo。而就控制台打印内容来说,对象的prototype应该是它继承到的一些属性方法。

  • Foo.prototype是个对象,对象是没有prototype的,控制台打印出来的结果也是undefined。所以我们后面考虑原型链的时候,对于对象,只探讨__proto__属性。
    在这里插入图片描述
    在这里插入图片描述

那么又出现了一个新问题,既然prototype是函数特有的,那么__proto__可是对象都有的,函数对象也是对象,那么函数的__proto__又是什么呢,按照上面的逻辑来说,构造函数的__proto__应该等于它的上级(父)的prototype属性,控制台打印出来是这样的。

> Foo.__proto__
< ƒ () { [native code] }
> Object.__proto__
< ƒ () { [native code] }

看不懂这个没关系,我们可以比较一下Foo.__proto__ === Object.__proto__,输出true。也就是说,确实这些构造函数,他们都是函数,所以Function应该是他们所有人的父亲。那么就有下面这个成立:**构造函数.__proto__ === Function.prototype。所有的函数都有这个共同的祖先。**同理,对象也是通过函数方法创造出来的,那么Object.__proto__===Function.prototype也该成立。

那么同理,**一切都可以看成对象,也就是说Object也可以看作所有对象类型的父,那么所有的对象类型,也应该有指向它的原型即Object.prototype的途径。**每个构造函数.prototype都是一个对象,对象的__proto__可以指向它的父的prototype。也就是说对任意的构造函数,都有:

构造函数.prototype.__proto__===Object.prototype成立。(除了Object.prototype本身)

  1. 前面铺垫完成了。同理,o1是构造函数Object()的实例对象,所以它的隐式原型属性指向构造函数Object的显式原型属性。prototypeo1.__proto__===Object.prototype肯定是成立的。
  2. 同样的,Object.prototype.constructor === Object,即o1.__proto__ .constructor === Object成立。
  3. Function同5,Funciton.prototype.constructor === Function
  • 最后,根据前面推出来的构造函数.__proto__ === Function.prototype可知,Foo.__proto__===Object.__proto__===Function.__proto__===Function.prototype

  • 根据构造函数.prototype.__proto__===Object.prototype同样可以知道,Foo.prototype.__proto__===Function.__proto__ ===Object.prototype。

但是,最后根据这个理论,Object.prototype.__proto__也应该指向Object.prototype。

事实却并不是这样:Object.prototype.__proto__,指向的是原型链的尽头,一个null。如果按照我的理论把它画出来,最后的地方是一个死循环即:这种循环对于原型链的查找没有什么意义。
在这里插入图片描述

所以说,为了不出现这种情况,它本身的__proto__属性就指向了一个空对象null。当然这只是一种猜测。

原型链就是指的是根据__proto__这条隐式原型链查找父身上的属性或方法的链式结构。由于原型链的存在,很多方法和属性即使实例对象身上没有,也可以根据原型链向上查找使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值