//javaScript创建对象的几种模式特点
/*
//1 工厂模式
function createPerson(name,age,job)
{
var o=new Object();
o.name=name;
o.age=age;
o.job=function()
{
alert(name);
}
}
createPerson("Tom",18,"Teachaer");
createPerson("Jack",20,"Student");
//特点:优点:创建了一个共享的方法 和三个各自的属性
//缺点:我们无法知道它们所属的类型 它们都是Object
//如果没有这个缺点 我想用这个模式是最好的
// 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("Tom",18,"Teachaer");
var Person2=new Person("Jack",20,"Student");
// 优点:现在可以知道类型了 Person
// 缺点:创建了三个属性 和三个方法 因为方法也是对象 这里并不共享
//补充:函数既可以当成构造函数也可以当成普通函数
// 如果这里当普通函数这里就是定义windows的属性 因为this指向windows
//但是,这个函数是可以修改的 思路是把函数放在外面,这样就能共享了
//个人觉得带来的问题是用的只是windows的方法 而不是本对象的方法
//如下:
function Person(name,age,job)
{
this.name=name;
this.age=age;
this.job=job;
this.sayName=sayName;//等价于window.sayName
}
function sayName()
{
alert(this.name);
}
var Person1=new Person("Tom",18,"Teachaer");
var Person2=new Person("Jack",20,"Student");
//但是问题又来了 这个sayName好像在windows下的对象都可以调用
//本来想本类对象自己共享,现在成了大家共享,毫无封装性可言了.
//3 原型模式
//我们创建的每个函数都有一个prototype(原型属性) 这个属性是一个指针,指向一个对象
//而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法
//如果按照字面意思来理解,那么prototype就是通过构造函数而创建的那个对象实例的原型对象。
//使用原型对象的好处是可以让所有实例共享它包含的属性和方法
//其实就是一个对象 有函数和属性 我们让某个构造方法创建的对象都指向这个对象
//相当于一个人为一类人服务
//如下
function Person()
{
}
Person.prototype.name="Nicolas";
Person.prototype.age=29;
Person.prototype.job="Software Engineer";
Person.prototype.sayName=function()
{
alert(this.name);
};
var Person1=new Person();
alert(Person.prototype.age);
//看起来我们只是定义了原型的属性和方法(而且看起来还是共享的)
// 并没有定义对象的方法和属性,那它是怎么调用的?
//那就必须知道什么是原型对象
//1)理解原型对象
/*只要创建新函数,就会根据一组特定的规则为该函数创建一个prototype属性
这个属性指向函数的原型对象,所有的原型对象都会自动获得一个constructor
属性,这个属性包含一个指向prototype属性所在函数的指针,前面的例子中Prototype就是指向Person这个函数
而且这个原型对象既然是对象 也继承了Object里面定义的方法
当调用构造函数创建一个新实例,该实例内部将包含一个指针,指向构造函数的原型对象
这里的意思是构造函数有一个prototype属性指向原型对象 并且实例也有一个属性指向原型对象 叫做Prototype
虽然没有标准的形式访问Prototype(实例的Prototype) 但是很多浏览器都支持一个属性 _proto_
这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间
这样一来,我们就建立了实例与原型对象之间的联系,本实例没有的就去找原型对象
在js高级程序设计这本书的插图中 很明了的解释
虽然在所有实现中都无法访问到Prototype(这里的意思是说直接访问)
比如person1.Prototype
但可以通过isPrototypeof()方法来确定对象之间
是否存在这种关系
alert(Person.propotype.isPrototypeOf(person1)) //如果你没有创建实例 这个就返回false
ECMAScript 5增加了一个新方法 叫Object.getPropertyOf(),在所有支持的实现中
这个方法返回 Prototype
例如 alert(Object.getPrototypeof(person1)==Person.prototype)
alert(Object.getPrototypeOf(person1).name);
当读取到一个属性或方法时 如果在本实例中没有找到属性或方法 就会去原型对象中查找
我们一般就是在实例中定义属性 而在原型对象中定义方法。\
原型对象中的属性不能重写 如果一个共享的东西 突然变化了 肯定会出问题
如果我们突然不要本类定义的属性 而要访问原型对象的属性 可以通过
delete 对象引用.属性 来完成
使用hasOwnProperty方法可以检测一个属性是存在于实例或者存在于原型中(方法从Object中继承而来)
可以使用in操作符判断属性是否存在于对象或者存在于原型中
alert(属性 in 对象) 如果属性存在于对象 或者原型对象中 就返回true
*/
//更简单的原型语法
/*
function Person()
{
}
Person.prototype=
{
name:"Nicolas",
age:29,
job:"Software Engineer",
sayName:function()
{
alert(this.name);
}
};
Person.prototype.name="Tom";
alert(Person.prototype.name);
*/
/*看起来好像是很清爽
但是这里的constructor指向的是Object 因为我们重写了原型对象
前面提到原型对象的constructor指向的是prototype所在函数的指针
我觉得口诀是这样:在哪里构造原型对象 constructor就指向哪里的构造函数
如果我们觉得这个constructor很重要 可以强制指回去
那么原来的原型对象也就换了(换人服务)
但是共享带来的好处也就是共享带来的坏处 加入有人在原型中修改了属性
而你恰好用得就是使用原型中的属性 那么就引发了问题 所以最好就用方法 不要用属性
*/
/*
//4 组合使用构造函数和原型模式 最常用的模式
//实例负责构建本对象独有属性 原型负责共享属性与方法
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);
}
}
*/
//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);
// }
// }
// }
// function Person()
// {
// }
// Person.prototype.name=18;
// Person.prototype.age=30;
// var person1=new Person();
// alert(person1.name);
// alert(person1.age);
// 寄生构造函数模式
//在前面的几种模式都不适用的情况下,可以使用寄生构造函数模式.
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 person1=new Person(‘tom‘,18,"Software Engineer");
alert(person1 instanceof Object);
/*
构造函数在没有返回值的情况下 默认为返回新对象实例 如果添加一个return语句
可以重写调用构造函数返回的值
*/