1. 工厂模式
function createPerson() {
this.name = "xiaohong";
this.getName = function () {
console.log(this.name);
};
}
var person1 = createPerson();
// 优点:简单
// 缺点:对象无法识别,因为所有的实例都指向同一个原型
2. 构造函数
function Person() {
this.name = "xiaohong";
this.getName = function () {
console.log(this.name);
};
}
var person = new Person();
// 优点: 实例可以识别为一个特定的类型
// 缺点: 每次创建实例时,构造函数内的方法都要被创建一次
// 优化
function getName() {
console.log(this.name);
}
function Person(name) {
this.name = name;
this.getName = getName;
}
var person = new Person("xiaoming");
3. 原型模式
function Person() {}
Person.prototype.name = "xiaoming";
Person.prototype.getName = function () {
console.log(this.name);
};
var person = new Person();
// 优点:方法不会重建
// 缺点:所有的属性和方法都共享;不能初始化参数
// 优化1:
function Person() {}
Person.prototype = {
name: "xiaoming",
getName: function () {
console.log(this.name);
},
};
var person = new Person();
// 优点:封装清晰点
// 缺点:重写了原型,丢失了constructor属性
// 优化2:
function Person() {}
Person.prototype = {
constructor: Person,
name: "xiaoming",
getName: function () {
console.log(this.name);
},
};
var person = new Person();
// 优点:实例可以通过实例.prototype.constructor找到构造函数
// 缺点:所有的属性和方法共享;不能初始化参数
4. 组合模式
function Person() {
this.name = "xiaohong";
}
Person.prototype = {
constructor: Person,
getName: function () {
console.log(this.name);
},
};
var person1 = new Person();
// 优点:该共享的共享,该私有的私有,使用最广泛的方式;
// 缺点:希望写在一个地方,即更好的封装性;
5. 动态原型模式
function Person() {
this.name = "xiaohong";
if (typeof this.getName !== "function") {
Person.prototype.getName = function () {
console.log(this.name);
};
}
}
var person = new Person();
注意:使用动态原型模式时,不能用对象字面量重写原型
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("xiaohong");
// console.log(person1.__proto__ === Person.prototype);
var person2 = new Person("xiaoming");
// console.log(person2.__proto__ === Person.prototype);
person1.getName(); // 报错
person2.getName(); // 注释掉上面一个,下面一个个执行
- 注意这个时候,回顾下 apply 的实现步骤,会执行 obj.Person 方法,这个时候就会执行 if 语句里的内容,注意此时实例的原型指向构造函数的 prototype 属性(是字面量覆盖前的prototype),使用字面量方式直接覆盖 Person.prototype,并不会更改实例的原型的值,person1 依然是指向了以前的原型,而不是 覆盖后的Person.prototype。而之前的原型是没有 getName 方法的,所以就报错了。
- 生成person2实例的时候,Person.prototype已经覆盖了原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); // __proto__原型继承
}
}
var person1 = new Person("xiaohong");
// console.log(person1.__proto__ === Person.prototype);
var person2 = new Person("xiaoming");
// console.log(person2.__proto__ === Person.prototype);
person1.getName(); // 报错
person2.getName(); // 注释掉上面一个,下面一个个执行