1. 工厂模式
用接口来封装以特定接口来创建对象的细节
// 缺点:对象无法识别,因为所有的实例都指向一个原型
var log = console.log.bind(console)
function creatPerson(name) {
var o = new Object()
o.name = name
o.getName = function () {
console.log(this.name);
};
return o
}
var person = creatPerson('haha')
var person1 = creatPerson('haha')
log(1111, person.__proto__) //都是指向Object
log(2222, person1.__proto__) //都是指向Object
2.构造函数模式
// 优点:实例可以识别为一个特定的类型
// 缺点:每次创建实例时,每个方法都要被创建一次
var log = console.log.bind(console)
function Person(name) {
this.name = name
this.getName = function() {
log(this.name)
}
}
var person2 = new Person('meimei')
var person3 = new Person('meimei1')
log(person2.name) //meimei
//这里指向的是Person,但是每次创建实例,函数也会被创建一次
log(3333, person2.__proto__.constructor.name)
log(person2.getName == person3.getName) //false
2.1优化构造函数模式
优点:解决了每个方法都要被重新创建的问题
缺点:这叫啥封装……
var log = console.log.bind(console)
function Person1(name) {
this.name = name;
this.getName = getName;
}
// 放在外面调用,可以避免上面的重复创建问题
function getName() {
console.log(this.name);
}
var person4 = new Person1('kevin');
var person5 = new Person1('kevin1');
log(4444, person4.__proto__.constructor.name) //指向"Person1"
log(person4.getName == person5.getName) //true
3.原型模式
// 优点:方法不会重新创建
// 缺点:1. 所有的属性和方法都共享 2. 不能初始化参数
var log = console.log.bind(console)
function Person2() {}
// 无法初始化这个name值
Person2.prototype.name = 'hah'
Person2.prototype.getName = function(){
console.log(this.name);
}
var person6 = new Person2(); //无法改变name 的值
log(5555, person6.__proto__.constructor.name) //指向"Person2"
3.1优化原型模式
// 优点:封装性好了一点, 实例可以通过constructor属性找到所属构造函数
// 缺点:重写了原型, 原型模式该有的缺点还是有
var log = console.log.bind(console)
function Person3() {}
Person3.prototype = {
coustructor: Person3,
name: 'hah',
getName: function(){
console.log(this.name);
}
}
var person7 = new Person3(); //无法改变name 的值
log(6666, person7.__proto__.coustructor.name) //指向"Person3"
4.组合使用构造函数模式和原型模式
// 优点:该共享的共享,该私有的私有,使用最广泛的方式
// 缺点:有的人就是希望全部都写在一起,即更好的封装性
var log = console.log.bind(console)
function Person4(name) {
this.name = name
}
Person4.prototype.getName = function(){
console.log(this.name);
}
var person8 = new Person4('haha');
log(7777, person8.__proto__.constructor.name) //指向"Person4"
4.1动态原型模式
var log = console.log.bind(console)
function Person5(name) {
this.name = name
if(typeof this.getName != 'function') {
// 注意:使用动态原型模式时,不能用对象字面量重写原型
Person5.prototype.getName = function() {
log(this.name)
}
}
}
var person9 = new Person5('meimei')
log(8888, person9.__proto__.constructor.name) //指向"Person5"
5.1寄生构造函数模式
// 寄生-构造函数-模式,也就是说寄生在构造函数的一种方法。
// 缺点:创建的实例使用 instanceof 都无法指向构造函数
// 特殊情况下可使用,如果想创建一个具有额外方法的特殊数组,但又不想直接修改Array构造函数
var log = console.log.bind(console)
function Person6(name) {
var o = new Object()
o.name = name
o.getName = function() {
log(this.name)
}
return o
}
var person10 = new Person6('meimei') //比工厂模式多了一个new,实际上2者的结果是一样的
console.log(person10 instanceof Person) // false
console.log(person10 instanceof Object) // true
log(9999, person10.__proto__.constructor.name) //指向Object
5.2稳妥构造函数模式
// 与寄生构造函数模式有两点不同:
// 1)新创建的实例方法不引用 this
// 2)不使用 new 操作符调用构造函数
// 稳妥对象最适合在一些安全的环境中。
// 稳妥构造函数模式也跟工厂模式一样,无法识别对象所属类型。
var log = console.log.bind(console)
function Person7(name){
var o = new Object();
o.sayName = function(){
console.log(name);
};
return o;
}
var person11 = Person7('kevin');
person11.sayName(); // kevin
person11.name = "daisy";
person11.sayName(); // kevin
console.log(person11.name); // daisy
log(1000, person11.__proto__.constructor.name) //指向Object
详见:查看效果