工厂函数是任何不使用class
或constructor
的函数并且会return一个对象。因此,工厂函数不使用new
关键字。工厂函数在JavaScript中一直很有吸引力,因为它们提供了轻松生成对象实例的能力,而无需深入到类和new关键字的复杂性中。
JavaScript提供了一种非常方便的对象字面语法来创建对象。
const user = {
userName: 'Frank',
avatar: "Frank.jpg"
};
看起来和JSON非常类似。(JavaScript’s Object literal Notation)其实JSON是基于javascript的对象字面量表示来的。:
的左边是属性名,:
的右边是属性值。
可以通过两种方式来访问对象的属性:dot notation和 computed property。
// dot notation
console.log(user.userName);
// computed property
const key = 'avatar';
console.log(user[key]);
如果同一作用域内的变量名称与对象内的属性名称相同,则可以省略对象字面量中创建的冒号和值。
const userName = 'yudao';
const avatar = 'yudao.jpg';
const user = {
userName,
avatar
};
console.log(user);// {userName: 'yudao', avatar: 'yudao.jpg'}
对象字面量支持一种更简洁的method语法:
const userName = 'yudao';
const avatar = 'yudao.jpg';
const user = {
userName,
avatar,
setUserName(username){
this.userName = username;
return this;
}
};
console.log(user.setUserName('Frank').userName);// Frank
如果想使用dot notation方式(.call()
)来调用函数,那么该函数必须是对象的一个属性。第7行的this
代表调用setUserName
的对象(本例中的user),通过setUserName的参数,改变了对象的userName的值;第8行将原对象返回。
对象字面量
方式创建的对象并不灵活,不易扩展。若是想使用对象字面量
创建多个对象,则需要结合factory function
。object literal + factory function
=> factory pattern
。接下来,将前面示例中的单个user对象的生产方式变成工厂模式批量生产。Let’s go!
假设我们的应用程序需要很多用户,简单定义四个属性firstName、lastName、email、fullName。
// 定义“用户”工厂
const createUser = ({ firstName, lastName, email }) => ({
firstName,
lastName,
email,
fullName() {
return `${this.firstName} ${this.lastName}`;
},
});
接下来,可以通过createUser
函数非常方便地批量“生产”用户了。
const createUser = ({ firstName, lastName, email }) => ({
firstName,
lastName,
email,
fullName() {
return `${this.firstName} ${this.lastName}`;
}
});
const zhangsan = createUser({
firstName: "三",
lastName: "张",
email: "sanzhang@yudao.com"
});
const lisi = createUser({
firstName: "四",
lastName: "李",
email: "lisi@yudao.com"
});
console.log(zhangsan);// {firstName: '三', lastName: '张', email: 'sanzhang@yudao.com', fullName: ?}
console.log(lisi);//{firstName: '四', lastName: '李', email: 'lisi@yudao.com', fullName: ?}
关于通过箭头函数创建一个字面量对象,有个小细节需要说明下:
// arrow funciton
/* 箭头函数有个隐含的返回特性:如果函数体只是一个简单的表达式,则可以省略return关键字 */
const ex0 = () => 'foo';
console.log(ex0()); // 该函数返回一个字符串'foo'
const ex1 = () => { foo: 'bar' };
console.log(ex1()); // undefined
// 为什么是undefined呢?
// 当返回一个对象字面量时,需要注意 在函数体外加一对括号
const ex2 = () => ({ foo: 'bar' });
console.log(ex2()); // {foo:'bar'}
当我们必须创建多个共享相同属性的较小对象时,工厂模式非常有用。工厂函数也可以根据当前环境或用户特定的配置轻松返回自定义对象。
In JavaScript, the factory pattern isn’t much more than a function that returns an object without using the new
keyword. ES6 arrow functions allow us to create small factory functions that implicitly return an object each time.
在JavaScript中,工厂模式只不过是一个可以返回对象而不使用“new”关键字的函数。ES6箭头函数允许我们创建每次隐式返回一个对象的小工厂函数。
However, in many cases it may be more memory efficient to create new instances instead of new objects each time.
然而,在许多情况下,每次创建新实例可能比创建新对象更节省内存。
class User {
constructor(firstName, lastName, email) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
fullName() {
return `${this.firstName} ${this.lastName}`;
}
}
const user1 = new User({
firstName: "John",
lastName: "Doe",
email: "john@doe.com",
});
const user2 = new User({
firstName: "Jane",
lastName: "Doe",
email: "jane@doe.com",
});