JavaScript创建对象的方法
- 工厂模式
- 构造函数模式
- 原型模式
- 组合使用构造函数模式和原型模式
- 动态原型模式
- ES6的class
工厂模式
用函数来封装以特定接口创建对象
function createPerson(name, age) {
var o = new Object();
o.name = name;
o.age = age;
o.sayName = function() {
console.log(this.name);
}
}
var person1 = createPerson('Kan', 25);
var person2 = createPerson('ManagoKK', 24);
不足: 没有解决对象识别的问题(怎么知道一个对象的类型)
构造函数模式
构造函数实际上会经历的4个步骤:
- 创建一个新对象
- 将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
- 执行构造函数中的代码(为这个新对象添加属性)
- 返回新对象
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
console.log(this.name);
}
}
var person1 = new Person('Kan', 25);
var person2 = new Person('ManagoKK', 24);
person1.constructor == Person; // true
person2.constructor == Person; // true
person1 instanceof Object; // true
person1 instanceof Person; // true
不足: 每个方法都要在每个实例上重新创建一遍, 不同实例上的同名函数是不相等的.
原型模式
创建的每个函数(对象)都有一个prototype属性, 这个属性就是对象实例的原型对象. 使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法.
function Person() {
}
Person.prototype.name = 'Kan';
Person.prototype.age = 25;
Person.prototype.sayName = function() {
console.log(this.name);
}
var person1 = new Person();
person1.sayName(); // Kan
var person2= new Person();
person2.sayName(); // Kan
person1.sayName == person2.sayName; // true
不足: 其所有属性都被很多实例共享, 包括所有引用类型, 一定其中一个实例修改了原型的引用类型, 就会在其他实例中反映出来, 所以很少单独使用原型模式.
组合使用构造函数模式和原型模式
创建自定义类型的最常见方式, 就是组合使用构造函数模式与原型模式. 构造函数模式用于定义实例属性, 而原型模式用于定义方法和共享的属性.
function Person(name, age) {
this.name = name;
this.age = age;
this.phones = ['iPhone6'];
}
Person.prototype = {
constructor: Person,
sayName: function() {
console.log(this.name);
}
}
var person1 = new Person("Kan", 25);
var person2 = new Person("MangoKK", 24);
person2.phones.push('iPhone8');
person1.phones; // iPhone6
person2.phones; // iPhone6, iPhone8
person1.phones === person2.phones; // false
person1.sayName === person2.sayName; // true
是es6之前使用最为广泛的创建自定义类型的方法
动态原型模式
把所有信息都封装在了构造函数中, 而通过在构造函数中初始化原型, 又保持了同时使用构造函数的原型的优点
function Person(name, age) {
this.name = name;
this.age = age;
// 这段代码只会在初次调用构造函数时才会执行
if(typeof this.sayName != "fucntion") {
Person.prototype.sayName = fucntion() {
console.log(this.name);
};
}
}
var person1 = new Person("Kan", 25);
person1.sayName(); // Kan
- ps: 使用动态原型模式时, 不能使用对象字面量重写原型. 如果在已经创建了实例的情况下重写原型, 那么就会切断现有实例与新原型之间的联系.
ES6的class
其实ES6的class只是组合使用构造函数模式和原型模式的语法糖
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
this.phones = ['iPhone6'];
}
sayName() {
console.log(this.name);
}
}