对象实例化是一条必经之路,不然对象 怎么出生,难道他们是从石头缝里蹦出来的吗?
而且它们又不能像现实生物一样papapa…
每种编程语言都有自己实例化对象的方式,js也不例外,基本有下面几种方式。
- Object.create(null | object | obj.prototype),它的参数可以直接为一个对象,也可以是原型对象,也可以为空。
- 字面量 就是 var obj = { prop:’’, … method:function(){},… }
- new关键字,通过new关键配合构造函数
还有工厂模式等,都是大同小异,其实严格来讲,js创建对象的方式就是第一种方式今天的重点不在这里,今天我们要说说new这个关键字。
创建对象是使用new关键字到底干了个什么事呢?这是一个问题
直接上代码:
function ARobot(){
this.num = 1;
this.say = function(){
console.log("我是A类机器人");
}
}
function BRobot(){
this.num2 = 2;
this.say2 = function(){
console.log("我是B类机器人")
}
}
BRobot.prototype = new ARobot();
BRobot.prototype.num = 3;
BRobot.prototype.say = function(){
console.log("我是C类机器人");
}
var obj = new BRobot();
console.log(obj.num);
obj.say();
如果你知道答案,那基本上可以不用看了。
如果不知道,那还是看看吧
答案:
不绕弯了,直接说原理吧; 当代码执行到 new BRobot()时,发生了几件事:
1. var obj = Object.create(BRobot.prototype);
2.将构造函数内部的this也指向obj 如果BRobot()有参数,传入参数,构造函数执行。
3. 如果构造函数返回了一个对象,那么new出来的结果就是这个对象。如果构造函数没有返回值,或者返回了一个非对象的值,那么new的结果就是obj对象。通常来说构造函数没有返回值,除非是要覆盖当前正在创建的对象。
OK,来分析分析上面的代码吧。
-
首先,我们定义了两个构造函数他们分别负责制造A类机器人和B类机器人,一个ARobot,一个是BRobot,并且它们各自有着各自的属性和方法,睁大眼看仔细,他们属性和方法是不同名的哦。
-
然后,我们在实例化对象之前,先做了些小动作。
来看看这三句:
BRobot.prototype = new ARobot();
BRobot.prototype.num = 3;
BRobot.prototype.say = function(){
console.log(“我是C类机器人”);
}
第一句,用new实例化了一个ARobot()作为BRobot的原型,根据我们之前所说的new所做的事,它将得到一个实例化的ARobot对象,这个对象将替换掉BRobot原来的原型,然后对替换后BRobot的原型修改了num属性和say方法…。 -
最后我们重新生产(new)了一个BRobot,然后打印了他的num属性,以及执行了say方法。因为在第2步中,B类型的原型已经被修改,而且值得注意的是,B类型之前是没有sum属性的,也没有say方法(我说过的看仔细哦,看清他们的属性名和方法名,是不同的,emmm…坑B)。
这里就考察到this了,我们说过new的第二步就是将构造函数中的this指向当前new的对象,会发生什么事呢,在我们对 对象内部的成员进行修改时,this就是指带当前的对象,那么问题来了…当前obj有num2属性和say2方法吗?看清吧…haha,没有,所以当前的obj会怎么办——顺着自己的原型链向上查找,结果发现原型BRobot.prototype上有,那么就会使用,所以最终结果才会是
好了,我做一次修改,就是将BRobot构造函数的num属性和say方法改成与ARobot相同的名字
function BRobot(){
this.num = 2;
this.say = function(){
console.log("我是B类机器人")
}
}
结果将会是什么呢?
结果:
你会发现即使我们对BRobot的原型做了修改也没改变实例化的结果,为什么呢,这也是this的功劳,因为我们修改后,实例化的obj对象,在new操作的第二步中,构造函数内的this指向obj,构造函数本身是有num属性和say方法的所以从第一步创建的对象,会在第二步中被当前构造函数内的属性和方法重新赋值,而原型链上的属性依然是原型链的,并且也已被修改,但是没什么卵用。就如同泥人,先用一个模子固个大体,不同之处再通过构造函数去完成,完成后的泥人有自己的特征,而模子上也有自己的特征。
可以看到原型已经被修改成了ARobot,并且其内部属性和方法也被修改了。
好了new关键字,就说到这里。
补充:说一说new关键字与字面量声明对象的区别。
先看一个结果:
可以看到两种创建对象方式所耗的时间不相同,而且差别较大。
为什么会这样,
字面量形式创建对象,强调的是创建对象一个可变的哈希映射
而使用new创建对象,是要调用对应的构造函数,其中存在一个过程,即调用对应名称的构造函数,作用域解析,ESC的入栈出栈。并且还有可能存在类型判断,如果有Object的参数存在,会依据参数进行类型判断,然后根据对应类型,委派内部对应的构造函数,去创建对象。