一、分别是哪四种模式?
- 工厂模式
- 构造函数模式
- 原型模式
- 组合模式
二、知识前提
1、什么是工厂模式?
工厂模式是一种创建型模式,简单来说,工厂模式就是创建对象的一种方式
2、工厂模式有什么用?
作用:创建对象;降低代码冗余度。
类似我们使用函数的原理,传递不同的参数,就会调用同一函数,产生不同的值
应用场景:当你想要批量生产同种类的对象的时候;比如,你想生成一个班级的40个学生,每个学生都有姓名、年龄等特征。这时候你创建一个“工厂”,把信息丢到工厂里,工厂就给你造一个人出来,非常方便。
3、其它几个模式有什么用?
其它模式都是为了更快、简单的创建对象而研发出的设计模式,类似于一种历史的发展趋势、组合模式则是历史发展的最终产物,完美的解决了其它模式遇到的问题
三、详情
一、工厂模式
例子:
function createPerson(name, age) { // Object构造函数 var person = new Object() person.name = name person.age = age // 函数是引用数据类型,所以每个实例调研时,都会重新占据一个堆区 person.sayName = function () { console.log(this.name); } return person } var obj1 = createPerson('zhangsan', 17) var obj2 = createPerson('lisi', 18) console.log(obj1, obj2); console.log(obj1 === obj2); //false /* 优点:只要我们往工厂函数里面塞参数,工厂函数就会像生产产品一样造个人出来。 缺点:类型模糊 是大的Object 不知道是具体的哪个对象 */
优点:只要我们往工厂函数里面塞参数,工厂函数就会像生产产品一样造个人出来
缺点:类型模糊 不知道是哪个具体对象
解决办法:使用自定义构造函数
二、自定义构造函数模式
例子:
function Person(name, age, gender) { this.name = name this.age = age this.gender = gender this.sayName = function () { console.log(this.name); } } // 1、new-说明Person当作一个自定义构造函数 this存在于Person中,被p1调用,所有this指向p1 同理p2 var p1 = new Person('zhangsan', 18, 'male') var p2 = new Person('lisi', 16, 'female') console.log(p1); //p1对象 console.log(p2); //p2对象
执行结果:
优点:批量创建对象 解决了工厂模式的对象类型模糊问题
缺点:方法冗余-不同的实例调用时,每实例对象中的方法会分别占据堆内存
产生缺点的原因:
解决办法:将对象中的方法写在全局
额外知识:
- 自定义构造函数模式和工厂模式最大的区别?
- 没有显式地创建对象。
- 属性和方法直接赋值给了 this。
- 没有 return。
instanceof——判断一个对象是某个对象的实例
将对象中的方法写在全局
例子:
// 修改后 function Person(name, age, gender) { this.name = name this.age = age this.gender = gender // 通过赋值调用即可sayName函数 this.sayName = sayName } /* 放在全局,全局也会影响作用域,类似Animal构造函数也可以使用sayName(), 但我们本意是 只有Person构造函数才可以调用 */ function sayName() { console.log(this.name); } var person1 = new Person("zhangsan", 29, "male"); var person2 = new Person("lisi", 27, "female"); person1.sayName(); // zhangsan person2.sayName(); // lisi console.log(person1.sayName === person2.sayName); //true
优点:解决了在自定义函数中,每次调用都产生不同的function实例
缺点:方法冗余、影响全局作用域
解决办法:使用原型模式
三、原型模式
例子:
解决影响全局作用域的原理:
因为每个构造函数都会创建一个prototype属性(原型属性)具体可以参考对象中的原型解释。因此在构造函数给实例对象赋值,也可以给他们的原型赋值
不同的实例对象,会继承对应原型对象中的方法。因此解决了 全局作用域的问题
优点:解决了代码冗余(一个实例一个方法)、影响全局作用域
额外知识:
如何改变实例对象的值,而不继承?
如何判断该属性是自己的属性(继承也返回false)
- 如何判断一个属性是否属于 原型属性
三、更简单的原型模式
例子:
优点:页面看起来更整洁
缺点1:从constructor指向发生改变
解决方式:使用defineProperty修改指向
缺点2:当实例对象p1修改了某个值,实例p2也获得了修改后的值
例子:
四、组合模式
由以上可以看出来,构造函数模式更利于存储私有属性,原型模式更利于存储共享属性
例子:
优点:解决了以上代码冗余、原型模式的问题