上一篇文章提到了如果要创建单个对象,可以采用new Object()方法生成对象实例,或者采用字面量方式直接定义对象。那么如果要批量构造多个对象呢?
问题: 如何批量生产对象?
构造三个人物对象,每个都有属性name, age, height,还有方法eating
解决方案一:工厂模式
工厂模式会有一个工厂函数,工厂函数可以产生想要的对象
就像一个工厂,给输入,工厂函数对输入进行加工,输出出来
function createPerson(name, age){
return {
name: name,
age: age,
eating: function() {
console.log(name + ' is eating');
}
}
}
const p1 = createPerson('zs', 12);
const p2 = createPerson('ls', 17);
const p3 = createPerson('ww', 18);
工厂模式的缺点:
- 对象p1,p2,p3没有对应的类型,仅仅是字面量,不成体系(相当于工厂无logo
console.log(p1)
// 实际:{name: 'zs', age: 12, eating:[Function: eating]}
// 理想:Person{name: 'zs', age: 12, eating:[Function: eating]}
解决方案二:构造函数👍
对于JS中的任何一个普通函数,当用new关键字来调用时,它就是构造函数。可见与函数定义无关,与调用方法
有关。在社区中,通常默契地将函数名首字母大写来表示该函数以后希望被作为构造函数来使用
function Person(name, age) {
this.name = name;
this.age = age;
this.eating = function() {
console.log(this.name + ' is eating');
}
}
const p1 = new Person('zs', 12);
const p2 = new Person('ls', 17);
const p3 = new Person('ww', 18);
构造函数构造出的对象带有“logo”
console.log(p1)
//打印结果有类型标识了
Person {
name: 'zs',
age: 12,
eating: [Function: eating],
}
构造函数的原理(new之后发生了什么)
构造函数之所以能构造出对象,其实JS帮助我们做了很多骚操作。你以为new之后直接执行函数体代码,其实并不是,事实比我们看到了多了四步
1 自从用new调用函数后,JS引擎就会在内存中创建一个空对象{}
const newObj = {};
2 该对象内部的[[prototype]]属性会被赋值为函数的prototype对象
newObj.__proto__ = functionName.prototype
3 构造函数内部的this会指向这个新对象
this = newObj
4 从上到下执行函数体(只有这步是我们能直观看到代码的)
5 返回创造出来的对象
举个例子
function Person(name, age) {
this.name = name;
this.age = age;
this.eating = function() {
console.log(this.name + ' is eating');
}
}
const p1 = new Person('zs', 12);
//----------------------------------------------------------------------------
/*实际JS引擎帮助我们实现的操作*/
const newObj = {};
newObj.__proto__ = Person.prototype;
this = newObj;
this.name = name;
this.age = age;
this.eating = function() {
console.log(this.name + ' is eating');
}
return newObj;
构造函数原型上绑定方法(节省空间
采用构造函数的确可以批量创建对象,且对象还都有该构造函数的logo,那么构造函数有什么缺点吗?有的。由于每次函数调用都会创建新的对象,对象中的函数(比如eating)也会创建多份,对于函数而言创建多份没有必要,能不能共用一个函数
呢?
// 在函数原型上添加方法
Person.prototype.eating = function() {
console.log(this.name + ' is eating'); // 函数的this在调用时被绑定,所以还是绑定的是创建的对象
}
将方法转移到构造函数原型上来定义后,对于实例对象p1, p2,依然可以调用eating方法。
调用时p1的eating时,如果p1对象没有该方法,会去p1对象的原型对象p1.__proto_
找,因为在构造p1时,绑定的原型:p1.__proto__ = Person.prototype
,所以可以找到p1.__proto__.eating