• JS 原型的原理


    接下来,我们要说一个很重要的东西,就是原型,也就是 prototype。

    原型这个东西在 js 里面是非常有用的一个东西,也非常的重要。

    对于前端来说,原型肯定不会陌生。

    但是有几个问题:这玩意到底是干啥的?它的原理是什么?都用在哪里?

    首先,这里用一句话特别明确的告诉大家:

    原型这个东西,它可以给类添加或修改东西,这样的话,这个类它所有的实例就都会有这个东西,这是它的根本作用。

    那么我们就直接来一个例子看看:
    在这里插入图片描述
    可以看到,当我们在数组的原型上面加了一个 a = ‘123’ 之后,它就有了。

    最厉害的是,以后我再蹦出来一些别的数组实例,只要它还是个数组,那它上面就也会有这个 a:
    在这里插入图片描述
    这个就是原型的作用,它可以给类添加东西,添加完之后,这个类所 new 出来的,所有实例上面都有这个东西。
    那么现在我们就有一个问题,怎么做到的,它的原理是什么?

    它的原理其实非常的简单,就是在你这个实例需要某个东西的时候(这个东西可以是个属性,也可以是个方法),它是这样的一个顺序:
    首先,从自己身上找, 如果自己身上有,那就直接拿来用。如果没有,它会继续去我的这个类身上找。如果类身上有,那自然就好。如果还没有,它还会再去父类的原型上面试着找一下。如果还没有,在往上找,一直找到最后,能找到 Object.prototype 上,这是它最终的一个归宿(因为 Object 其实是所有人间接的祖宗,它是最上面的)。一直找到 Object 身上,如果还没有,不好意思,undefined,没找到就是 undefined。
    说白了,先在自己身上找,没有就找它爹要,找他爹其实就是在找它爹的原型,还没有,就找它爷爷,一直找到 Object 身上,还没有,就是 undefined。

    既然了解了原型,那我什么时候会用到它?可以用它来干啥?

    以前的时候可能还会用的多一点,现在有专门的class了,方法直接写里面,那还要原型干啥?

    当然有用,用途也非常的简单,就是给类去添加方法。

    一般情况下,分成 2 种用途:
    1,添加一些公共的方法。
    假设我现在有一个方法,它的作用是统计一下我这个字符串里面有几个 a,那么注意,我有两种方法来做这个事:

    首先第一个方法,我可以把它封装成一个函数:
    在这里插入图片描述
    这种方法是可以的,但是有 2 个问题:

    1,太啰嗦了。人家每次用的时候都是括号罗括号,如果层级深一点,变量名长一点,看起来就一大堆,很麻烦。

    2,你直接把 function countA(){} 这个函数给露在全局外面,这个时候其实很容易重名的。

    所以第二种方法可以这么来写,我们可以直接把它扔到原型上面去:
    在这里插入图片描述
    可以看到,一样的可以去解决问题。

    并且,在用法上 str.countA() 比 countA(str) 用起来比较方便和自然。

    而且最重要的是,不容易重名。因为如果是一个全局的变量,那就很容易重名。

    比如现在这个是统计字符串的 a,如果我还有一个 countA 是用来统计数组有几个 a 的呢?
    在这里插入图片描述
    这样就不会重名。

    所以,原型的第一种用途就是,可以去给一些类,不管是系统类,还是你自己的类,去添加一些公共的方法。
    然后第二种用途就是,可以去修补系统的函数
    什么意思呢?

    这种用法其实用的还蛮多的,有人给它起了个专门的名词叫 polyfill,补充系统函数的功能
    相信大家经常看到 polyfill 这个词,其对应的中文也有很多,比如适配器,垫片等等。刚开始的时候百思不得其解,啥玩意啊?
    其实说白了,polyfill 就是兼容。
    比如 map 函数在高级浏览器中是没问题的:
    在这里插入图片描述
    可以看到,这个结果在谷歌浏览器上面是 OK 的。

    但是,低级浏览器是不认识 map 的,它是 ES6 才出现的函数,比如 IE:
    在这里插入图片描述
    那么如果我们用了这种方法之后,是不是在低级浏览器上也能使用 map 了:
    在这里插入图片描述
    就是这么简单。

    当然这时候还有个问题,就是我们自己实现的方法,虽然说功能是一致的,但是它的性能远不如原生提供的方法来的高。
    所以,我们可以这么写:
    在这里插入图片描述
    说的直白点,如果本身你就有 map,那就用系统那套,因为系统那套性能高。

    如果没有,Array.prototype.map 是 undefined,那我就用后面自己实现的这个。

    这样的话,既照顾了低级浏览器,高级浏览器下面也还是用的系统那套,性能不会受到影响。

    这个就是原型的一个用法。

    到现在,我们基本上来说,就算是理解了原型各种各样的一些东西,那么我们来总结一遍:

    原型在以前的版本当中,其实它更主要的是帮我们来实现这个类本身。

    而现在,我们有了 class 之后,理论上,在我写这个类的时候,其实是用不着原型了,但是原型它自己也有很大的作用。

    原型的作用其实非常的简单,就是给这个类去添加方法。
    它不是去给某一个实例加,它是给类加东西,加完之后,所有的实例它都会有。

    当然这里面我们不光要了解它的一个作用,我们也得知道它为什么能起这个作用,这个也是一件很重要的事。

    这个过程其实特别的简单,当然这个过程不用我们来完成,都是由 js,由语言自身来支撑这些功能的,不用我们来做。

    就是说它其实会往上找,就这三个字,就能体现它这功能的原理。
    说白了就是说,它会先去找实例本身,如果有,那自然最好。如果没有,没关系,我可以找实例所对应的那个类,它的原型,然后找它的原型上有没有。如果还没有的话,它还会继续往上再来找,这样的一个过程。

    所以说原型这个东西,其实也并不复杂。

    然后原型的功能,或者说我们什么时候去用它,它一般来说有 2 个大用途:

    • 第一个,我可以去给这个类去添加一些公共的方法
    • 第二个,给系统类去打补丁。你有就用你的,因为系统自带的,肯定性能最高,没有就再用我这个。
  • 相关阅读:
    EFK环境搭建(基于K8S环境部署)
    HTTP头部信息解释分析(详细整理)(转载)
    SpringSecurity
    MyBatis-Plus入门案例
    刷题笔记17——KMP
    数说故事香氛品类分析及行业新趋势、消费者需求洞察
    如何导出文件名到Excel?
    JAVA中的异常
    一个简单好用的localstorage组件store
    延误件如何筛选 物流查询分享查询方法筛选延误三天以上物流件
  • 原文地址:https://blog.csdn.net/wu_2004/article/details/133034997