菜单

JS 的 new 到底是干什么的?

2018年12月20日 - JavaScript

JS 的 new 到底是怎么的?

2017/04/10 · JavaScript
· 4 评论 ·
new

初稿出处: 方应杭   

绝大多数讲 new
的稿子会打面向对象的思绪讲起,可是自己始终认为,在表达一个东西之时光,不应该引入另一个双重复杂的事物。

今自己自从「省代码」的角度来讲 new。

—————————

想像大家以打造一个策略类战争游戏,玩家可以操作一积士兵攻击对方。

咱俩紧要来探究一下这么些游戏里的「创设士兵」环节。

一个小将的当微机里便是同一堆放属性,如下图:

图片 1

咱无非待那样就足以打造一个战士:

JavaScript

var 士兵 = { ID: 1, // 用于区分每个士兵 兵种:”美利哥大兵”, 攻击力:5,
生命值:42, 行走:function(){ /*举手投足俩步的代码*/}, 奔跑:function(){
/*狂奔的代码*/ }, 死亡:function(){ /*Go die*/ }, 攻击:function(){
/*贴他熊脸*/ }, 防御:function(){ /*护脸*/ } } 兵营.制造(士兵)

1
2
3
4
5
6
7
8
9
10
11
12
13
var 士兵 = {
  ID: 1, // 用于区分每个士兵
  兵种:"美国大兵",
  攻击力:5,
  生命值:42,
  行走:function(){ /*走俩步的代码*/},
  奔跑:function(){ /*狂奔的代码*/  },
  死亡:function(){ /*Go die*/    },
  攻击:function(){ /*糊他熊脸*/   },
  防御:function(){ /*护脸*/       }
}
 
兵营.制造(士兵)

C++ new到底new什么,到底new

9: int *obj = new int(6);
00F714CE push 4 //压栈
00F714D0 call operator new (0F711EAh) //调用new函数返回分配的地址addr --- 0F711EAh是指令 jmp operator new 的地址
00F714D5 add esp,4 //恢复栈
00F714D8 mov dword ptr [ebp-0F8h],eax //把返回的地址addr赋给起始地址为ebp-0F8h的内存空间
00F714DE cmp dword ptr [ebp-0F8h],0 //判断分配是否成功
00F714E5 je main+51h (0F71501h)  //如果不成功跳往0x0F71501h   
00F714E7 mov eax,dword ptr [ebp-0F8h] //起始地址为ebp-0F8h 的内存空间(addr)赋值给eax
00F714ED mov dword ptr [eax],6 //把以起始地址为eax的内存空间(addr)置成6
00F714F3 mov ecx,dword ptr [ebp-0F8h] //起始地址为ebp-0F8h 的内存空间(addr)赋值给ecx
00F714F9 mov dword ptr [ebp-100h],ecx //ecx的值(addr)赋给起始地址为ebp-100h的内存空间
00F714FF jmp main+5Bh (0F7150Bh) //无条件跳转到0x0F7150B
00F71501 mov dword ptr [ebp-100h],0 //起始地址为ebp-100h的内存空间置为0---分配失败的情况
00F7150B mov edx,dword ptr [ebp-100h] //起始地址为ebp-100h的内存空间(addr)赋值给edx
00F71511 mov dword ptr [obj],edx  //把edx的内容(addr)赋值给obj为起始地址的内存空间a
10: delete obj;
00F71514 mov eax,dword ptr [obj]  //把obj为起始地址的内存空间送往eax
00F71517 mov dword ptr [ebp-0ECh],eax //eax送往以ebp-0ECh为起始地址的内存空间
00F7151D mov ecx,dword ptr [ebp-0ECh]  //以ebp-0ECh为起始地址的内存空间送往ecx
00F71523 push ecx //ecx压栈
00F71524 call operator delete (0F710A0h)
00F71529 add esp,4  
11:int *obj2 = new int(7);
与分配obj相同

  

 此时输出*obj,会落“7”。 why? obj本来是乘为分配的地址addr_obj,
删除操作就是去除掉addr_obj中的情,释放addr_obj内存,不过obj本身或赖为其的
当我们叫obj2分配空间时,new函数会回到第一单可用的地点,也即便是刚释放的addr_obj,此时obj如故靠为该地方,所以取上述结果。
这样做即便偶尔会正确,可是后患无穷!!!     addr的经过的地方 eax
-> ptr [ebp-0F8h] -> ecx ->  ptr [ebp-100h] -> edx ->
ptr[obj]   new函数所要召开的 1.
调用对象的构造函数,分配空间,再次回到地址addr 2.
把重临的地方addr赋值给指针对象

