在JavaScript创建对象(二)——构造函数模式中提到,构造函数模式存在相同功能的函数定义多次的问题。本篇文章就来讨论一下该问题的解决方案——原型模式。

首先我们来看下什么是原型。我们在创建一个函数时,这个函数会包含一个属性prototype,这个属性是一个指针,它指向一个对象——该函数的原型对象,这就是原型,它包含了该函数类型的所有实例可共享的属性和方法,见下面示意图:

如图所示,声明了一个函数Person。在JavaScript中,一个函数被声明的同时就具有了一些属性,其中有一个叫做prototype,它指向了该函数的原型对象,即上述示例中的Person Prototype。同时,这个原型对象有一个叫做constructor的属性反过来又指向了该函数对象。

当我们创建一个函数的实例时,例如上面的var personObj = new Person('张三', 12);,这个实例也会有一个属性指向该函数的原型对象,在Chrome的开发工具中显示为__proto__。

上面我们说原型的属性可以被该函数类型的所有实例所共享,那具体是怎么实现呢?看下面的示例:

在上面的代码中,我们并没有给实例添加name属性和sayName方法,但是依然可以通过实例调用,貌似实例天生就具有了原型的属性和方法,其实不是的,下面是在Chrome的开发工具中看到的内容:

我们看到,p1是Person类型的,我们给p1设置了age属性,这里也能看到age是18。另外我们看到p1有个__proto__属性,这个就是我们在原型示意图中说的指向原型对象的属性。

代码读取对象实例某个属性的时候会执行一次搜索,首先搜索对象实例,如果搜索到了就返回,如果没有则会继续搜索__proto__指向的原型对象,搜索到了就返回。所以上面例子中p1.age是搜索到了p1的age属性返回了,p1.name是搜索到Person Prototype的name返回了,p2.age在Person Prototype中也没搜到,于是返回了undefined。这就是实例对象共享原型属性的原理。

除了上面的写法,原型还有一种更简单的定义方式,就是用一个包含所有属性和方法的对象字面量来重写整个原型对象,这样避免了每当给原型添加一个属性就要书写一遍Person.prototype的繁琐,同时从视觉上看也更好地封装了原型的功能,如下代码所示:

现在回到文章一开始提出的相同功能的函数定义多次的问题,因为函数原型的属性和方法可以由所有实例所共享,所以只要在原型中定义一次,所有实例就都可以使用,这样就完美解决了构造函数模式的问题。

总结一下,与构造函数模式相比:

  1. 原型模式不必在构造函数中定义属性和方法,而是直接定义在原型中。
  2. 这些属性和方法被所有实例共享。
  3. 想学习更多java知识的朋友可以进群:874811168 一起学习 还有全套的免费资料领取

原型模式虽然好用,但也不是没有缺点。首先,它省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值。其次,最大的问题是由原型的共享本性带来的,下面来分析一下原型的共享问题。

通过共享,我们解决了构造函数模式相同功能的函数定义多次的问题,所以共享对于函数是有好处的。对于基本类型的属性,如上面的name、age,因为属性的搜索机制是从实例到原型,所以可以通过给实例添加一个同名的属性,屏蔽掉原型中相应的属性,问题也不大。然而,对于引用类型的数据来说,问题就比较严重了。来看下面的示例:

如上所示,Person.prototype包含了一个引用类型,数组friends,其中friends只是一个指针,['小明', '小刚']才是真正的对象。通过p1.friends修改了这个数组,因为共享的问题,p2.friends访问的也是同一个数组。假如我们的初衷就是共享一个数组,那么也没问题。但是多数情况下应该是不想共享的场景。比如这里,张三新交了一个女朋友小红,结果小红同时也是李四的女朋友,是张三有这癖好?是小红劈腿?还是人家张三只是单纯地交了个女朋友,被你搞得复杂了?这个说不清,既然说不清,那么程序就有问题。所以很少有人单独使用原型模式,那么这个问题怎么解决呢?办法还是有的,那就是组合使用构造函数模式和原型模式,这个实现也很简单,但为了区分原型模式,后面将会单独列一篇文章。

想学习更多java知识的朋友可以进群:874811168 一起学习 还有全套的免费资料领取

本文参考《JavaScript高级程序设计(第3版)》,关于原型模式的其他特点读者可以查阅第6.2.3章节,里面有详细的说明。

出处:https://my.oschina.net/bob1900/blog/2221882

