网页前端开发学习必备教程JavaScript

前端开发工程师语法基础:如何理解JavaScript原型?

2019-03-19  本文已影响11人  WEB开发李家靖

关注公众号【前端研究所】,后台回复“0.1”,1毛钱学习网易云前端课程

之前有讲过一次JavaScript原型和原型链的内容了,但是有很多同学和李老师说不好理解,今天重新整理了一下,结合一些案例,来专门讲一下原型。

我们为什么需要原型?什么是原型?

传统构造函数存在问题

很多时候,我们都喜欢使用传统的构造函数,然后使用new的方式来创建对象,但是这种方式是又点问题的。

举个例子:

通过自定义构造函数的方式,创建小狗对象:

给大家画个图理解一下对象实例化的过程:

在使用new关键字,每次创建一个对象的时候,都会在内存开辟一个新的空间,我们从上图可以看出,每只创建的小狗有一个say方法,这个方法都是独立的,但是功能完全相同。随着创建小狗的数量增多,造成内存的浪费就更多,这就是我们需要解决的问题。

为了避免内存的浪费,我们想要的其实是下图的效果:

解决方法:

这里最好的办法就是将函数体放在构造函数之外,在构造函数中只需要引用该函数即可。






              
              
            

看到这里,很多小伙伴就觉得,就这样换一下函数位置就可以解决问题了,也不算很难呀,也用不上原型呀。

但是其实这样写依然存在问题:

  • 全局变量增多,会增加引入框架命名冲突的风险

  • 代码结构混乱,会变得难以维护

  • 在这样看,想解决上面的问题,就需要用到构造函数的原型概念了

    原型的概念

    prototype:原型。每个构造函数在创建出来的时候系统会自动给这个构造函数创建
    并且关联一个空的对象。这个空的对象,就叫做原型。

    关键点理解:

  • 每一个由构造函数创建出来的对象,都会默认的和构造函数的原型关联;

  • 当使用一个方法进行属性或者方法访问的时候,会先在当前对象内查找该属性和方法,如果当前对象内未找到,就会去跟它关联的原型对象内进行查找;

  • 也就是说,在原型中定义的方法跟属性,会被这个构造函数创建出来的对象所共享;

  • 访问原型的方式:

  • 构造函数名.prototype。

    画个图大家好理解一点:

    示例代码:

    给构造函数的原型添加方法

    我们可以看到,在上面的代码里,本身Dog这个构造函数中是没有say这个方法的,我们通过Dog.prototype.say的方式,在构造函数Dog的原型中创建了一个方法,实例化出来的dog1、dog2会先在自己的对象先找say方法,找不到的时候,会去他们的原型对象中查找。

    画个图理解:

    在构造函数的原型中可以存放所有对象共享的数据,这样可以避免多次创建对象浪费内存空间的问题。

    原型的使用

    1、使用对象的动态特性

    使用对象的动态属性,其实就是直接使用prototype为原型添加属性或者方法。

    2、直接替换原型对象

    每次构造函数创建出来的时候,都会关联一个空对象,我们可以用一个对象替换掉这个空对象。

    注意:

    使用原型的时候,有几个注意点需要注意一下,我们通过几个案例来了解一下。

    1.使用对象.属性名去获取对象属性的时候,会先在自身中进行查找,如果没有,就去原型中查找;

    2.使用对象.属性名去设置对象属性的时候,只会在自身进行查找,如果有,就修改,如果没有,就添加;

    注意:一般情况下,不会将属性放在原型中,只会将方法放在原型中;

    3.在替换原型的时候,替换之前创建的对象,和替换之后创建的对象的原型不一致!!!

    画个图理解下:

    图中可以看出,实例出来的h1对象指向的原型中,只有say()方法,并没有kill()方法,所以h1.kill()会报错。同理,h2.say()也会报错。

    __proto__属性

    在js中以_开头的属性名为js的私有属性,以__开头的属性名为非标准属性。__proto__是一个非标准属性,最早由firefox提出来。

    1、构造函数的 prototype 属性

    之前我们访问构造函数原型对象的时候,使用的是prototype属性:

    在之前我们是无法通过构造函数new出来的对象访问原型的:

    2、实例对象的 __proto__ 属性

    __proto__属性最早是火狐浏览器引入的,用以通过实例对象来访问原型,这个属性在早期是非标准的属性,有了__proto__属性,就可以通过构造函数创建出来的对象直接访问原型。

    如图所示:

    3、__proto__属性的用途

  • 可以用来访问原型;

  • 在实际开发中除非有特殊的需求,不要轻易的使用实例对象的__proto__属性去修改原型的属性或方法;

  • 在调试过程中,可以轻易的查看原型的成员;

  • 由于兼容性问题,不推荐使用。

  • constuctor属性

    constructor:构造函数,原型的constructor属性指向的是和原型关联的构造函数。

    示例代码:

    画个图理解:

    获取复杂类型的数据类型:

    通过obj.constructor.name的方式,获取当前对象obj的数据类型。

    在一个的函数中,有个返回值name,它表示的是当前函数的函数名;

    实例化出来的teacher对象,它的数据类型是啥呢?我们可以通过实例对象teacher.__proto__,访问到它的原型对象,再通过.constructor访问它的构造函数,通过.name获取当前函数的函数名,所以就能得到当前对象的数据类型。又因为.__proto__是一个非标准的属性,而且实例出的对象继承原型对象的方法,所以直接可以写成:obj.constructor.name。

    其实JavaScript原型的运用更多是在面向对象编程的继承上,那在继承的时候我们具体要怎么使用呢?我们下次继续讲解!

    上一篇下一篇

    猜你喜欢

    热点阅读