http://www.bkjia.com/cjjc/1097797.htmlwww.bkjia.comtruehttp://www.bkjia.com/cjjc/1097797.htmlTechArticleC++ new到底new什么,到底new 9: int *obj = new
int(6);00F714CE push 4 //压栈00F714D0 call operator new (0F711EAh)
//调用new函数重临分配的地址addr — 0F711EAh是指…

注意 constructor 属性

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

JavaScript

士兵.prototype = { constructor: 士兵 }

1
2
3
士兵.prototype = {
  constructor: 士兵
}

倘你还对「士兵.prototype」赋值,那么这一个 constructor
属性就从未有过了,所以您应该如此形容:

JavaScript

士兵.prototype.兵种 = “美利坚同盟国战士” 士兵.prototype.攻击力 = 5
士兵.prototype.行走 = function(){ /*动俩步的代码*/}
士兵.prototype.奔跑 = function(){ /*狂奔的代码*/ } 士兵.prototype.死亡
= function(){ /*Go die*/ } 士兵.prototype.攻击 = function(){
/*贴他熊脸*/ } 士兵.prototype.防御 = function(){ /*护脸*/ }

1
2
3
4
5
6
7
士兵.prototype.兵种 = "美国大兵"
士兵.prototype.攻击力 = 5
士兵.prototype.行走 = function(){ /*走俩步的代码*/}
士兵.prototype.奔跑 = function(){ /*狂奔的代码*/  }
士兵.prototype.死亡 = function(){ /*Go die*/    }
士兵.prototype.攻击 = function(){ /*糊他熊脸*/   }
士兵.prototype.防御 = function(){ /*护脸*/       }

或者您呢得以自己受 constructor 重新赋值:

JavaScript

士兵.prototype = { constructor: 士兵, 兵种:”美利坚同盟国小将”, 攻击力:5,
行走:function(){ /*挪俩步的代码*/}, 奔跑:function(){ /*狂奔的代码*/
}, 死亡:function(){ /*Go die*/ }, 攻击:function(){ /*贴他熊脸*/ },
防御:function(){ /*护脸*/ } }

1
2
3
4
5
6
7
8
9
10
士兵.prototype = {
  constructor: 士兵,
  兵种:"美国大兵",
  攻击力:5,
  行走:function(){ /*走俩步的代码*/},
  奔跑:function(){ /*狂奔的代码*/  },
  死亡:function(){ /*Go die*/    },
  攻击:function(){ /*糊他熊脸*/   },
  防御:function(){ /*护脸*/       }
}

完。

2 赞 6 收藏 4
评论

图片 2

优雅?

有人提议创立一个老将的代码分散于点滴只地点万分不雅观,于是我们之所以一个函数把当下片有交换起:

JavaScript

function 士兵(ID){ var 临时对象 = {} 临时对象.__proto__ = 士兵.原型
临时对象.ID = ID 临时对象.生命值 = 42 return 临时对象 } 士兵.原型 = {
兵种:”美利坚同盟国大兵”, 攻击力:5, 行走:function(){ /*移动俩步的代码*/},
奔跑:function(){ /*狂奔的代码*/ }, 死亡:function(){ /*Go die*/ },
攻击:function(){ /*贴他熊脸*/ }, 防御:function(){ /*护脸*/ } } //
保存也文件:士兵.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function 士兵(ID){
  var 临时对象 = {}
 
  临时对象.__proto__ = 士兵.原型
 
  临时对象.ID = ID
  临时对象.生命值 = 42
  
  return 临时对象
}
 
士兵.原型 = {
  兵种:"美国大兵",
  攻击力:5,
  行走:function(){ /*走俩步的代码*/},
  奔跑:function(){ /*狂奔的代码*/  },
  死亡:function(){ /*Go die*/    },
  攻击:function(){ /*糊他熊脸*/   },
  防御:function(){ /*护脸*/       }
}
 
// 保存为文件:士兵.js

接下来就足以满面春风地引用「士兵」来创建士兵了:

JavaScript

