1.字面量
直接申明一个对象
let p = {
name:'zb',
age:18,
height:10,
address:'jjj'
eating:function(){
....
},
}
上面的方式在申明对象的时候,有很多冗余的代码,下面我们利用工厂模式来进行改进。
2.工厂模式
工厂模式是在原来的字面量的基础上进行封装,由于函数在new 的过程中是返回一个对象,所以我们在内部申明一个对象的变量,并且返回出去
function createPerson(name,age,height,address) {
// 返回一个对象,那么内部肯定需要一个对象
let p = {}
p.name = name
p.age = age
p.height = height
p.address = address
p.eating = function() {
console.log('...');
}
return p
}
let p1 = new createPerson('zb', 18, 10, 'hhhh')
let p2 = new createPerson('zb1', 18, 10, 'hhhh')
let p3 = new createPerson('zb2', 18, 10, 'hhhh')
但是工厂模式也有缺陷,就是这样创建的p1,p2,p3的对象,获取不到对象最真实的类型。因为对象的类型都是Object类型了,但是从某种角度来说,这些对象应该有一个他们共同的类型。
下面我们来看一下另一种模式:构造函数模式
3.构造函数模式
构造函数也是一个函数,从表现形式来看,和千千万万的普通函数没啥区别;
如果一个函数被new 操作符来调用了,那么这个函数就是构造函数。
function foo(name,age,height){
this.name = name
this.age = age
this.height = height
}
new foo()
此时foo就是构造函数了(必须是通过new操作符来调用才能是构造函数)
那么我们通过new来调用函数与普通函数有什么区别?
new 的时候会执行以下操作:
new的时候执行以下的五步
(1)先创建一个对象,
(2)这个对象内部的prototype赋值为该构造函数的prototype属性
(3)构造函数的内部的this指向创建出来的新对象
(4)执行函数的内部代码
(5)如果构造函数没有返回非空对象,则返回创建出来的新对象
那我们来模拟实现一个new操作符
function _new(fn, ...args) {
//(1)先创建一个对象,
//(2)这个对象内部的prototype赋值为该构造函数的prototype属性
const obj = Object.create(fn.prototype)
//利用apply函数来将this指向obj对象,并且指向函数的内部代码
let res = fn.apply(this, args)
//(5)如果构造函数没有返回非空对象,则返回创建出来的新对象
return typeof res === 'Object' ? Object(res) : obj
}
所以当我们new 的时候,
实例对象的隐式原型会指向构造函数的原型 也就是 f1.proto === foo.prototype 构造函数的缺点:
当创建太多对象的时候,会重复开辟内存空间