资讯专栏INFORMATION COLUMN

JS中那些拧巴的概念-原型

mengera88 / 2095人阅读

摘要:测试目录在文件中引入文件以下所有文件都在中玩原型构造器一说到原型一定和对象直接相关。的概念应该理解的差不多了,下面我们再造几个构造器作为练习。将构造器中的方法拷贝到实例化的对象当中。

测试目录:

在html文件中引入js文件


以下所有文件都在base.js中玩~

原型(Prototype)-构造器(Constructor)

一说到原型,一定和对象直接相关。
以前我们这样声明一个对象

当对象是一个用户时

当我们又需要一个用户时

可以看到两个对象的结构无区别。

那么问题来了,如果我们需要创建100个用户时,也要这么做吗?当然不要
两个原因:

用户的信息是动态的,我们不能在代码中把它们写死。

所以想到一种办法简化我们的工作:创建一个function专门为我们生成user

可以看出,打印的结果与前面的没有任何区别~
但是我们却少写了很多代码。

这个function的本质就是生成对象。
在这个function中,先新建一个空对象,然后将它填满,最后返回这个对象。
这样的函数我们称它为工厂函数(Factory Function),专门生产对象。

在原生JS中,有一种更加简便的生产对象的方式

这个function中的this就代表它即将生成的对象。
注意:一旦使用这种方式来定义一个工厂函数时,就要用new关键词来叫它。

打印结果依然与前面的没区别~

这种写法相当于原生JS帮我们省去了声明对象和返回对象的步骤。

像这样用new关键词叫的function通常我们称它为构造器/构造函数(Constructor),构造函数的第一个字母一般大写。
不大写也没关系,大写不过是为了让其他人知道这是一个构造函数。

Constructor的概念应该理解的差不多了,下面我们再造几个构造器作为练习。

实例一:

实例二:

原型-prototype和__proto__

生成一个对象的过程叫实例化(Instantistion)。不管在哪种语言里面都一样。

我们再给这个构造器加一些功能,比如greet和eat。

实例化一个对象whh

运行whh.greet();

当我们还需要一个用户

可见两位用户都可以greet。但是注意,它们两都实例了this.greet这个能力。也就是说,whh这个对象中有greet这个能力(方法),lsd这个对象中也有同样的方法。这两个方法是完全独立的,我们来验证这一点,在控制台中测试:

如图,说明它每实例化一次都会给自己创造一份与其它对象同样的方法。在本例中也就是greet和eat方法。这里可以理解为拷贝代码。将构造器中的方法拷贝到实例化的对象当中。

这个时候我们想 有必要一次次拷贝吗?能不能想一种办法把它们放到一个地方?当实例化的对象要用的时候用一个东西就可以了。这就引入了原型(prototype)。

创建一个function。

在控制台输入a.prototype

发现它是一个对象。
原生JS就有这样一个机制,在我们创建一个function的时候,它就首先给我们prototype这样一个对象,放到function下。

为什么要这么做呢?prototype有什么用呢?
prototype就是用于给它即将生成的对象继承下去的属性。也就是说我们一眼看不出来,但它实际拥有的能力。我们来举个栗子

它没有在自有的属性中显示name属性,而在继承的属性中显示。但当我们使用的时候是相当于自己的属性在用的。而且不管我们new了几个对象,它们中的__proto__都是一样的(其实是指向同一对象的)。下图可验证。

既然如此,我们在以下例子中就可以把greet方法放到prototype中了。

修改为

在控制台中

也就是说,现在的function只会存在一个地方,它不再需要每次都拷到实例的对象中去。

用原型的方式来指定一个方法还有一个好处,可以动态更新。

当我们想知道一个对象来自于那个工厂函数,可以在控制台中输入 对象.constructor
如图

那么就意味着,如果我们想复制一个对象的结构,可以这样做:

这就相当于

以上就是有关prototype和__proto__的逻辑。

原生对象的原型

学到这里也许我们会有个疑问,当我们就这样创建一个对象时,它的原型是什么呢?或者说它有没有父亲呢?是谁创建的它呢?

我们来打印一下就知道了~

它的constructor是一个叫Object的函数,也就是说,它是有父亲的。
也就是说,以下两种写法是等价的。

我们来测试一下以上说法是否正确。

声明两个对象

然后再控制台中测试

也就是说上面两种创建对象的方法是等价的~

还有一种情况,当我们想创建一个不继承任何东西的对象时该怎么做呢?
我们可以这样:

这样我们就创建了一个最干净的对象~

在参数中设置原型,比如

看到这里,我们应该不再恐惧对象这个东西了,它的继承关系我们已经搞的很清楚了。
下面我们做个练习:
a是一个数组,我们打印它

可以清楚的看到,它的constructor是一个叫Array的function

也就相当于

两种写法是等价的。

我们继续往下看

Array()也有继承的属性,它的constructor是Object()。

综上,如果Object()是爷爷,那么Array()就是爸爸,而我们声明的数组对象a就是儿子。

我们来试一下从爸爸那继承来的方法:(拿push方法来举例)

证明它从爸爸那继承下来的方法确实能用。