var 士兵们 = [] for(var i=0; i<100; i++){ 士兵们.push(士兵(i)) }
兵营.批量创造(士兵们)

1
2
3
4
5
6
var 士兵们 = []
for(var i=0; i<100; i++){
  士兵们.push(士兵(i))
}
 
兵营.批量制造(士兵们)

做一百单兵卒

若急需创造 100 个战士怎么处置也?

循环 100 次吧:

JavaScript

var 士兵们 = [] var 士兵 for(var i=0; i<100; i++){ 士兵 = { ID: i,
// ID 不可知重复 兵种:”美利坚合众国士兵”, 攻击力:5, 生命值:42, 行走:function(){
/*挪动俩步的代码*/}, 奔跑:function(){ /*狂奔的代码*/ },
死亡:function(){ /*Go die*/ }, 攻击:function(){ /*贴他熊脸*/ },
防御:function(){ /*护脸*/ } } 士兵们.push(士兵) }
兵营.批量创建(士兵们)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var 士兵们 = []
var 士兵
for(var i=0; i<100; i++){
  士兵 = {
    ID: i, // ID 不能重复
    兵种:"美国大兵",
    攻击力:5,
    生命值:42,
    行走:function(){ /*走俩步的代码*/},
    奔跑:function(){ /*狂奔的代码*/  },
    死亡:function(){ /*Go die*/    },
    攻击:function(){ /*糊他熊脸*/   },
    防御:function(){ /*护脸*/       }
  }
  士兵们.push(士兵)
}
 
兵营.批量制造(士兵们)

哟呀好简单。

JS 之大的关注

JS 之大创造了 new 关键字,可以于咱少写几实施代码:

图片 3

如若你在战士前边使用 new 关键字,那么得掉做四件工作:

  1. 不要创制临时对象,因为 new 会帮你开(你下「this」就得拜到现对象);
  2. 毫不绑定原型,因为 new 会帮您做(new
    为了领悟原型在啊,所以指定原型的名字啊 prototype);
  3. 不要 return 临时对象,因为 new 会帮您开;
  4. 甭让原型想名字了,因为 new 指定名字啊 prototype。

质疑

点的代码有一个问题:浪费了诸多内存。

  1. 行进、奔跑、死亡、攻击、防御这三个动作对每个士兵其实是一律的,只待各自引用和一个函数就得了,没必要更创立100 个步履、100个奔跑……
  2. 那么些精兵的兵种和攻击力都是千篇一律的,没必要创造 100 次。
  3. 单发 ID 和生命值需要创造 100 次,因为每个士兵发出和好之 ID 和生命值。

立即无异于不行我们用 new 来描写

JavaScript

function 士兵(ID){ this.ID = ID this.生命值 = 42 } 士兵.prototype = {
兵种:”美利坚同盟国兵”, 攻击力:5, 行走:function(){ /*移步俩步的代码*/},
奔跑:function(){ /*狂奔的代码*/ }, 死亡:function(){ /*Go die*/ },
攻击:function(){ /*贴他熊脸*/ }, 防御:function(){ /*护脸*/ } } //
保存也文件:士兵.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function 士兵(ID){
  this.ID = ID
  this.生命值 = 42
}
 
士兵.prototype = {
  兵种:"美国大兵",
  攻击力:5,
  行走:function(){ /*走俩步的代码*/},
  奔跑:function(){ /*狂奔的代码*/  },
  死亡:function(){ /*Go die*/    },
  攻击:function(){ /*糊他熊脸*/   },
  防御:function(){ /*护脸*/       }
}
 
// 保存为文件:士兵.js

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

JavaScript

var 士兵们 = [] for(var i=0; i<100; i++){ 士兵们.push(new 士兵(i))
} 兵营.批量创设(士兵们)

1
2
3
4
5
6
var 士兵们 = []
for(var i=0; i<100; i++){
  士兵们.push(new 士兵(i))
}
 
兵营.批量制造(士兵们)

new
的功能,就是望那么几执行代码。(也即使是所谓的语法糖)

改进

扣押罢我们的专辑往日著作(JS
原型链
)的同学肯定领会,用原型链可以化解还创设的题目:我们事先创设一个「士兵原型」,然后为「士兵」的
__proto__ 指向「士兵原型」

JavaScript

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(士兵) } 兵营.批量制造(士兵们)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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(士兵)
}
 
兵营.批量制造(士兵们)

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图