对象创建(Object Creation)
尽管使用Object构造函数或者对象字面量可以很方便的创建单个的对象,但是这也有一个明显的缺点:基于相同的接口创建多个对象时,存在大量的代码冗余。
1. 工厂模式(The Factory Pattern)
使用工厂模式创建特定接口的对象的例子:
function createPerson(name, age, job) {
let o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function() {
console.log(this.name);
};
return o;
}
let person1 = createPerson("Nicholas", 29, "Software Engineer");
let person2 = createPerson("Greg", 27, "Doctor");
2. Function构造函数模式(The Function Constructor Patter)
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() {
console.log(this.name);
};
}
let person1 = new Person("Nicholas", 29, "Software Engineer");
let person2 = new Person("Greg", 27, "Doctor");
person1.sayName(); // Nicholas
person2.sayName(); // Greg
与前面的createPerson()函数相比,Person()函数不同之处有:
- 没有显式的创建对象;
- properties和methods直接被赋给了this对象;
- 没有return语句。
按照惯例,constructor函数总是以大写字母开头,非constructor函数以小写字母开头。
以这种方式创建实例时,会执行以下流程: - 在内存中创建一个新的object;
- 将新object的[[Prototype]]指针赋给constructor的prototype属性;
- 将constructor的this指针赋给新object,因此this指向了新object;
- 如果constructor返回了non-null的object,则返回该object;否则返回刚刚创建的object。
Constructors as Functions
constructor functions和其他functions之间没有语法的区别,使用new操作符调用的函数就可以视作constructor 函数。举例:
// use as a constructor
let person = new Person("Nicholas", 29, "Software Engineer");
person.sayName(); // "Nicholas"
// call as a function
Person("Greg", 27, "Doctor"); // adds to window
window.sayName(); // "Greg"
// call in the scope of another object
let o = new Object();
Person.call(o, "Kristen", 25, "Nurse");
o.sayName(); // "Kristen"
constructor pattern的问题
使用Constructor的主要问题是:
每一个实例都会创建一个单独的Function实例,而这些Function实例是在做同一件事情。
如前面的例子中,person1和person2都有一个sayName()方法,但是他们不是同一个Function实例。
console.log(person1.sayName == person2.sayName); // false
因此可以把Function的定义移到constructor的外面。
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName;
}
function sayName() {
console.log(this.name);
}
let person1 = new Person("Nicholas", 29, "Software Engineer");
let person2 = new Person("Greg", 27, "Doctor");
person1.sayName(); // Nicholas
person2.sayName(); // Greg
Prototype模式(The Prototype Pattern)
使用prototype的好处是该prototype所有的properties和methods可以在所有的对象实例之间共享。
Prototypes是如何工作的?
无论何时,只要一个函数被创建,它的prototype属性也会被创建。
默认情况下,所有的prototypes会自动获取一个constructor属性指向construct函数。
每当调用constructor来创建一个实例时,该实例拥有一个指向constructor的prototype的内部指针,称之为[[Prototype]]。并没有一个标准的方式来访问[[Prototype]],但是Firefox, Safari和Chrome都支持__proto__属性:指向constructor函数的prototype。
需要重点理解的是,是instance和constructor的prototype之间存在直接的关联,而不是instance和constructor之间。
- 由相同的constructor创建的两个instances共享同一个prototype对象;
console.log(person1.__proto__ === Person.prototype); // true
conosle.log(person1.__proto__.constructor === Person); // true
console.log(person1.__proto__ === person2.__proto__); // true
网友评论