JavaScript面向对象编程
JavaScript面向对象编程
创建自定义对象的**最简单方式**就是创建一个Object的实例,然后再为它添加属性和方法。 ```js var person = new Object(); person.name = "iPhone"; person.age = 8; person.job = "mobile phone";
person.sayName = function() {
console.log(this.name);
};
早期的JavaScript开发人员经常使用这个方法创建新对象,后来**对象字面量**成为创建这种对象的首先模式。上面的例子可以写成这样:
```js
var person = {
name : "iPhone";
age : 8;
job : "mobile phone";
sayName : function () {
console.log(this.name);
}
}
虽然 Object构造函数和对象字面量都可以用来创建单个对象,但当使用同一个接口创建很多对象时,会产生大量重复代码。为解决这个问题,大家开始使用工厂模式。
function createPerson (name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function () {
console.log(this.name);
};
return o;
}
var person1 = createPerson("John", 29, "Teacher");
var person2 = createPerson("Amy", 30, "Doctor");
函数 createPerson() 能够根据接受的参数来构建一个包含所有必要信息的 Person 对象。可以无限地调用这个函数,它每次都会返回一个包含三个属性一个方法的对象。工程模式解决了创建对个相似对象的问题,但却没有解决识别对象类型的问题。构造函数模式应运而生。
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
console.log(this.name);
};
}
var person1 = new Person("John", 29, "Teacher");
var person2 = new Person("Amy", 30, "Doctor");
构造函数模式与工厂模式相似,不同的地方在于:
- 没有显式地创建对象;
- 直接将属性和方法赋给 this 对象;
- 没有 return 语句。
还要注意函数名 Person 首字母大写,以便和非构造函数相区分。
要创建 Person 的新实例,必须使用 new 操作符。
在这个例子中, person1 和 person2 分别保存着 Person 的一个不同实例,这两个实例都有一个 constructor(构造函数) 属性,且指向 Person。
console.log(person1.constructor == Person) //true
console.log(person2.constructor == Person) //true
可以使用 instanceof 操作符检测类型
console.log(person1 instanceof Object); //true
console.log(person1 instanceof Person); //true
**原型模式**,我们创建的每个函数都有一个 prototype(原型)属性,这个属性是一个指针,指向一个对象,这个对象的用途就是包含可以由特定类型的所有实例共享的属性和方法。使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。 ```js function Person() { }
Person.prototype.name = "John";
Person.prototype.age = "29";
Person.prototype.job = "Teacher";
Person.prototype.sayName = function() {
console.log(this.name);
}
var person1 = new Person();
person1.sayName(); //"John"
var person2 = new Person();
person2.sayName(); //"John"
console.log(person1.sayName == person2.sayName) //true
在此,我们将 sayName() 方法和所有属性添加到了 Person 的 prototype 属性中,构造函数成了空函数。我们仍然可以通过调用构造函数来创建新对象,而且新对象还会具有相同的属性和方法。
和构造函数不同,新对象的这些属性和方法是由所有实例共享的,即 person1 和 person2 访问的都是同一个 sayName() 函数。
<br>
####组合使用构造函数模式和原型模式
构造函数用于定义实例属性,原型模式用于定义方法和共享的属性。每个实例都会有自己的实例属性的副本,同时又共享着对方法的引用,还支持向构造函数传递参数。
```js
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Sheldon", "Penny"];
}
Person.prototype = {
constructor : Person,
sayName : function() {
console.log(this.name);
}
}
var person1 = new Person("John", 29, "Teacher");
var person2 = new Person("Amy", 30, "Doctor");
person1.friends.push("Leonard");
console.log(person1.friends); // ["Sheldon", "Penny", "Leonard"]
console.log(person2.friends); // ["Sheldon", "Penny"]
console.log(person1.friends === person2.friends); //false
console.log(person1.sayName === person2.sayName); //true
此例中,实例属性在构造函数中定义,而由所有实例共享的属性 constructor 和方法 sayName() 则是在原型中定义的。修改 person1.friends 时,并不会影响到 person2.friends,因为它们引用自不同数组。这种混合模式应用广泛。
参考文档:《JavaScript高级程序设计》