编写代码过程中随时有创建对象的需要,不经意间就创建了一个对象。创建对象有很多方式,这里就我目前了解到的方式进行梳理。
先介绍3种基础的方式,并加上工厂模式的改进。后续再就原型、继承等概念进行展开,会有更多创建对象的方式。
一、字面量
字面量是指某种数据的典型的、直观的形式,数组的形式是[],对象的形式是{}。
使用对象字面量创建对象,{}内使用“键:值”的格式,代码如下:
var obj = {
name: 'bencjl',
age: 19,
sayHi: function () {
console.log('hi');
}
}
console.log(obj);
二、内置Object类
Object类是JavaScript内置的类,而且所有对象的最终原型都是Object。
这里先使用构造函数Object()创建了对象,然后再逐个属性赋值。代码如下:
var obj = new Object();
obj.name = 'bencjl';
obj.age = 19;
obj.sayHi = function() {
console.log('hi');
}
console.log(obj);
另外,Object()构造函数还可以接受一个对象作为参数。如果参数是一个对象字面量,写法接近上面字面量创建对象的写法了;如果参数是一个对象的变量名,返回的还是这个变量的引用地址,没有什么意义。
三、构造函数
Object对象是通过Object()构造函数创建的。同样道理,我们也可以自定义构造函数,创建自定义的对象。
function ObjFunc() {
this.name = 'bencjl';
this.age = 19;
this.sayHi = () => {
console.log('hi');
}
}
var obj = new ObjFunc();
console.log(obj);
这里要夹带两个“私货”:
(1) console打印出来,有个标记是ObjFunc,而前面两种方法没有这个标记。这个ObjFunc标记说明这是一个自定义的类(的对象),不是Object类(的对象)。
(2) 前面的代码,sayHi()都是用匿名函数格式function(){},这里sayHi()使用了箭头函数的格式()=>{}。
四、改进:字面量 + 工厂模式
不管是字面量还是内置Object类,前面的写法都只能写一堆代码、创建一个对象。如果需要大量、反复创建对象怎么办?这时就要复用代码,要包装成函数。(构造函数的方式已经是函数的方式了)
这就是工厂模式的一种代码实现,包装成函数之后可以不断调用、批量生产对象。代码如下:
function createObject(name, age, sayHi) {
return {
name,
age,
sayHi
}
}
var obj = createObject('bencjl', 19, () => {
console.log('hi');
});
console.log(obj);
这里又夹带了“私货”:
(1) 函数当然可以传递参数,这里“工厂函数”写成传递参数的形式,调用函数创建对象时才传入自定义的参数。
(2) “工厂函数”返回的对象字面量,没有使用“键:值”格式。因为ES6支持这种简写的形式,只要属性名和赋值变量名字一样就行。这个简写的特性一般用在对象字面量中,其他方式套用不了。这里相当于属性名是“name”、属性值等于变量name,非简写形式就是“name: name”。
五、改进:内置Object类 + 工厂模式
将创建对象的代码包装成函数没有什么复杂的:
function createObject({ sayHi, age = 19, name }) {
var o = new Object();
o['name'] = name;
o['age'] = age;
o['sayHi'] = sayHi;
return o;
}
var obj = createObject({
name: 'bencjl',
sayHi: () => {
console.log();
}
});
console.log(obj);
除了方括号[]访问形式,这里主要夹带的“私货”是解构赋值:
首先这个函数本质上是要接受一个对象作为参数的,而不是具体的name、age作为参数,调用时传递的实参也确实是一个对象。
其次,在参数列表中顺便做了结构赋值,并支持age默认值,不需要再到函数体中用中间变量接收、判断参数默认值。
最后,参数这种写法有什么好处?和第四部分相比,这种写法用属性名来对应匹配、赋值,不需要记住参数的先后顺序。