第6章 面向对象的程序设计
6.1 理解对象
**1. 属性类型:**数据属性和访问器属性
2.定义多个属性: object.defineProperties()
3.读取属性的特性:object.getOwnPropertyDescriptor()
6.2 创建对象
1.工厂模式
工厂模式是软件工程领域一种广为人知的设计模式。如下例子所示:
function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o;
}
var person1 = createPerson('zhangsan',29,'software Engineer');
var person2 = createPerson('lisi',26,'teacher');
2.构造函数模式
可以使用构造函数模式将前面的例子重写,如下:
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var person1 =new Person('zhangsan',29,'software Engineer');
var person2 =new Person('lisi',26,'teacher');
不同之处:
- 没有显示的创建对象;
- 直接将属性和方法赋给了this对象;
- 没有return 语句
此外,还应该注意到函数名Person使用的是大写字母P;按照惯例,构造函数始终都是以一个大写字母开头,而非构造函数则应该以一个小写字母开头;
这两个对象都有一个constructor(构造函数)属性,该属性指向person,如下所示:
alert(person1.constructor == Person); //true
alert(person2.constructor == Person); //true
2.1 将构造函数当作函数;
构造函数与其他函数的唯一区别就是在于调用它们的方式不同,,任何函数,只要通过new 操作符来调用,那他就可以作为构造函数;如果没有通过new 操作符调用,则与普通函数没有区别;
例如:
//当作构造函数使用
var person = new Person('zhangsan',29,'software Engineer');
person.sayName(); //'zhangsan'
//作为普通函数
Person('lisi',26,'teacher'); //添加到window
window.sayName(); //'lisi'
//在另外一个对象的作用域中调用
var o = new Object();
Person.call(o, 'zhangshan', 29, 'nurse');
o.sayName(); //'zhangshan'
不用new操作符调用Person(),那么属性和方法都被添加给window对象;
2.2 构造函数的问题
使用构造函数的主要问题就是每个方法否要在每个实例上重新创建一遍。
3.原型模式
创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途就是包含可以由特定类型的所有实例共享的属性和方法。
function Person(){
Person.prototype.name = 'zhangsan';
Person.prototype.age = 29;
Person.prototype.job = "software Engineer";
Person.prototype.syaName = function(){
alert(this.name);
}
}
var person1 = new Person();
person1.sayName(); //‘zhagnsan’
var person2 = new Person();
person2.sayName(); //‘zhagnsan’
alert(person1.sayName == person2.sayName)
与构造函数模式不同的是,新对象的这些属性和方法是由所有实例共享。换句话说,person1和person2访问的都是同一组属性和同一个sayName()函数。
4、组合使用构造函数模式和原型模式
创建自定义类型的最常见方式,就是组合使用构造函数模式和原型模式。,每个实例都会有自己的一份实例属性和副本,但同时又共享着对方法的引用,最大限度地节省了内存。例如
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["zhangsan", "lisi"];
}
Person.prototype = {
constructor: Person,
syaName: function(){
alert(this.name);
}
}
var person1 =new Person('zhangsan',29,'software Engineer');
var person2 =new Person('lisi',26,'teacher');
person1.friends.push("van");
alert(person1.friends); //"zhangshan,lisi,van"
alert(person2.friends); //"zhangshan,lisi"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true
实力属性都是在构造函数中定义的,而由所有实例共享的属性constructor和方法sayName()则是在原型中定义的。而修改person1.friends,并不会影响到person2.friends,因为它们分别引用了不同的数组。
5、动态原型模式
动态原型模式可以通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型。,比如
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
//方法
if (typeof this.sayName != 'function') {
Person.prototype.sayName = function(){
alert(this.name);
}
};
}
var friend = new Person('zhangsan',29,'software Engineer');
friend.sayName();
只在sayName()方法不存在的情况下,才会将它添加到原型中,这段代码只会在初次调用构造函数时才会执行。,要记住,这里对原型所做的修改,能够立即在所有实例中得到反映。
6、寄生构造函数模式
不想写。。。。