废话不多说,先撸代码。
var newFunc = function ( func ){
//1.新建一个空对象,并将 构造函数的原型对象赋给这个空对象
var obj = Object.creat(func.prototype);
//2.执行构造函数,相应参数被传入,并将this的上下文指向新创建的对象obj
var ret = func.call(obj);
//3.如果构造函数返回了对象,就舍弃之前创建的对象obj,newObj = ret
if(typeof ret === 'object') return ret;
//4.反之,newObj = obj
else return obj;
}
var foo = function(name){
this.name = name || 'lalaBao';
}
var newObj = newFunc(foo);
造函数其实和普通函数本质上并无区别,唯一的区别有两个:
1、函数首字母大写,这个区别只是约定俗成的,便于区分。你实在要小写定义构造函数也完全没问题,所以这个区别可以忽略。
2、构造函数的调用需要用new操作符,而普通函数的调用又分很多种,但是都不会用到new操作符。
所以,构造函数和普通函数的区别就在这个new操作符里,现在让我们来好好研究一下这个new操作符。
用new操作符创建对象时发生的事情:
(1)创建一个新对象;
(2)将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
(3)执行构造函数中的代码(为这个新对象添加属性和方法);
(4)返回新对象;
构建函数的问题:
每个方法都要在每个实例上重新创建一遍, 虽然构造函数解决了判断实例类型的问题,但是,说到底,还是一个对象的复制过程。跟工厂模式颇有相似之处。也就是说,当我们声明了100个person对象,那么就有100个getName方法被重新生成。
这里的每一个sayName方法实现的功能其实是一模一样的,但是由于分别属于不同的实例,就不得不一直不停的为sayName分配空间。这就是工厂模式存在的第二个麻烦。
显然这是不合理的。我们期望的是,既然都是实现同一个功能,那么能不能就让每一个实例对象都访问同一个方法?
var p1 = new Person('Ness', 20);
var p2 = new Person('Ness1', 21);
console.log(p1.sayName == p2.sayName); //false