//创建对象
//工厂模式
//解决了创建多个相似对象的问题,但没有解决对象识别的问题
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,"SW");
//构造函数模式
//与工厂模式的不同:没有显示地创造对象,直接将属性和方法付给了this对象,没有return语句
//任何函数,只要通过new操作符来调用,那它就可以作为构造函数
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,"SW");
//可以使用call()或apply()在某个特殊对象的作用域中调用Person()函数
var o = new Object();
Person.call(o, "Kristen", 25, "Nurse");
o.sayName(); //"Kristen"
//问题:每个方法都要在实例上重新创建一遍,不同实例上的同名函数是不相等的
//改进:
function Pers (name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName - sayName;
}
function sayName(){
alert(this.name);
}
var person1 = new Person("Nicholas",29,"SW");
//新问题:在全局作用域中定义的函数实际上只能被某个对象调用,这让全局作用域有点名不副实
//如果对象需要定义很多方法,那么就要定义很多个全局函数
//原型模式
//创建的每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型
//的所有实例共享的属性和方法
//好处:可以让所有对象实例共享它所包含的属性和方法,不必在构造函数中定义对象的实例信息,而可以直接添加到原型对象中
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "SW";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"Nicholas"
//在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的
//指针
//Person.prototype.constructor指向Person
//Object.getPrototypeOf()方法返回[[Prototype]]的值
//虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值,只能屏蔽原型中的值,使用delete操作符
//可以完全删除属性,从而能够重新访问原型中的属性
//hasOwnProperty()(从object中继承而来)只在给定属性存在于实例中时才返回true
//同时使用hasOwnProperty()方法和in操作符,可以确定该属性是存在于对象还是原型中
function hasPrototypeProperty(object, name){
return !object.hasOwnProperty(name) && (name in object);
}
//hasPrototypeProperty返回true说明name属性在原型中,false说明name属性在实例中
//Object.keys()方法取得对象上所有可枚举的实例属性,接受一个对象作为参数,返回一个包含所有可枚举属性的字符串数组
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "SW";
Person.prototype.sayName = function(){
alert(this.name);
};
var keys = Object.keys(Person.prototype);
alert(keys); //"name,age,job,sayName"
var p1 = new Person();
p1.name = "Rob";
p1.age = 31;
var p1keys = Object.keys(p1);
alert(p1keys); //"name,age"
//得到所有实例属性,不论是否可以枚举,使用Object.getOwnPropertyNames()方法
var keys = Object.getOwnPropertyNames(Person.prototype);
alert(keys); //”constructor,name,age,job,sayName”
//更简单的原型语法,但constructor属性不再指向Person了,而是指向Object构造函数
function Person(){
}
Person.prototype = {
name : "Nicholas",
age : 29,
job : "SW",
sayName : function(){
alert(this.name);
}
};
//可以通过设定”constructor : Person”来指定constructor属性,但其{[Enumerable]}特性会被设置为true,可以通过如下方式来避免
Object.defineProperty(Person.prototype, "constructor",{
enumerable : false,
value : Person
});
//实例中的指针仅指向原型,而不指向构造函数
//重写原型对象切断了现有原型与任何之前已经存在的对象实例之间的联系
//原型模式的缺点:首先,它省略了为构造函数传递初始化参数这一环节,结果所有的实例在默认情况下都将取得相同的属性值
//最大的问题是由其共享的本性所导致的,对于引用类型的属性,一个更改会导致所有的都改变
//组合使用构造函数模式和原型模式
//构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性
function Pers (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,"SW");
var person2 = new Person("Greg",27,"Doctor");
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Court,Van"
alert(person2.friends); //"Shelby,Court"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true
//动态原型模型
//if语句检查的可以是初始化之后应该存在的任何属性或方法,只要检查其中一个即可
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, "SW");
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, "SW"); //此行不同于工厂模式
friend.sayName();
//特殊情况下用来为对象创建构造函数
function SpecialArray(){
//创建数组
var values = new Array();
//添加值
values.push.apply(values,arguments);
//添加方法
values.toPipedString = function(){
return this.join("|");
};
//返回数组
return values;
}
var colors = new SpecialArray("red","blue","green");
alert(colors.toPipedString();)
//寄生构造函数模式返回的对象与构造函数或者与构造函数的原型属性之间没有关系
//稳妥构造函数模式
//所谓稳妥对象,指的是没有公共属性,其方法也不引用this的对象,在禁用this和new的安全的环境中
//稳妥构造函数与寄生构造函数类似,但又亮点不同:
//一是新创建对象的实例方法不引用this
//二是不适用new操作符调用构造函数
function Person(name, age, job){
//创建要返回的对象
var o = new Object();
//可以在这里定义私有变量和函数
//添加方法
o.sayName = function(){
alert(name);
};
//返回对象
return o;
}
var friend = Person("Nicholas",29,"SW");
friend.sayName(); //"Nicholas"
//继承
//原型链继承
//ECMAScript只支持实现继承
//将原型链作为实现继承的主要方法,基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
}
function SubType(){
this.subproperty = false;
}
//继承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSuperValue = function(){
return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); //true
//通过instanceos操作符和isPrototypeOf()方法来确定原型与实例的关系
//给原型添加方法的代码一定要放在替换原型的语句之后
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
}
function SubType(){
this.subproperty = false;
}
//继承了SuperType
SubType.prototype = new SuperType();
//添加新方法
SubType.prototype.getSubValue = function(){
return this.subproperty;
};
//重写超类型中的方法
SubType.prototype.getSuperValue = function(){
return false;
};
var instance = new SubType();
alert(instance.getSuperValue()); //false
//在通过原型链实现继承时,不能使用对象字面量创建原型方法
//原型链最主要的问题来自包含引用类型的值的原型
//第二个问题是在创建子类型的实例时,不能向超类型的构造函数中传递参数
//借用构造函数
//基本思想是在子类型构造函数的内部调用超类型构造函数
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
//原型式继承
function object(o){
function F(){};
F.prototype = o;
return new F();
}
var person = {
name : "Nicholas",
friends : ["Shelby","Court","Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends) //"Shelby,Court,Van,Rob,Barbie"
//Object.create()方法规范了原型式继承,接收两个参数:一个用作新对象原型的对象;一个为新对象定义额外属性的对象
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 inheritPrototype(subType,superType){
var prototype = Object(superType.prototype); //创建对象
prototype.constructor = subType; //增强对象
subType.prototype = prototype; //指定对象
}
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;
}
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge = function(){
alert(this.age);
};