面向对象的程序设计
理解对象
属性类型
-
创建自定义对象的最简单方式就是创建一个Object的实例,然后再为它添加属性和方法
var person=new Object(); person.name="Nicholas"; person.age=20; person.job="Software Engineer"; person.sayName=function(){ alert(this.name) }
-
对象字面量称为创建这种对象的首选方式
var person={ name:"Nicholas", age:20, job:"Software Engineer", sayName:function(){ alert(this.name); } };
-
两种属性
-
数据属性,可以读取和写入值,有四个描述其行为的特性
- [[Configurable]]表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,特性默认值为true
- [[Enumerable]]表示能否通过for-in循环返回属性,特性默认值为true
- [[Writable]]表示能否修改属性的值,特性默认值为true
- [[Value]]包含这个属性的数据值,读取属性值的时候,从这个位置读,写入属性值的时候,把新值保存在这个位置,特性默认值是undefined
-
要修改属性默认的特性,使用Object.definePropery()方法,这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。
var person={}; Object.definePropery(person,"name",{ writable:false, value:"Nicholas" }); alert(person.name);//"Nicholas" person.name="Greg"; alert(person.name);//"Nicholas"
-
访问器属性,包含一对getter和setter函数。在读取访问器属性的时候,会调用getter函数,这个函数负责返回有效的值。在写入访问器属性的时候,会调用setter函数并传入新值,这个函数负责决定如何处理数据。
- [[Configurable]]表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性,特性默认值为true
- [[Enumerable]]表示能否通过for-in循环返回属性,特性默认值为true
- [[Get]]在读取属性时调用的函数,默认值为undefined
- [[Set]]在写入属性时调用的函数,默认值为undefined
- 访问器属性不能直接定义,必须使用Object.defineProperty()来定义
-
定义多个属性
-
Object.defineProperties()方法可以通过描述符一次定义多个属性,这个方法接收两个对象参数,一个对象是要添加和修改其属性的对象,第二个对象的属性与第一个对象中要添加或修改的属性一一对应
var book = {}; Object.defineProperties(book, { _year: { value: 2004 }, edition: { value: 1 }, year: { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } } });
读取属性的特性
-
Object.getOwnPropertyDescription()方法,可以取得给定属性的描述符,这个方法接收两个参数,属性所在的对象和要读取其描述符的属性名称
var book = {}; Object.defineProperties(book, { _year: { value: 2004 }, edition: { value: 1 }, year: { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } } }); var descriptor = Object.getOwnPropertyDescriptor(book, "_year"); alert(descriptor.value); //2004 alert(descriptor.configurable); //false alert(typeof descriptor.get); //"undefined" var descriptor = Object.getOwnPropertyDescriptor(book, "year"); alert(descriptor.value); //undefined alert(descriptor.enumerable); //false alert(typeof descriptor.get); //"function"
创建对象
工厂模式
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("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");
构造函数模式
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
-
只要通过new操作符来调用,那它就可以作为构造函数
// 当作构造函数使用 var person = new Person("Nicholas", 29, "Software Engineer"); person.sayName(); //"Nicholas" // 作为普通函数调用 Person("Greg", 27, "Doctor"); // 添加到 window window.sayName(); //"Greg" // 在另一个对象的作用域中调用 var o = new Object(); Person.call(o, "Kristen", 25, "Nurse"); o.sayName(); //"Kristen"
原型模式
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"Nicholas"
var person2 = new Person();
person2.sayName(); //"Nicholas"
alert(person1.sayName == person2.sayName); //true
- 无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象,默认情况下,所有的原型对象都会自动获得一个constructor属性,这个属性包含一个指向prototype属性所在函数的指针。
组合使用构造函数模式和原型模式
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructor : Person,
sayName : function(){
alert(this.name);
}
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Count,Van"
alert(person2.friends); //"Shelby,Count"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true
动态原型模式
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("Nicholas", 29, "Software Engineer");
friend.sayName();
寄生构造函数模式
function Person(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 friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName(); //"Nicholas"
稳妥构造函数模式
function Person(name, age, job){
//创建要返回的对象
var o = new Object();
//可以在这里定义私有变量和函数
//添加方法
o.sayName = function(){
alert(name);
};
//返回对象
return o;
}
继承
原型链
-
可以通过两种方式来确定原型和实例之间的关系,第一种方式是使用instanceof操作符,只要这个操作符来测试实例与原型链中出现过的构造函数,结果就会返回true
alert(instance instanceof Object); //true alert(instance instanceof SuperType); //true alert(instance instanceof SubType); //true
-
第二种方式是使用isPrototypeOf()方法,只要是原型链中出现过的原型,都可以说是原型链所派生的实例的原型,因此isPrototypeOf()方法也会返回true
alert(Object.prototype.isPrototypeOf(instance)); //true alert(SuperType.prototype.isPrototypeOf(instance)); //true alert(SubType.prototype.isPrototypeOf(instance)); //true
借用构造函数
function SuperType(){
this.colors = ["red", "blue", "green"];
}
function SubType(){
// 继承了 SuperType
SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green"
-
对于原型链而言,借用构造函数有一个很大的优势,即可以在子类型构造函数中向超类型构造函数传递参数
function SuperType(name){ this.name = name; } function SubType(){ //继承了 SuperType,同时还传递了参数 SuperType.call(this, "Nicholas"); //实例属性 this.age = 29; } var instance = new SubType(); alert(instance.name); //"Nicholas"; alert(instance.age); //29
组合继承
-
指的是将原型链和借用构造函数的技术组合到一块
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ //继承属性 SuperType.call(this, name); this.age = age; } //继承方法 SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ alert(this.age); }; var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" instance1.sayName(); //"Nicholas"; instance1.sayAge(); //29 var instance2 = new SubType("Greg", 27); alert(instance2.colors); //"red,blue,green" instance2.sayName(); //"Greg"; instance2.sayAge(); //27
原型式继承
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
寄生式继承
-
思路和构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,函数在内部以某种方式来增强对象
function createAnother(original){ var clone = object(original); //通过调用函数创建一个新对象 clone.sayHi = function(){ //以某种方式来增强这个对象 alert("hi"); }; return clone; //返回这个对象 } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = createAnother(person); anotherPerson.sayHi(); //"hi"
寄生组合式继承
-
无论什么情况下都会调用两次超类型构造函数,一次是在创建子类型原型的时候,另一次实在子类型构造函数内部
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); // 第二次调用 SuperType() this.age = age; } SubType.prototype = new SuperType(); // 第一次调用 SuperType() SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ alert(this.age); };
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。