JavaScript创建对象(三)——原型模式的更多相关文章

  1. javascript创建对象之原型模式(三)

    少废话,先上代码: function Human() { } Human.prototype.name = "成吉思汗"; Human.prototype.sex = " ...

  2. 从ES6重新认识JavaScript设计模式(三): 建造者模式

    1 什么是建造者模式? 建造者模式(Builder)是将一个复杂对象的构建层与其表示层相互分离,同样的构建过程可采用不同的表示. 建造者模式的特点是分步构建一个复杂的对象,可以用不同组合或顺序建造出不 ...

  3. 理解javascript中的原型模式

    一.为什么要用原型模式. 早期采用工厂模式或构造函数模式的缺点:  1.工厂模式:函数creatPerson根据接受的参数来构建一个包含所有必要信息的person对象,这个函数可以被无数次的调用,工厂 ...

  4. Javascript设计模式之原型模式、发布订阅模式

    原型模式 原型模式用于在创建对象时,通过共享某个对象原型的属性和方法,从而达到提高性能.降低内存占用.代码复用的效果. 示例一 function Person(name) { this.name = ...

  5. 浅谈JavaScript中的原型模式

    在JavaScript中创建对象由很多种方式,如工厂模式.构造函数模式.原型模式等: <pre name="code" class="html">/ ...

  6. 再起航,我的学习笔记之JavaScript设计模式09(原型模式)

    我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 我们 ...

  7. JavaScript面向对象OOM 2(JavaScript 创建对象的工厂模式和构造函数模式)

      在创建对象的时候,使用对象字面量和 new Object() 构造函数的方式创建一个对象是最简单最方便的方式.但是凡是处于初级阶段的事物都会不可避免的存在一个问题,没有普适性,意思就是说我要为世界 ...

  8. OC编程之道-创建对象之原型模式

    一 什么是原型模式?(what) 有些对象的创建代价过大或过于复杂,要是可以重建相同的对象并作轻微的改动,事情会容易的多(效率变高).典型的例子是复制组合结构(eg树形结构),从零开始构建一个树型组合 ...

  9. JavaScript设计模式-3.原型模式

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. JavaScript设计模式 (1) 原型模式

    原型模式(Prototype):用原型实例指向创建类对象,使用于创建新对象的类共享原型对象的属性以及方法. //图片轮播类 var LoopImages = function (imgArr, con ...

随机推荐

  1. Grunt、Gulp区别 webpack、 requirejs区别

    1. 书写方式 grunt 运用配置的思想来写打包脚本,一切皆配置,所以会出现比较多的配置项,诸如option,src,dest等等.而且不同的插件可能会有自己扩展字段,导致认知成本的提高,运用的时候 ...

  2. webpack初识

    1.什么是Webpack WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等) ...

  3. 第 8 章 容器网络 - 051 - 在 overlay 中运行容器

    在 overlay 中运行容器 运行一个 busybox 容器并连接到 ov_net1: docker run -itd --name bbox1 --network ov_net1 busybox ...

  4. centos7:mysql-5.7.23安装(二进制安装)

    mysql有二进制码安装,和源码编译安装(mysql5.5使用cmake安装,mysql5.7需要安装boost依赖安装),因为boost依赖安装麻烦,所以用二进制码安装 MySql 5.7.23安装 ...

  5. EntityFramework的安装

    关于EntityFramework在vs2012无法引用的问题 这段时间学习MVC,发现一个问题,我公司的电脑可以直接引用EntityFrameWork这个命名空间,但我家里面的电脑就不能直接引用,刚 ...

  6. canvas学习之饼状图

    接着上一节说,这次我使用canvas绘制了饼状图,主要是SectorGraph.js, 引入 import {canvasPoint} from '../../assets/js/canvas';im ...

  7. JavaScript动态加载资源

    //动态加载样式 function dynamicLoadingCss(path){ if(!path || path.length === 0){ return false; } var head ...

  8. CF-721C DAG图拓扑排序+费用DP

    比赛的时候写了个记忆化搜索,超时了. 后来学习了一下,这种题目应该用拓扑排序+DP来做. dp[][]保存走到[第i个节点][走过j个点]时所用的最短时间. pre[][]用前驱节点求路径 然后遍历一 ...

  9. MySql之安装以及设置密码等

    1.MySQL的下载安装.简单应用及目录介绍 1.下载安装 windows10的:https://www.cnblogs.com/clschao/articles/9916971.html linux ...

  10. Vue之vue自动化工具快速搭建单页项目目录

    1 生成项目目录 使用vue自动化工具可以快速搭建单页应用项目目录. 该工具为现代化的前端开发工作流提供了开箱即用的构建配置.只需几分钟即可创建并启动一个带热重载.保存时静态检查以及可用于生产环境的构 ...