JavaScript创建对象的几种方式
工厂模式
function createObj (name, age, sex) {
const obj = new Object()
obj.name = name
obj.age = age
obj.sex = sex
obj.sayName = function () {
console.log(this.name)
}
return obj
}
let obj1 = createObj('小明', 15, '男')
let obj2 = createObj('小红', 16, '女')
console.log(obj1, obj2)
优点:解决了创建多个相似对象代码复用的问题
缺点:使用工厂模式创建的对象,没有解决对象识别的问题,也就是怎样知道这个对象的类型是什么
构造函数
function createObj (name, age, sex) {
this.name = name
this.age = age
this.sex = sex
this.sayName = function () {
console.log(this.name)
}
}
let obj1 = new createObj('小明', 15, '男')
let obj2 = new createObj('小红', 16, '女')
console.log(obj1,obj2)
当我们使用构造函数实例化一个对象的时候,对象中会包含一个__proto__
属性指向构造函数原型对象,而原型对象中包含一个constructor
属性指向构造函数。因此在实例对象中我们可以通过原型链来访问到constructor属性,从而判断对象的类型。
优点:解决了工厂模式中对象类型无法识别的问题,并且创建自定义构造函数意味着将来可以将他的实例标识为一种特定的类型。
缺点:在使用构造函数创建对象时,每个方法都会在实例对象中重新创建一遍,会造成内存的浪费
原型模式
function Obj() {
}
Obj.prototype.name = 'objName'
Obj.prototype.age = 15
Obj.prototype.sex = '女'
Obj.prototype.sayName = function () {
console.log(this.name)
}
let obj1 = new Obj()
console.log(obj1)
obj1.sayName()
与构造函数模式不同的是,原型对象上的属性方法,是所有实例共享的
优点:解决了构造函数模式中多个实例对象中多次定义同一方法的问题
缺点:所有实例对象都是相同的默认属性值,在实例化的时候不能动态指定
使用构造函数和原型模式
function Obj(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
}
Obj.prototype = {
constructor: Obj,
sayName: function () {
console.log(this.name)
}
}
let obj1 = new Obj('小明', 15, '男')
let obj2 = new Obj('小红', 16, '女')
console.log(obj1, obj2)
obj1.sayName()
优点:每个实例创建的时候都支持向构造函数传参,每个实例都拥有自己的一份实例属性的副本,又共享着原型上的属性和方法。
缺点:使用了两种模式,封装不是很好
动态原型模式
function Obj(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
if (typeof this.sayName !== 'function') {
Obj.prototype.sayName = function () {
console.log(this.name)
}
}
}
let obj1 = new Obj('小李', '22', '男')
obj1.sayName()
优点:解决了构造函数加原型对象模式的封装问题