JS:new

前提

本文不从面向对象的角度来讨论new命令,而是以’省代码’的角度来看new。

模拟造士兵

如果我们要造一堆士兵,每个士兵有生命值、编号、攻击力和攻击行为。这些特性在计算机里就是一堆属性,有些属性是士兵私有的(生命值和编号),有些属性是每个士兵都共有的(攻击力和攻击行为)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var container = []
var soldier
soldier.prototype = {
attackValue: 10,
attack: function(){/*攻击行为*/}
}
for(var i =0 ; i<100 ; i++){
soldier = {
id: i,
HP: 100
}
}
//_proto_不是标准属性,实际中不能这么写
soldier._proto_ = soldier.prototype
container.push(soldier)

上面代码造了100个士兵在容器里,把士兵私有的属性单独进行添加,而共有的属性就放在原型里。然而创建士兵的代码分散在两个地方,很不优雅,可以用一个函数把这两部分联系起来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var container = []
function soldier(id){
//创建一个临时对象
var temporary = {}
temporary.id = id
temporary.HP = 100
temporary._proto_ = soldier.prototype
return temporary
}
soldier.prototype = {
attackValue: 10,
attack: function(){}
}
for( var i = 0 ; i<100; i++){
container.push(soldier(i))
}

new的出现

上面代码还得声明一个临时对象,同时还要返回这个临时对象,于是JS之父发明了new关键字,让你少写几行代码,改进后的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
var container = []
function Soldier(id){
this.id = id
this.HP = 100
}
Soldier.prototype = {
attackValue: 10.
attack: function(){}
}
for(var i = 0 ; i<100 ; i++){
container.push(new Soldier(i))
}

通过上面两个代码的对比,new的作用帮你省了几行代码。new帮你创建了一个临时对象,且临时对象的原型指向构造函数的原型。同时返回这个临时对象(相当于执行了该构造函数)。Soldier里的this指的是那个临时对象。

constructor属性

在使用new创建临时对象时,该构造函数的原型里会有一个constructor属性,这个属性用来记录该对象是由哪个函数创建来的。在重新对这个构造函数的原型赋值时,要注意这个属性会被覆盖掉,需要手动添加。

1与new Number(1)的区别

虽然二者的值都为1,但前者属于基本类型,其内存在Stack区,而后者属于复杂类型,是个对象,其内存在Heap区。通过new会执行这个构造函数,并返回一个实例对象。后者的内存图如下所示: