前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JS完美收官——原型和原型链

JS完美收官——原型和原型链

作者头像
程序员法医
发布2022-08-11 16:32:53
3940
发布2022-08-11 16:32:53
举报
文章被收录于专栏:vue全家桶vue全家桶

原型原型链这部分知识会影响到写面试题,或者做一些公共的组件和插件,总之是通用型的一些东西

🍀 原型 prototype

「所有的函数都有一个属性prototype,称之为函数原型」。那是不是真的每个函数都有呢?

举个栗子🌰:

当我们创建一个函数的时候会自动加上prototype属性,那么函数又是怎么创建的呢?函数是通过new Function创建的,所以可以认为是在new Function函数对象中自动加了一个属性prototype

举个栗子🌰:

代码语言:javascript
复制
//创建一个函数
function test(){};
//相当于
let test = new Function();//自动加了一个属性prototype原型

原型prototype到底是个什么东西呢?「默认情况下,prototype是一个普通的Object对象」,如图:

那既然prototype是对象的话,那肯定是有属性的,「默认情况下,prototype有一个属性constructor,它也是一个对象,对象存的是一个引用地址,它指向构造函数本身」

瞅张简图方便大家理解:

说明:add是个函数,函数中有个属性prototype,prototype是个对象,可以称为add的原型,add原型中又有一个属性constructor,它指向构造函数add本身。证明下,如图:

那么原型有什么用呢?原型本身没啥用,但是配合隐式原型却大有作为

🍁 隐式原型 __proto__

所有的对象都有一个属性:__proto__,称之为隐式原型。 刚刚在原型中也说了一句话:所有的函数都有一个属性prototype,称之为函数原型

「灵魂拷问:」

  1. test是个函数,请问test是否有__proto__属性?

所有函数都是对象,所以test必须有__proto__属性

  1. let obj = {},请问obj是否有prototype属性?

obj不是函数,只有函数才有prototype,普通对象是没有prototype的,但它肯定有__proto__属性

  1. test是个函数,它肯定有prototype属性,那么请问prototype里面是否有__proto__属性?

默认情况下,prototype是一个普通的Object对象,既然是对象,那必须有__proto__属性

说了这么多,那隐式原型是个啥东西啊?默认情况下,隐式原型指向创建对象的函数原型,然而创建对象的方式一定是通过new出来的,这种形式let obj = {}其实是语法糖,真正是通过let obj = new Object()创建对象的,包括创建函数,也是同理let test = new Function()

举个栗子🌰:

代码语言:javascript
复制
function test() {
            
}
let obj = new test();
//obj.__proto__ === test.prototype; 返回true

如果说test函数中返回了一个对象,那么此时情况又不一样了

代码语言:javascript
复制
function test() {
     return {};//相当于return new Object()
}
let obj = new test();
//obj.__proto__ === Object.prototype; 返回true

瞅个简图:

一个函数可以产生多个对象,每new一次产生一个对象,图中add函数通过new产生了对象1和对象2,而所有对象中都有一个属性__proto__隐式原型,而隐式原型又指向函数add的原型,从图中我们可以发现一个现象:对象1的__proto__、对象2的__proto__以及函数add的prototype它们是共用一块内存空间。这也是为什么我们把同一个函数写在原型上的原因,因为写在原型上,每个对象都可以使用。看看数组原型上有哪些方法:

这就是在提示我们,将来写构造函数的时候,应该把所有共享的东西写在原型里面。当访问一个对象的成员时,首先会看看对象自身是否拥有该成员,如果有直接使用;如果没有,会在原型链中依次查找是否拥有该成员,如果有直接使用

如果有一天发现函数原型上的方法不够用,我们可以自己写函数添加到原型上,以增强对象的功能,这种方式也叫猴子补丁,猴子补丁会导致原型污染,使用需谨慎。

🌴 原型链

我们先来看一张图,理解了图,原型链也就理解了

我们先看白色的箭头,白色表示函数的原型,每一个函数都有原型,Object函数的原型是Object对象【①】,那么自定义函数也是有原型的,自定义函数的原型也是一个对象【③】。这里有个特殊点:Function是直接被添加到内存里面的,Function指向Function的原型【②】

然后看绿色线条,绿色线条表示new,所有的函数都是通过new Function产生的,Object函数和自定义函数都是如此【④⑤】,自定义函数还会生成自定义对象【⑥】,举个例子🌰:

代码语言:javascript
复制
//自定义函数Test,通过new产生一个自定义对象obj
function Test(){};

let obj = new Test();

再看蓝色的线,表示隐式原型,前面也说了,隐式原型指向创建对象的函数原型,谁创建的它,它就指向谁,自定义函数是Function创建的,那么它就指向Function的原型【⑦】,Obejct也是通过let Object = new Function()创建的,所以Object隐式原型也会指向Function的原型【⑧】,举个例子🌰:

代码语言:javascript
复制
function Test(){};

//Test函数其实是通过下面方式创建的

let Test = new Function();

//由于所有的对象都是通过函数产生的,那么Test身上一定有__proto__
Test.__proto__ === Function.prototype;//true

📢 特殊点:由于Function是直接添加到内存的,没有谁创建它,所以Function__proto__指向自身的prototype【⑨】

接着再看蓝色箭头【⑩】,自定义对象的隐式原型指向函数的原型,举个例子🌰:

代码语言:javascript
复制
function Test(){};

let obj = new Test();

obj.__proto__ === Test.prototype;//true,自定义对象的隐式原型指向函数的原型

文章开头有提到:默认情况下,prototype是一个普通的Object对象,所以可以说原型prototype是通过new Object()创建的,于是原型对象的隐式原型都指向Object的原型【⑪⑫】

📢 特殊点:Object的原型的隐式原型指向null【⑬】,Object.prototype.__proto__ === null

看段代码:

代码语言:javascript
复制
function Test(){};
  
let obj = new Test();

console.log(obj.toString());

输出:

自定一个函数Test,obj本身并没有toString方法,那为什么可以调用toString?这是因为自身没有,会顺着隐式原型到自定义函数原型上查找,若还未找到,继续顺着自定义函数原型的隐式原型向上查找,最终在在Object原型上找到toString方法。

😊 好了, 以上就是我的分享,小伙伴们点个赞再走吧 👍 支持一下哦~ 😘,我会更有动力的 🤞

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-08-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端猎手 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 🍀 原型 prototype
  • 🍁 隐式原型 __proto__
  • 🌴 原型链
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档