想象我们在制作一个策略类战争游戏,玩家可以操作一堆士兵攻击敌方。

我们着重来研究一下这个游戏里面的「制造士兵」环节。

一个士兵的在计算机里就是一堆属性,如下图:

一、荒蛮时代:对象是数据的集合

我们只需要这样就可以制造一个士兵:

var 士兵 = {

ID: 1, // 用于区分每个士兵

兵种:"美国大兵",

攻击力:5,

生命值:42,

行走:function(){ /*走俩步的代码*/},

奔跑:function(){ /*狂奔的代码*/  },

死亡:function(){ /*Go die*/    },

攻击:function(){ /*糊他熊脸*/   },

防御:function(){ /*护脸*/       }

}

兵营.制造(士兵)

制造一百个士兵

如果需要制造 100 个士兵怎么办呢?

循环 100 次吧:

var 士兵们 = []

var 士兵

for(var i=0; i<100; i++){

士兵 = {

ID: i, // ID 不能重复

兵种:"美国大兵",

攻击力:5,

生命值:42,

行走:function(){ /*走俩步的代码*/},

奔跑:function(){ /*狂奔的代码*/  },

死亡:function(){ /*Go die*/    },

攻击:function(){ /*糊他熊脸*/   },

防御:function(){ /*护脸*/       }

}

士兵们.push(士兵)

}

兵营.批量制造(士兵们)

哎呀好简单。

质疑

上面的代码存在一个问题:浪费了很多内存。

行走、奔跑、死亡、攻击、防御这五个动作对于每个士兵其实是一样的,只需要各自引用同一个函数就可以了,没必要重复创建 100 个行走、100个奔跑……

这些士兵的兵种和攻击力都是一样的,没必要创建 100 次。

只有 ID 和生命值需要创建 100 次,因为每个士兵有自己的 ID 和生命值。

二、原型时代:对于公用的封装

改进

看过我们的专栏以前文章(JS 原型链)的同学肯定知道,用原型链可以解决重复创建的问题:我们先创建一个「士兵原型」,然后让「士兵」的 __proto__ 指向「士兵原型」

var 士兵原型 = {

兵种:"美国大兵",

攻击力:5,

行走:function(){ /*走俩步的代码*/},

奔跑:function(){ /*狂奔的代码*/  },

死亡:function(){ /*Go die*/    },

攻击:function(){ /*糊他熊脸*/   },

防御:function(){ /*护脸*/       }

}

var 士兵们 = []

var 士兵

for(var i=0; i<100; i++){

士兵 = {

ID: i, // ID 不能重复

生命值:42

}

/*实际工作中不要这样写,因为 __proto__ 不是标准属性*/

士兵.__proto__ = 士兵原型

士兵们.push(士兵)

}

兵营.批量制造(士兵们)

三、原型+临时模版时代

优雅?

有人指出创建一个士兵的代码分散在两个地方很不优雅,于是我们用一个函数把这两部分联系起来:

function 士兵(ID){

var 临时对象 = {}

临时对象.__proto__ = 士兵.原型

临时对象.ID = ID

临时对象.生命值 = 42

return 临时对象

}

士兵.原型 = {

兵种:"美国大兵",

攻击力:5,

行走:function(){ /*走俩步的代码*/},

奔跑:function(){ /*狂奔的代码*/  },

死亡:function(){ /*Go die*/    },

攻击:function(){ /*糊他熊脸*/   },

防御:function(){ /*护脸*/       }

}

// 保存为文件:士兵.js

然后就可以愉快地引用「士兵」来创建士兵了:

var 士兵们 = []

for(var i=0; i<100; i++){

士兵们.push(士兵(i))

}

兵营.批量制造(士兵们)

四、模版+原型+二阶构造:new时代

JS 之父的关怀

JS 之父创建了 new 关键字,可以让我们少写几行代码:

只要你在士兵前面使用 new 关键字,那么可以少做四件事情:

不用创建临时对象,因为 new 会帮你做(你使用「this」就可以访问到临时对象);

不用绑定原型,因为 new 会帮你做(new 为了知道原型在哪,所以指定原型的名字为 prototype);

不用 return 临时对象,因为 new 会帮你做;

不要给原型想名字了,因为 new 指定名字为 prototype。

这一次我们用 new 来写

function 士兵(ID){

this.ID = ID

this.生命值 = 42

}

士兵.prototype = {

兵种:"美国大兵",

攻击力:5,

行走:function(){ /*走俩步的代码*/},

奔跑:function(){ /*狂奔的代码*/  },

死亡:function(){ /*Go die*/    },

攻击:function(){ /*糊他熊脸*/   },

防御:function(){ /*护脸*/       }

}

