工厂模式
function createPerson(name) {
var o = new Object()
o.name = name
o.getName = function() {
console.log(this.name)
}
return o
}
var person1 = new createPerson('zhansan')
缺点:对象无法识别,因为所有的实例都指向一个原型
构造函数模式
function createPerson(name) {
this.name = name
this.getName = function() {
console.log(this.name)
}
}
var person1 = new createPerson('zhansan')
优点:实例可以识别为一个特定的类型
缺点:每次创建实例时,每个方法都要被创建一次
构造函数优化
function createPerson(name) {
this.name = name
this.getName = getName
}
function getName() {
console.log(this)
}
var person1 = new createPerson('zhansan')
优点:解决了每个方法都要被重新创建的问题
缺点:封装性不好
原型模式
function Person(name) {}
Person.prototype.name = 'zhansan'
Person.prototype.getName = function() {
console.log(this.name)
}
var person1 = new Person()
优点:方法不会被重新创建
缺点:所有的方法和属性都共享、不能初始化参数
原型模式优化1
function Person(name) {}
Person.prototype = {
name: 'zhansan',
getName: function() {
console.log(this.name)
}
}
var person1 = new Person()
优点:封装性好一点
缺点:重写了原型,丢失了constructor属性
原型模式优化2
function Person(name) {}
Person.prototype = {
constructor: Person,
name: 'zhansan',
getName: function() {
console.log(this.name)
}
}
var person1 = new Person()
优点:实例可以通过constructor属性找到所属构造函数
缺点:原型模式该有的缺点还是有
组合模式
构造函数模式和原型模式组合使用
function Person(name) {
this.name = name
}
Person.prototype = {
constructor: Person,
getName: function() {
console.log(this.name)
}
}
var person1 = new Person()
优点:该共享的共享,该私有的私有,使用最广泛的方式
缺点:封装性不是很好
动态原型模式
function Person(name) {
this.name = name
if(typeof this.getName != 'function') {
Person.prototype.getName = function() {
console.log(this.name)
}
}
}
var person1 = new Person('zhansan')
注意:使用动态原型模式时,不能使用对象字面量重写原型
function Person(name) {
this.name = name
if(typeof this.getName != 'function') {
Person.prototype = {
constructor: Person,
getName: function() {
console.log(this.name)
}
}
}
}
var person1 = new Person('zhansan')
var person2 = new Person('lisi')
person1.getName() // 报错,并无该方法
person2.getName() // 可以访问到
new的实现步骤:
- 首先新建一个对象
- 然后将对象的原型指向Person.prototype
- 然后Person.apply(obj)改变this指针方向
- 返回这个对象
构造函数的prototype属性指向了实例的原型,使用字面量方式直接覆盖Person.prototype,并不会更改实例的原型的值,person1依然指向以前的Person的原型,而不是Person.prototype。
如果就是想使用字面量的方式写的话,
function Person(name) {
this.name = name
if(typeof this.getName != 'function') {
Person.prototype = {
constructor: Person,
getName: function() {
console.log(this.name)
}
}
return new Person(name)
}
}
var person1 = new Person('zhansan')
var person2 = new Person('lisi')
person1.getName() // zhansan
person2.getName() // lisi
寄生构造函数模式
function Person(name) {
var o = new Object()
o.name = name
o.getName = function() {
console.log(this.name)
}
return o
}
var person1 = new Person('zhansan')
console.log(person1 instanceof Person) // false
console.log(person1 instanceof Object) // true
这种方式可以在特殊的情况下使用,比如我们想创建一个具有额外方法的特殊数组,但是又不想直接修改Array构造函数
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')
var colors2 = SpecialArray('red2', 'blue2', 'green2')
console.log(colors)
console.log(colors.toPipedString()) // red|blue|green
console.log(colors2)
console.log(colors2.toPipedString()) // red2|blue2|green2
稳妥构造函数模式
function person(name) {
var o = new Object()
o.getName = function() {
console.log(name)
}
return o
}
var person1 = person('zhansan')
person1.getName() // zhansan
person1.name = 'daisy'
person1.getName() // zhansan
console.log(person1.name) // 'daisy'
所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this的对象
与寄生构造函数模式有两点不同:
- 新创建的实例方法不引用this
- 不使用new操作符调用构造函数
稳妥对象最适合在一些安全的环境中。
稳妥构造函数模式也跟工厂模式一样,无法识别对象所属类型