使用 Object 构造函数或对象字面量可以方便地创建对象,但这些方式也有明显不足:创建具
有同样接口的多个对象需要重复编写很多代码。
工厂模式
用方法接收参数,并返回一个对象
function createCar(n, p, like) {
let o = new Object()
o.name = n
o.price = p
o.isLike = like
o.say = function () {
console.log(`${this.name}${this.price}${this.isLike}`);
}
return o
}
const carOfByd = createCar('byd', '20W', 'yes')
const carOfWww = createCar('Www', '20W', 'no')
console.log('carOfByd :>> ', carOfByd);
// {name: "byd", price: "20W", isLike: "yes", say: ƒ}
console.log('carOfWww :>> ', carOfWww);
// {name: "Www", price: "20W", isLike: "no", say: ƒ}
// 解决了创建多个对象的问题,但没有解决对象标识问题(新创的对象是什么类型的)
// intanceof 来确定对象的类型;
console.log('carOfByd instanceof Object :>> ', carOfByd instanceof Object);
// true
console.log('carOfByd instanceof createCar :>> ', carOfByd instanceof createCar);
// false
工厂模式解决了创建多个类似实例的问题。但是创建的实例是没有特定对象标识的
问
题
:
对
象
标
识
的
用
处
是
什
么
?
\color{red}问题:对象标识的用处是什么?
问题:对象标识的用处是什么?
构造函数模式
使用构造函数传递参数,将接收参数挂载到this上,是用new操作符创建实例对象
function CreateCar(c,w,p){
this.color = c,
this.weight = w,
this.price = p,
this.say = function(){
console.log(`这个车是${c},重${w},价值${p}`);
}
}
const byd = new CreateCar('红色的','2T','20W')
const www = new CreateCar('黑色的','1.6T','15W')
console.log('byd :>> ', byd);
// CreateCar {color: "红色的",price: "20W",say: ƒ (),weight: "2T"}
console.log('www :>> ', www);
// CreateCar {color: "黑色的",price: "15W",say: ƒ (),weight: "2T"}
console.log('byd instanceof CreateCar :>> ', byd instanceof CreateCar); // true
console.log('byd instanceof Object :>> ', byd instanceof Object); // true
console.log('www instanceof CreateCar :>> ', www instanceof CreateCar); // true
console.log('www instanceof Object :>> ', www instanceof Object); // true
以上代码使用构造函数创建的实例对象,都有一个特定的类型“CreateCar”;是有CreateCar构造函数生成的。解决了工厂函数不能区分新创建对象类型的问题
缺点:
- 构造函数定义的方法在每个实例上都会创建一遍, 造成不必要的内存浪费(有一个公共方法,所有实例使用即可)
注意:new操作符在执行构造函数时的过程?
3. 在内存中创建一个新的对象
4. 将新对象的**[[prototype]]** 赋值为构造函数的prototype属性
5. 将新对象的this赋值为构造函数的this
6. 执行构造函数内部代码(给新对象添加属性和方法)
7. 如果构造函数返回非空对象,则返回改对象;否则,返回刚创建的新对象
原型模式
每一个函数都会创建一个prototype(原型)对象。这个对象包含由特定引用类型的实例共享的属性和方法。使用原型对象的好处是,在它上面定义的属性和方法可以被对象实例共享。
// 构造函数
function Person () {}
// 原型上添加属性和方法
Person.prototype.name = "zs"
Person.prototype.age = 18
Person.prototype.lesson = ['js','css','html']
Person.prototype.say = function(){
console.log(`我是${this.name},今年${this.age}`);
}
// new操作构造函数实例化的时候,构造函数的括号不是必须的
const p1 = new Person
const p2 = new Person()
console.log('p1 :>> ', p1); // Person{}
console.log('p2 :>> ', p2); // Person{}
console.log('p1.name :>> ', p1.name); // 'zs'
console.log('p2.name :>> ', p2.name); // 'zs'
p1.name = 'ls'
p1.say() // 我是ls,今年18
p2.say() // 我是zs,今年18
console.log('p1.__proto__.name :>> ', p1.__proto__.name); // 'zs'
console.log('p2.__proto__.name :>> ', p2.__proto__.name); // 'zs'
p1.lesson?.push('vue')
console.log('p1.lesson :>> ', p1.lesson); //["js", "css", "html", "vue"]
console.log('p2.lesson :>> ', p2.lesson); //["js", "css", "html", "vue"]
// 原型的属性和方法共享给实例,但是如果在实例中重写同名属性是可以遮蔽原型中的属性(原型链查找)
使用原型创建的对象实例,会将原型中的属性和方法共享给实例对象