我们再来试一下从爷爷那继承来的方法:(拿toString方法来举例)

总结:在JS中只要我们不明确的用Object.create()来创建对象,其余都是继承Object.prototype的。

如何实现多级继承链

有这样一条继承链

这样的一条继承链在代码中如何体现? 我们可以应用到之前说过的构造器。

创建三个构造器,并且使用Person构造器创建一个叫lsd的人。

我们从最顶级开始看
实例两个对象并打印

前面我们提到过,实例出来的对象会各自拷一份能力。所以打印结果是false。

事实上这些纯逻辑(纯能力)的东西是没有必要拷贝的,那我们为什么不将它们放到原型中去呢?

刷新网页

此时的eat都是指向prototype的。相当于借了一个能力过来,而非拷贝一个能力过来。

接下来我们看Mammal这个构造器

那么此时实例化的对象m有没有eat和sleep这种能力呢?

可见是没有的。因为此时三个构造器是独立的,我们还没有指定它们之间的继承关系。那么如果指定这条继承链呢?

拿Mammal和Animal说,Mammal不仅要继承Animal的prototype,而且还要有自己的东西。

我们可以用到前面提到的create方法。

这种写法就相当于 {__proto__:Animal.prototype}

现在我们再来测试一下实例化的对象m

这样我们就可以说它继承成功了。

不过现在还有一个问题,我们在控制台调用一下m对象的constructor。

打印结果是Animal而非Mammal。而事实上Mammal才是m对象的constructor。这是为啥呢?

仔细看对象m的打印结果,发现并没有constructor。

这是因为我们在前面把它的prototype重写了,覆盖掉了。

所以才会继承了上一级的constructor。

补救方法是,我们再明确指定一下就可以啦。

大功告成~

接下来我们看Person

到这里我们就完成了原型的三级继承~~~~撒花!

现在还有一个问题,不同的动物毛色可能不一样,体重可能也不一样,等等等。也就是说,它们会共有一些属性,不过值不一样。
我们可以这样做:

此时实例化的对象中就有了我们用this指定的两个显性属性"color"和"weight"

但是当我们实例一个Mammal的对象并传入参数,然后打印。

我们发现,打印出来的是一个空对象。
我们希望的是,只要是动物(不管是哺乳动物还是人),都存在毛色,体重等等属性。
这个功能如何实现呢?
我们可以这样做:

我们希望Mammal中的this与Animal中的this绑定到一块。然后正常传入参数。

在Person中同理

我们来打印一个Mammal中实例化的对象m做测试,看看它是否继承Animal中的两个显性属性。

我们再来试一下Person

我们再new一个Person。

可见,显性属性是拷贝的。它们之间互不影响。这就是显性属性的继承方式。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/107578.html

相关文章

  • JS面向对象之五 【继承】

    摘要:首先为了模拟类创建对象的功能搞出了构造函数。也就是名字肤色肤色这里是继承里的自有属性生命值这里继承的共有属性的方法攻击力兵种美国大兵攻击防御死亡肤色 JS面向对象之五 【继承】 我们已经准备了很多前置知识,包括 原型链,对象和对象之间的关系 this,对象和函数之间的关系 new, 用函数批量创建特定的对象的语法糖 JS面向对象的前世今生 我们说,面向对象是一种写代码的套路。因为如...

    genefy 评论0 收藏0
  • svg的基本图形与属性【小尾巴的svg学习笔记1】

    摘要:因为项目有可能用到所以学习了一下,做此笔记,图截自慕课网,侵删。下一个笔记将会描述在代码里的实际应用。因为项目有可能用到, 所以学习了一下,做此笔记,图截自慕课网,侵删。 一、基本图形   1、矩形          x,y定义矩形的左上角坐标;     width,height定义矩形的长度和宽度;     rx,ry定义矩形的圆角半径长度,这里注意,如果rx给值了ry没给值,ry沿用rx...

    neroneroffy 评论0 收藏0
  • JS基础】原型对象的那些事(一)

    摘要:通过同一个构造函数实例化的多个实例对象具有同一个原型对象。所以当给原型对象赋值一个新对象时,切记将原型对象的指回原构造函数以上就是本次分享的内容,关于原型对象的其他知识,下一篇基础原型对象的那些事二会讲到。 谈起js的基础,绕不过去的坎就是:原型链、作用域链、this(em...好吧,还有闭包),今天总结一下关于原型对象的一些知识,供自己和大家复习。 概念理解 什么是原型对象呢?有以下...

    edgardeng 评论0 收藏0
  • 2016年云巴产品更新合集

    摘要:实时弹幕使用云巴,直播平台可快速实现视频直播中发送弹幕打赏点赞等实时互动功能。云巴聊天室支持图片上传文件发送文档评论系统正式上线新增搜索功能,我们会做得更好。 SDK 篇 Android SDK 更新 Release 1.6.3后台进程相互拉起的特殊版本 Release 1.6.4增加 so 文件 Release 1.8.0支持小米、华为推送,无需注册第三方账号 Release 1....

    CoffeX 评论0 收藏0

发表评论

0条评论

mengera88

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<