// 保存为文件:士兵.js

然后是创建士兵(加了一个 new 关键字):

var 士兵们 = []

for(var i=0; i<100; i++){

士兵们.push(new 士兵(i))

}

兵营.批量制造(士兵们)

new 的作用,就是省那么几行代码。(也就是所谓的语法糖)

注意 constructor 属性

new 操作为了记录「临时对象是由哪个函数创建的」,所以预先给「士兵.prototype」加了一个 constructor 属性:

士兵.prototype = {

constructor: 士兵

}

https://zhuanlan.zhihu.com/p/23987456

js编程思想:模型进化论--JS 的 new 到底是干什么的?的更多相关文章

  1. JS基础语法---编程思想和对象

    编程思想: 把一些生活中做事的经验融入到程序中 面向过程:凡事都要亲力亲为,每件事的具体过程都要知道,注重的是过程 面向对象:根据需求找对象,所有的事都用对象来做,注重的是结果 面向对象特性: 封装, ...

  2. JS高级---体会面向对象和面向过程的编程思想

    体会面向对象和面向过程的编程思想 ChangeStyle是自定义的构造函数,再通过原型添加方法的函数. 实例化对象,导入json参数,和创建cs,调用原型添加的方法函数 过渡,先熟悉记忆 <!D ...

  3. js高级编程思想

    js惰性思想: 能够执行一次就搞定绝对不会执行第二次 function createXHR(){ var xhr=null, falg=false, ary=[ function(){ return ...

  4. JS高级---面向对象的编程思想(贪吃蛇梳理)

    面向对象的编程思想(贪吃蛇梳理) 模拟贪吃蛇游戏,做的项目 地图: 宽,高,背景颜色,因为小蛇和食物都是相对于地图显示的, 这里小蛇和食物都是地图的子元素, 随机位置显示, 脱离文档流的, 地图也需要 ...

  5. 翻译连载 | 第 9 章:递归(下)-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇

    原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...

  6. 翻译连载 | 第 11 章:融会贯通 -《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇

    原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...

  7. 翻译连载 | 附录 A:Transducing(上)-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇

    原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...

  8. 翻译连载 | 附录 B: 谦虚的 Monad-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇

    原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...

  9. JS编程题练习

    JS编程题练习 1. 两个数组合并成一个数组排序返回 先依次比较两个数组,按照小的就传入新的数组.当这次比较完之后可能有一个数组的长度很长,留下一些数组,然后在新数组的末尾插入即可. function ...

随机推荐

  1. maven-3.6.1

    1.下载 cd /opt/ wget https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.6.1/binaries/apache-m ...

  2. 028 ElasticSearch----全文检索技术03---基础知识详解01-IK分词器和映射

    1.IK分词器 (1)安装 使用IK分词器可以实现对中文分词的效果.下载IK分词器:(Github地址:https://github.com/medcl/elasticsearch-analysis- ...

  3. FEL表达式的用法

    Fel是开放的,引擎执行中的多个模块都可以扩展或替换.Fel的执行主要是通过函数实现,运算符(+.-等都是Fel函数),所有这些函数都是可以替换的,扩展函数也非常简单. Fel有双引擎,同时支持解释执 ...

  4. myeclipse安装android开发环境全过程

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/liang_824/article/det ...

  5. Python 监控脚本

    Python 监控脚本 整体通过psutil模块动态获取资源信息.下为示例图: #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time: 2019- ...

  6. centOS 在线安装lnmp

    CentOS7源码安装最新版LNMP环境   lnmp环境版本如下: 系统:CentOS 7 x86_64 NGINX:nginx-1.7.12 数据库:mariadb-10.0.13 PHP:php ...

  7. .net平台下对C#代码的编译

    最近赶项目忽然想到一个问题,那就是在 .Net平台下的C#代码是怎么从源代码到机器可以识别的电脑的(只怪自己上学不好好读书,现在又要重补一遍了!!!) 话不多说直接上调研结果: 预习知识: 1: IL ...

  8. ASP.NET MVC 允许跨域请求设置

    场景:创建一个图片上传的站点,用于其他站点跨域上传附件和图片之类. 上传插件结合百度的 webuploader.js 经常会碰到,跨域的问题,如下, 处理方式呢,是在web.config 中配置允许跨 ...

  9. vue自定义指令VNode详解(转)

    1.自定义指令钩子函数 Vue.directive('my-directive', {bind: function () {// 做绑定的准备工作// 比如添加事件监听器,或是其他只需要执行一次的复杂 ...

  10. element-ui Upload 上传获取当前选择的视频时长

    <el-upload class="upload-demo" ref="vidos" :action="URL+'/api/post/file' ...