原文:https://zhuanlan.zhihu.com/p/23987456?refer=study-fe函数
大部分讲 new 的文章会从面向对象的思路讲起,可是我始终认为,在解释一个事物的时候,不该该引入另外一个更复杂的事物。this
今天我从「省代码」的角度来说 new。spa
---------------------------prototype
想象咱们在制做一个策略类战争游戏,玩家能够操做一堆士兵攻击敌方。3d
咱们着重来研究一下这个游戏里面的「制造士兵」环节。code
一个士兵的在计算机里就是一堆属性,以下图:orm
咱们只须要这样就能够制造一个士兵:对象
var 士兵 = { ID: 1, // 用于区分每一个士兵 兵种:"美国大兵", 攻击力:5, 生命值:42, 行走:function(){ /*走俩步的代码*/}, 奔跑:function(){ /*狂奔的代码*/ }, 死亡:function(){ /*Go die*/ }, 攻击:function(){ /*糊他熊脸*/ }, 防护:function(){ /*护脸*/ } } 兵营.制造(士兵)
若是须要制造 100 个士兵怎么办呢?blog
循环 100 次吧:游戏
var 士兵们 = [] var 士兵 for(var i=0; i<100; i++){ 士兵 = { ID: i, // ID 不能重复 兵种:"美国大兵", 攻击力:5, 生命值:42, 行走:function(){ /*走俩步的代码*/}, 奔跑:function(){ /*狂奔的代码*/ }, 死亡:function(){ /*Go die*/ }, 攻击:function(){ /*糊他熊脸*/ }, 防护:function(){ /*护脸*/ } } 士兵们.push(士兵) } 兵营.批量制造(士兵们)
哎呀好简单。
上面的代码存在一个问题:浪费了不少内存。
看过咱们的专栏之前文章(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 之父建立了 new 关键字,可让咱们少写几行代码:
只要你在士兵前面使用 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 的做用,就是省那么几行代码。(也就是所谓的语法糖)
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(){ /*护脸*/ } }
完。