注释里讲解的十分细致了,这里就不多废话了,直接上代码:
2004){
this._year=value;
this.edition +=value-2004;
}
}
});
book.year=2005;
alert(book.edition);//2
//创建对象
//1、将构造函数当做函数
function Person(name,age,job) {
this.name=name;
this.age=age;
this.job=job;
this.sayName=function(){
alert(this.name);
}
}
//当做构造函数使用
var person=new Person("xulei",23,"software");
person.sayName();
//作为普通函数使用
Person("xulei2","job2");//添加到window中
window.sayName();
//在另一个对象的作用域中调用
var o=new Object();
Person.call(o,"xulei3","job3");
o.sayName();
再来一段:
//1、无论什么时候,只要创建了一个<a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>,就会根据一组特定的规则,为该<a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>创建一个prototype<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>,该<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>指向<a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>的原型对象
//在默认情况下,所有的原型对象都会<a href="/tag/zidong/" target="_blank" class="keywords">自动</a>获得一个constructor(构造<a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>)<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>,这个<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>包含一个指向prototype<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>所在<a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>的指针
//如
function Person(){
}
//Person.prototype.constructor 指向Person
//创建了<a href="/tag/zidingyi/" target="_blank" class="keywords">自定义</a>的构造<a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>之后,其原型对象默认只会取得constructor<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>,至于其他<a href="/tag/fangfa/" target="_blank" class="keywords">方法</a>则都是从Object继承而来
//当<a href="/tag/diaoyong/" target="_blank" class="keywords">调用</a><a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>的创建一个新实例之后,该实例的内部包含一个指针(内部<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>)指向构造<a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>的原型对象
//在Firefox、safari、chrome在每个对象上都<a href="/tag/zhichi/" target="_blank" class="keywords">支持</a>一个<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>_proto_访问
var p1=new Person();
alert(Person.prototype.isPrototypeOf(p1))
alert(Object.getPrototypeOf(p1)==Person.prototype)
//虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。如果我们在实例中<a href="/tag/tianjia/" target="_blank" class="keywords">添加</a>了一个<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>
//而该<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>的<a href="/tag/mingcheng/" target="_blank" class="keywords">名称</a>与原型的中的实例同名,那我们就在实例中创建该<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>,该<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>将会<a href="/tag/pingbi/" target="_blank" class="keywords">屏蔽</a>原型中的那个<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>。eg:
function Person() {
}
Person.prototype.name="amber";
Person.prototype.age=23;
Person.prototype.job="software engineer";
Person.prototype.sayName=function(){
alert(this.name)
}
var person1=new Person();
var person2=new Person();
person1.name="amber.Xu";
alert(person1.name);//amber.xu --来自实例
alert(person2.name);//amber --来自原型
delete person1.name;
alert(person1.name);//amber --来自原型
//使用hasOwnProperty()<a href="/tag/fangfa/" target="_blank" class="keywords">方法</a>可以检测一个<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>是存在于实例中还是存在于原型中,这个<a href="/tag/fangfa/" target="_blank" class="keywords">方法</a>(从Object继承而来)
//只在给定<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>存在于对象实例中时,才会返回true
function Person() {
}
Person.prototype.name="amber";
Person.prototype.age=23;
Person.prototype.job="software engineer";
Person.prototype.sayName=function(){
alert(this.name)
}
var person1=new Person();
var person2=new Person();
alert(person1.hasOwnProperty("name"));//false 来自实例
alert(person2.hasOwnProperty("name"));//false 来自实例
person1.name="amber.xu";
alert(person1.name);
alert(person1.hasOwnProperty("name"));//true 来自实例
delete person1.name;
alert(person1.name);
alert(person1.hasOwnProperty("name"));//false 来自原型
//2、原型与in操作符
//in 有两种使用方式,一个是的单独使用和在for-in 中使用。在单独使用时,in操作符会在对象能够访问给定<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>时返回true
//无论该<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>时来自原型还是实例
function Person() {
}
Person.prototype.name="amber";
Person.prototype.age=23;
Person.prototype.job="software engineer";
Person.prototype.sayName=function(){
alert(this.name)
}
var person1=new Person();
var person2=new Person();
alert("name" in person1);//true 来自原型
alert("name" in person2);//true 来自原型
alert("height" in person1);//false
//这样就可以封装一个<a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>(给定<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>是否是来给定对象的原型)
function hasPrototypeProperty(object,name){
return !object.hasOwnProperty(name) && (name in object);
}
alert("----------------------------------");
alert(hasPrototypeProperty(person1,"name"));//true
person1.name="张三";
alert(hasPrototypeProperty(person1,"name"));//false
//使用for-in 返回的是所有能够通过对象访问、可枚举的<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>,其中既包含原型<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>也包含实例<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>。
//<a href="/tag/pingbi/" target="_blank" class="keywords">屏蔽</a>了原型中不可枚举<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>(将Enumerable<a href="/tag/biaoji/" target="_blank" class="keywords">标记</a>为false的<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>)的实例<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>也会在for-in中返回
//ie早期版本总中有一个bug:<a href="/tag/pingbi/" target="_blank" class="keywords">屏蔽</a>了原型中不可枚举<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>的实例<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>也不会在for-in中返回
//eg:
var o={
toString:function(){
return "my object";
}
};
for(var prop in o){
if(prop=="toString"){
alert("找到了");//在ie早期版本中不会<a href="/tag/xianshi/" target="_blank" class="keywords">显示</a>
}
}
//要取得对象上所有可枚举的<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>,可以使用ECMAScript5的Object.keys()<a href="/tag/fangfa/" target="_blank" class="keywords">方法</a>。接受一个对象作为参数,
//包含所有可枚举<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>的字符串数组
function Person() {
}
Person.prototype.name="amber";
Person.prototype.age=23;
Person.prototype.job="software engineer";
Person.prototype.sayName=function(){
alert(this.name)
}
var person1=new Person();
var person2=new Person();
var keys=Object.keys(Person.prototype);
alert(keys)
person1.name="amber.Xu";
person1.age=23;
var keys=Object.keys(person1);
alert(keys)
alert("-----------------------------------------")
//如果想要得到所有的实例<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>不管他是否可以枚举,都可以使用
alert(Object.getOwnPropertyNames(person1));
alert(Object.getOwnPropertyNames(Person.prototype));
alert("更简单的原型语法-----------------------------------------")
//3、更简单的原型语法
function Person() {
}
Person.prototype={
name:"AMBER",age:23,job:"software",sayName:function(){
alert(this.name)
}
}
//这样写之后constructor<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>不再指向Person<a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>,而是指向Object构造<a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>。
//尽管通过instanceof操作符还能返回正确的结果,但是通过constructor已经无法确定对象的类型了,eg:
var friend=new Person();
alert(friend instanceof Person)//true
alert(friend instanceof Object)//true
alert(friend.constructor==Person);//false
alert(friend.constructor==Object);//true
//如果constructor对你真的很重要,可以向下面一样设置成适当的值
function Person() {
}
Person.prototype={
constructor:Person,name:"AMBER",sayName:function(){
alert(this.name)
}
}
var friend=new Person();
alert("手动设置constructor-----------------------------------------")
alert(friend.constructor==Person);//true
//这种手动的<a href="/tag/tianjia/" target="_blank" class="keywords">添加</a>了constructor会使constructor变成可枚举的元(原生的constructor<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>时不可枚举的)。
//这种情况下就可以使用
Object.defineProperty(Person.prototype,"constructor",{
enumerable:false,value:Person
});
//原型的动态性
var friend=new Person();
Person.prototype.sayHi=function(){
alert("Hi");
}
friend.sayHi();//Hi (正常执行)
//因为实例和原型之间是松散的连接关系,实例与原型之间的连接只不过是一个指针,而非副本
//当我们<a href="/tag/diaoyong/" target="_blank" class="keywords">调用</a>sayHi()<a href="/tag/fangfa/" target="_blank" class="keywords">方法</a>时,首先会在实例中<a href="/tag/sousuo/" target="_blank" class="keywords">搜索</a>名为sayHi的<a href="/tag/fangfa/" target="_blank" class="keywords">方法</a>,在没找到的情况下会<a href="/tag/sousuo/" target="_blank" class="keywords">搜索</a>原型。
//但是,如果是重写整个原型对象,那么情况就不一样了。
//我们知道,<a href="/tag/diaoyong/" target="_blank" class="keywords">调用</a>构造<a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>时会为实例<a href="/tag/tianjia/" target="_blank" class="keywords">添加</a>一个指向最初原型的Prototype指针,而把原型<a href="/tag/xiugai/" target="_blank" class="keywords">修改</a>为另一个对象就等于切断了构造<a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>与最初原型之间的联系。
//请记住:实例中的指针仅指向原型,而不指向构造<a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>。eg:
function A(){}
var a1=new A();
A.prototype={
constructor:A,sayName:function(){
alert(this.name)
}
}
alert("ERROR-------------------------------------");
alert(a1.sayName());
//我们创建了一个A的实例,然后又重写了其原型对象,然后在<a href="/tag/diaoyong/" target="_blank" class="keywords">调用</a>a1.sayName()发生了<a href="/tag/cuowu/" target="_blank" class="keywords">错误</a>,因为a指向的原型中不包含以该名字命名的<a href="/tag/shuxing/" target="_blank" class="keywords">属性</a>/<a href="/tag/fangfa/" target="_blank" class="keywords">方法</a>
//原生对象的原型
//原型模式的重要性不仅体现在创建<a href="/tag/zidingyi/" target="_blank" class="keywords">自定义</a>类型方面。就连所有的原生的引用类型,都是采用这种模式创建的。所有的原生引用类型
//都在其构造<a href="/tag/hanshu/" target="_blank" class="keywords">函数</a>的原型上定义的<a href="/tag/fangfa/" target="_blank" class="keywords">方法</a> eg:
alert(typeof Array.prototype.sort);//function
alert(typeof String.prototype.substring);//function
//不仅可以在原生对象的原型取得虽有默认<a href="/tag/fangfa/" target="_blank" class="keywords">方法</a>的引用,而且可以定义新的<a href="/tag/fangfa/" target="_blank" class="keywords">方法</a>
//为String类型<a href="/tag/tianjia/" target="_blank" class="keywords">添加</a>一个startsWith()的<a href="/tag/fangfa/" target="_blank" class="keywords">方法</a>
String.prototype.startsWith=function(text){
return this.indexOf(text) == 0;
};
var msg="Hello";
alert(msg.startsWith("H"));
//我们并不建议这样做。
alert("原型对象的问题");
//6、原型对象的问题 实例
function Ques() {
}
Ques.prototype={
constructor:Ques,name:"amber",job:"IT",friends:["张三","李四"],//引用类型
sayName:function(){
alert(this.name)
}
};
var q1=new Ques();
var q2=new Ques();
q1.friends.push("王五");
alert(q1.friends);//
alert(q2.friends);//
alert(q1.friends===q2.friends);
//相信大家已经看到了问题,当我创建了两个实例q1、q2,当我为q1的“朋友”添加了“王五”之后,q2的”朋友“也有了三个张三、李四、王五
//那是因为数组存在于Ques.prototype上,而非q1上。所以出现了如上结果。
//而正是这个问题,我们很少看到有人单独使用原型模式的原因所在。
本文就先到这里了,后续我们再继续讨论javascript面向对象程序设计,希望大家能够喜欢。