转自知乎大神----JS 的 new 到底是干什么的?
大部分讲 new 的文章会从面向对象的思路讲起,但是我始终认为,在解释一个事物的时候,不应该引入另一个更复杂的事物。
今天我从「省代码」的角度来讲 new。
---------------------------
想象我们在制作一个策略类战争游戏,玩家可以操作一堆士兵攻击敌方。
我们着重来研究一下这个游戏里面的「制造士兵」环节。
一个士兵的在计算机里就是一堆属性,如下图:
我们只需要这样就可以制造一个士兵:
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))
}
兵营.批量制造(士兵们)
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: 士兵
}
如果你重新对「士兵.prototype」赋值,那么这个 constructor 属性就没了,所以你应该这么写:
士兵.prototype.兵种 = "美国大兵"
士兵.prototype.攻击力 = 5
士兵.prototype.行走 = function(){ /*走俩步的代码*/}
士兵.prototype.奔跑 = function(){ /*狂奔的代码*/ }
士兵.prototype.死亡 = function(){ /*Go die*/ }
士兵.prototype.攻击 = function(){ /*糊他熊脸*/ }
士兵.prototype.防御 = function(){ /*护脸*/ }
或者你也可以自己给 constructor 重新赋值:
士兵.prototype = {
constructor: 士兵,
兵种:"美国大兵",
攻击力:5,
行走:function(){ /*走俩步的代码*/},
奔跑:function(){ /*狂奔的代码*/ },
死亡:function(){ /*Go die*/ },
攻击:function(){ /*糊他熊脸*/ },
防御:function(){ /*护脸*/ }
}
完。
喜欢本文,请关注我的专栏《前端开发指南》。
想学前端?到 Q 群里找我:108801207
转自知乎大神----JS 的 new 到底是干什么的?的更多相关文章
- 转载自知乎大神---this 的值到底是什么?一次说清楚
你可能遇到过这样的 JS 面试题: var obj = { foo: function(){ console.log(this) } } var bar = obj.foo obj.foo() // ...
- 转自知乎大神----JS 闭包是什么
大名鼎鼎的闭包!这一题终于来了,面试必问. 请用自己的话简述 什么是「闭包」. 「闭包」的作用是什么. --------------------------------------- 首先来简述什么是 ...
- 转自知乎大神---什么是 JS 原型链?
我们知道 JS 有对象,比如 var obj = { name: 'obj' } 我们可以对 obj 进行一些操作,包括 「读」属性 「新增」属性 「更新」属性 「删除」属性 下面我们主要来看一下「读 ...
- 大神js总结
http://www.cnblogs.com/tylerdonet/p/5543813.html http://www.codesec.net/list/8/
- 项目管理模式:外瀑布内敏捷(有人称为“信封法”)--转自知乎大神:CORNERSTONE
作者:CORNERSTONE 链接:https://www.zhihu.com/question/265968122/answer/878124580 来源:知乎 著作权归作者所有.商业转载请联系作者 ...
- js编程思想:模型进化论--JS 的 new 到底是干什么的?
想象我们在制作一个策略类战争游戏,玩家可以操作一堆士兵攻击敌方. 我们着重来研究一下这个游戏里面的「制造士兵」环节. 一个士兵的在计算机里就是一堆属性,如下图: 一.荒蛮时代:对象是数据的集合 我们只 ...
- JS 的 new 到底是干什么的?
大部分讲 new 的文章会从面向对象的思路讲起,但是我始终认为,在解释一个事物的时候,不应该引入另一个更复杂的事物. 今天我从「省代码」的角度来讲 new. --------------------- ...
- 【转】JS 的 new 到底是干什么的?
原文:https://zhuanlan.zhihu.com/p/23987456?refer=study-fe 大部分讲 new 的文章会从面向对象的思路讲起,但是我始终认为,在解释一个事物的时候,不 ...
- JS高级群的日常!写一个从10到0的倒计时,用console.log打印,不可以用 setInterval!本来说好的研究avalonJS最后演变成了看着大神在那边互相比拼实力。。
JS高级群的日常!写一个从10到0的倒计时,用console.log打印,不可以用 setInterval!本来说好的研究avalonJS最后演变成了看着大神在那边互相比拼实力.. 小森执行一 ...
随机推荐
- Java中isAssignableFrom()方法与instanceof()方法用法
一句话总结: isAssignableFrom()方法是从类继承的角度去判断,instanceof()方法是从实例继承的角度去判断. isAssignableFrom()方法是判断是否为某个类的父类, ...
- Assetbundle管理与加载
最近在做项目优化的时候发现公司的项目用的还是老式的WWW去加载assetbundle资源的形式,而且是通过在两个Update里面分开加载AB和Asset的,这样虽然避免了协程的的使用,但是把一件事分开 ...
- openstack 主机无法ping通instance,无法ssh到instance
https://docs.openstack.org/zh_CN/user-guide/cli-nova-configure-access-security-for-instances.html 好不 ...
- Redis学习笔记之入门基础知识——简介
非关系型数据库,存储的数据类型:字符串(STRING).列表(LIST).集合(SET).散列表(HASH).有序集合(ZSET) 持久化:时间点转储(point-in-time-dump)(快照). ...
- Ubuntu16.04配置TOMCAT8
基于虚拟机Ubuntu16.04配置Tomcat过程 一.安装JDK 首先要确定好要安装的jdk和tomcat版本能对的上,具体如图所示: 版本选择是Jdk1.8,首先上官网http://www.or ...
- WAMP的一些配置修改
一.修改php运行的目录,即www目录 1. 在工具栏里点击 Apache->httpd.conf 2. 找到 DocumentRoot "G:/PHP/wamp/www/" ...
- 个人作业Week2-代码复审
代码复审Check List 概要部分 代码能符合需求和规格说明么? 符合.针对-c和-s可以将正确的结果输出到相应的sudoku.txt,并在规定的时间内求解. 代码设计是否有周全的考虑? 有的.我 ...
- [2017BUAA软工]提问回顾
原博客链接 原问题1:有没有系统的方法来提高一开始的文档的设计后的质量呢 在之前的OO课程上,我已经深刻领会到了设计的重要性,而且在这次的团队开发中,我也是负责从需求分析到代码设计的转换,所以对设计这 ...
- 格式化输出Json对象
1.调用方式: alert(JsonUti.convertToString(jsonObj)); //jsonObj为json对象. 2.格式化输出Json对象方法定义: var JsonUti = ...
- Docker(二十一)-Docker Swarm集群部署
介绍 Swarm 在 Docker 1.12 版本之前属于一个独立的项目,在 Docker 1.12 版本发布之后,该项目合并到了 Docker 中,成为 Docker 的一个子命令.目前,Swarm ...