您的位置:首页 > Web前端 > JavaScript

【JavaScript】--原型

2015-08-25 11:52 615 查看
(一)
创建对象:
基本的创建对象以及给对象赋值的方法为:

var box=new Object();//创建对象
box.name='Lishaoran';//创建属性并赋值
box.run=function(){//创建一个run方法并返回值
return this.name+this.age+'运行中…….';
};


客户端调用:

Var box2=box;//得到box的引用
Box2.name='nihao';//直接改变name属性
 

当创建多个类似对象声明的时候,可以用工厂模式来解决:
Function createObject(name,age){
var obj=new Object();//创建对象
obj.name=name;//创建属性并赋值
obj.run=function(){//创建一个run方法并返回值
return this.name+this.age+'运行中…….';
};
return obj;
}
 

 
(二)
还可以用构造函数来创建特定的对象
 
Function Box(name,age){
this.name=name;
this.age=age;
this.run=function(){
return this.name+this.age+'运行中…….';
};
}


 
客户端使用:

var box1=new Box('lishaoran',100);//给属性赋值
alert(box1.run());//运行对象的方法。输出姓名和年龄。


 
比较可以得出:构造函数方法没有显示的创建对象(new Object());直接将属性和方法赋给this对象。
还有一点不同:构造函数调用的时候必须用new运算符,而普通的函数没有。
 
 
(三)
       有了前面的两个先决条件咱们讲解原型就会简单的多了,下面让我一一道来:
有上面的两部分讲解可以知道:用构造函数创建对象的方法容易造成每次实例化都会分配一个内存地址,浪费空间,所以我们就引进了一个原型来解决。
原型(prototype)属性是一个对象,它可以通过调用构造函数而创建所在函数对象的原型对象。
使用原型可以让所有对象实例共享它所包含的属性和方法,也就是我们可以通过原型来直接将属性或者方法添加到构造函数中而不必在构造函数中定义对象的信息。
Function Box(){} //声明一个构造函数
Box.prototype.name='Lee';//用原型为构造函数添加属性
Box.prototype.age=100;
Box.prototype.run=function(){//用原型为构造函数添加方法
return this.name+this.age+'运行中…….';
}<span style="font-family: SimSun; font-size: 14pt; background-color: rgb(255, 255, 255);"> </span>

客户端访问:

var box1=new Box();
alert(box1.name);   //由上面代码知:对象构造函数中没有值,所以访问原型中的值,返回Lee;
box1.name='Jack';
alert(box1.name);//上面的一句已经给构造函数添加了name属性并赋值了,所以返回Jack;


 
咱们看看用构造函数和用原型模式声明一个对象属性在内存中的显示,可能就会明白上面客户端代码调用的不同了:
 



 


 
 
 
原型模式图中的两个属性:_proto_为实例指向原型对象的一个指针,它指向构造函数的原型属性constructor.
原型模式的执行流程为:
1、先查找构造函数实例中的属性或方法,如果有,立刻返回;
2、如果构造函数中没有,则去它的原型里面找,有则返回。
 
需要注意的是:原型的声明是有先后顺序的,如果重写原型则会切断之前的原型;而且我们可以通过对象实例来访问保存在原型中的值,但是却不能通过原型对象重写原型中的值!
 
原型的优点也是它的缺点:共享。因为它省略了构造函数传参初始化这一个过程,造成初始化的值都是一致的。而原型中所有属性都是被很多实例共享的,共享对于函数非常合适,但是对于包含引用类型的属性,就会导致所有引用这一属性的值都改变,非常不好!
为了解决构造传参和共享问题,我们可以组合构造函数+原型模式

Box.prototype={
constructor:Box,
run:function(){
returnthis.name+this.age+this.family;
}
};
 

但是运用原型模式会导致不管你是否调用了原型中的共享方法,都会初始化原型中的方法,所以我们就又提出了:动态原型模式

Function Box(name,age){
this.name=name;
this.age=age;
If(typeof this.run!='function'){//仅在第一次调用的时候初始化
Box.prototype.run=function(){
return this.name+this.age+'运行中……';
};
}
}


这样写就可以使当第一次调用构造函数时,run()方法发现不存在,然后初始化原型,当第二次调用的时候就不会初始化,这样既得到了封装,又实现了原型方法共享,并且属性都保持独立!
 
 
(四)
 
继承是面向对象中比较核心的概念。实现继承一般会有两种方式:一个是接口实现,另一个是继承。而ECMAScript只支持继承,不支持接口实现,而实现继承的方式也是依靠原型链完成的。
首先咱们得明白什么是原型链:

Function Box(){
This.name='Lee';
}

Function Desk(){
This.age=100;
}

Desk.prototype=new Box();//Desk继承了Box,通过原型形成链状。

Function table(){
This.level='A';
}

table.prototype=new Desk();//加长原型链


 
这就是一个原型链的体现,这样table就可以用Box和Desk的属性了!
 
 


 
PS:其实上面的原型链还缺少一环,就是Object,所有构造函数都继承自Object,而继承Object是自动完成的,不需要程序员手动继承。
 
在JS中,被继承的函数称为超类型,继承的函数称为子类型,继承不能用字面量的方法重写原型,而且子类型无法给超类型传参。
为了解决引用共享和超类型无法传参以及复用的问题,我们应用了对象冒充(借用构造函数)+原型链技术,这种模式就是组合继承
 

Function Box(age){
this.name=['Lee','Jack','Hello'];
this.age=age;
}
Box.prototype.run=function(){
returnthis.name+this.age;
};

Function Desk(age){
Box.call(this,age);//采用了对象冒充,给超类型Box传参数
}

Desk.prototype=new Box();//Desk继承了Box,通过原型形成链状。


 
客户端调用:

var desk=new Desk(100);
alert(desk.run());
 
 

总结:
除了上面讲的几种方法,还有一种继承模式叫原型式继承,这种继承借助原型并基于已有的对象创建新对象,同时还不必因此创建自定义类型。寄生式继承就是把原型式+工厂模式结合,目的是为了封装对象的过程。感觉不用到实际中很难理解,所以还是等以后有了一定的项目经验再来总结吧!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: