JS之对象创建模式
- 工厂模式
创建多个单体对象的时候会产生大量重复的代码发明一种接口函数
function createPerson(name, age, job ) {
var o = new Object();
o.name = name
o.age = age
o.job = job
o.sayName = function () {
console.log(this.name)
}
return o
}
var person1 = createPerson("pxj", 18, "ps")
person1.sayName() // pxj
var person2 = createPerson("xwh", 19, "tesxt")
person2.sayName() // xwh
- 构造函数模式
创建多个单体对象的时候会产生大量重复的代码发明一种接口函数
function Person(name, age, job ) {
this.name = name
this.age = age
this.job = job
this.sayName = function () {
console.log(this.name)
}
}
// 以上写法当创建多个对象的时候都会调用一下sayName,同时做了相同的一件事,修改如下
function Person(name, age, job ) {
this.name = name
this.age = age
this.job = job
this.sayName = sayName
}
// 将sayName设置为全局变量,但是尴尬的是只能被某个对象调用,而且如果多个方法的时候还要创建多个全局方法,不推荐啊
function sayName () {
console.log(this.name) //
}
var person1 = new Person("pxj", 18, "ps")
var person2 = new Person("xwh", 19, "test")
// 使用constructor 来识别是否是对象
console.log(person1.constructor === Person, person2.constructor === Person) // true true
// 使用instanceof 来检测是否是对象(推荐)
console.log(person1 instanceof Object) //true
和工厂模式不相同之处
1、没有显示创建对象
2、直接将属性和方法赋给了this对象
3、没有return语句
使用构造函数创建对象,必须使用new操作符, 创建时会经历四个步骤
1、创建一个对象
2、将构造函数的作用域赋给新对象(this指向这个新对象)
3、指向构造函数中的代码(为新对象添加方法)
4、返回新对象
构造函数模式的缺点
每个方法都要在每个实例上重新创建一遍
- 原型模式
完美解决了对象同时做一件事,并且设置为全局函数还只能自己对象调用的尴尬,每创建一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所以实例共享的属性和方法,使用原型对象的好处是可以让所有对象实例共享他所包含的属性和方法
function Person() {
}
Person.prototype.name = "PHJ"
Person.prototype.age = 19
Person.prototype.sayName = function () {
console.log(this.name)
}
var person1 = new Person()
person1.sayName() // PHJ
var person2 = new Person()
person2.sayName() // PHJ
console.log(person1.sayName() == person2.sayName()) // true
console.log(person2)
// 当为对象添加一个属性时,这个属性就会屏蔽原型对象上保存的属性,换句话说,添加2这个属性只会阻碍我们访问原型中的那个属性,但不会修改那个属性的
// 可以使用delete操作符来完全删除实例属性
// 不能重写原型中的值,但是创建的属性会屏蔽原型原先的值(同名的情况下)
// 实例上的属性方法和原型同级,优先查询实例上的属性和方法,如果找不到,则会往原型上找
person1.name = "ljs"
// 实例上已经创建了name属性了,就不在需要搜索原型了
person1.sayName() // ljs --- 来自实例
person2.sayName() // PHJ --- 来自原型
// 删除实例上的属性
delete person1.name
console.log(person1.name) // PHJ 之前添加已被删除、
// 使用hasOwnProperty()方法可以检测一个属性是存在实例中还是原型中(方法是从Object继承下来的)
person1.name = "ljs"
console.log(person1.hasOwnProperty("name")) // true(存在实例中)
delete person1.name // 删除其实例上的属性
console.log(person1.hasOwnProperty("name")) // false(存在原型中)
// sort() 按照数值大小进行排序
var arry = [5,1,3,4]
console.log(arry.sort()) // 1, 3, 4, 5
// 在字符串原型上添加方法,所有字符串都可用(不推荐)
String.prototype.startsWith = function (text) {
return this.indexOf(text) == 0
}
var S = "Hello World!"
console.log(S.startsWith("Hello"))
原型模式的弊端:修改原型上的一个方法会影响另外一个
// function Persons() {
// }
// Persons.prototype = {
// constructor: Person,
// name: "pxj",
// age: 66,
// job: "cxk",
// friends: ["ljs", "xwh"],
// sayName: function () {
// console.log(this.name)
// }
// }
// var persons1 = new Persons()
// persons1.friends.push("lht") // "ljs", "xwh", "lht"
// console.log(persons1.friends)
// var persons2 = new Persons()
// // 并无修改persons2上的friends属性
// console.log(persons2.friends) // "ljs", "xwh", "lht"
// console.log(persons1.friends === persons2.friends) // true
总结:构造函数用于定义实例属性,而原型模式用于定义方法和共享属性,设计模式之构造函数模式和原型模式混合体,完美解决了修改原型上的方法会影响另一个
// 构造模式定义法
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.friend = ["Sl", "CT"]
}
// 原型模式定义法
Person.prototype = {
constructor : Person,
sayName : function () {
console.log(this.name);
}
}
// 结合使用
var person1 = new Person('pyj', 18, "checker")
var person2 = new Person('xwh', 18, 'danker')
person1.friend.push('gui');
console.log(person1.friend, person2.friend)// 已在friend数组中添加了gui,然而person2却还是之前没改的
console.log(person1.friend === person2.friend) // false
console.log(person1.sayName === person2.sayName) // true
- 动态原型模式
他把所有信息都封装在构造函数中,而通过在够着函数中初始化原型,又保持了同时使用构造函数和原型的优点
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
// 重写原型
if(typeof this.sayName != "function") {
Person.prototype.sayName = function () {
alert(this.name)
};
}
}
var friend = new Person('jx', 19, 'software');
friend.sayName() // jx
- 寄生构造函数模式
可以在创建额外方法下使用
1.返回的对象与构造函数或者构造函数的原型属性之间没有关系,
2.不能依赖instanceof来判断类型
建议:可以使用其他模式就不要用这个模式了
function SpecialArray() {
// 创建数组
var values = new Array()
// 添加值
values.push.apply(values, arguments);
// 添加方法
values.toPipedString = function () {
return this.join('|');
}
return values
}
var colors = new SpecialArray('red', 'blue', 'green');
console.log(colors.toPipedString());// red/ blue/ green
6.稳妥构造函数模式
该方法与寄生设计模式类似,但有两点不同
1.新创建对象的实例方法不引用this
2.是不使用new操作符调用构造函数
function Person(name, age, job) {
// 创建要返回的对象
var o = new Object();
// 可以在这里定义私有变量和函数
o.sayName = function () {
console.log(name)
};
return o;
}
// 除了使用sayName()方法外,没有其他办法访问name的值
var friend = Person('ox', 19, 'sada');
friend.sayName(); // ox