对于javascript大家大部分时间用来做效果,但却忽视了最基础的东西,
当大家把javascript基本功学扎实了,我认为对以后写出漂亮的js代码有很大的帮助,
今天就总结下我对javascript关于面向对象方面的理解
首先总结一下javascript中的"类",
第一种算是比较灵活的方式了,成为工厂定义方式
var obj=new Object;
obj.color='red';
obj.dodo=function(){...};
为什么说它灵活,就是因为它可以在实例化对象后,可以对该对象增加属性,可以完善我们的需求,
我们经常会得到实例化的对象比如:=var aa=document.getElementById('lover'),此时我们可以很方便的增加各种方法属性,
aa.onclick=function(){...};aa.lover='i love you ';等,以至传递的时候只需要传递该对象;
<script language= "javascript">
var obj=new Object;
obj.color='red';
obj.dodo=function(){alert('aa')};
for(aa in obj)
{
alert(aa);//color;dodo;
}
</script>
javascript中定义类我们平时都是按照这种方式,因为毕竟和java和c#比较接近,
function Car(scolor,snum)
{
this.color=scolor;
this.dodo=function(){alert('aa')};
}
//这叫做构造函数方式定义类
var obj=new Car('yellow',30);
for(aa in obj)
{
alert(aa);//color;dodo
}
上面不用多介绍大家是最熟悉的了,
接下来介绍原型方式:
什么是原型,关于具体的概念大家可以查看资料,不想说太多,只想举例子来说明,
<script language= "javascript">
function Car(scolor,snum)
{
this.color=scolor;
this.dodo=function(){alert('aa')};
}
Car.prototype.getValue = function (){
return this.color;
}
Car.prototype.setValue = function (value){
this.color = value;
}
var obj=new Car('yellow',30);
obj.setValue(666);
alert(obj.getValue());//666
for(aa in obj)
{
alert(aa);//color;dodo;setValue;getValue
}
</script>
可以看到利用原型可以为对象增加属性和方法,具体为什么要利用原型来操作,概念性的问题可以查资料,
但是有一点需要注意的是:
<script language= "javascript">
function Car(scolor,snum)
{
//this.cc="cc";
//this.docc=function(){alert(this.cc)}
}
Car.prototype.cc = "cccc"
Car.prototype.docc = function (){alert(this.cc)}
var obj=new Car('yellow',30);
for(aa in Car.prototype)
{
alert(aa);//cc;docc
}
alert(obj.cc);
obj.docc();
</script>
虽然同样是给对象增加了cc属性和docc方法,但是查找顺序是先查找构造函数中是否有该属性和方法,
没有再搜索propertype,根据
<script language= "javascript">
function Car(scolor,snum)
{
this.cc="cc";
this.docc=function(){alert(this.cc)}
}
Car.prototype.cc = "cccc"
Car.prototype.docc = function (){alert(this.cc)}
var obj=new Car('yellow',30);
alert(obj.cc);//cc
delete obj.cc;
alert(obj.cc);//cccc
obj.docc();//cccc
delete obj.docc();
obj.docc();//cccc
</script>
可以看到首先删除两个属性仍然可以输出属性值,并且第一个obj.docc()获取的是原型中的cc属性值
看下面的例子:
<script language= "javascript">
function Car(scolor,snum)
{
this.cc="cc";
}
Car.prototype.cc = "cccc"
Car.prototype.docc = function (){alert(this.cc)}
var obj=new Car('yellow',30);
Car.prototype.docc();//cccc
</script>
可以直接调用原型方法,调用的是原型中的cc属性而不是构造函数的,
如果没有定义原型cc属性,就会显示undefined,在直接调用原型方法时这是需要注意的地方
再然后介绍一下javascript静态的实现方法:
<script language= "javascript">
function Car()
{
Car.docc = function (){alert('cc')}
}
Car.docc = function (){alert('cccc')}
Car.docc();//cccc
var obj=new Car();//初始化后构造函数中的静态方法覆盖外边定义的静态方法,需要注意!
Car.docc();//cc
</script>
在了解以上基本概念以后,接下来介绍一下javascript如何实现继承,
我们知道所有的对象都是继承objec类,而javascript中是怎样继承了object类呢?
其实在javascript中隐藏了
Car.prototype = new Object();
作用是什么呢?很明显Object中有toString()方法,
这样
Car.paopertype.toString()=function(){...}
//是不是就显而易见了,在实例化Car可以成功的引入该属性,而Object中的所有属性和方法都归了Car,就这样Car继承了Object的所有属性和方法。
<script language= "javascript">
function Car(scolor,snum)
{
this.cc="cc";
}
alert(Car.toString());
</script>
上面的例子不是太贴切,我补充一个大家看看
<script language= "javascript">
function obj()
{
this.aa='aa';
this.bb=function(){alert('==========')};
}
function Car()
{
this.cc="cc";
}
Car.prototype = new obj();
var aa=new Car();
for(a in aa)
{
alert(a);//aa;bb;cc
}
aa.bb();
for(b in Car.prototype)
{
alert(b);//aa;bb
}
</script>
这样大家就能明白
Car.prototype = new obj();
这句话的含义了。
接下来又引出一个重要属性,constructor,
<script language= "javascript">
function Car(scolor,snum)
{
this.cc="cc";
}
alert(Car.prototype.constructor);//constructor就是指向自己本身的一个属性
</script>
再看下面
<script language= "javascript">
function Car(scolor,snum)
{
this.cc="cc";
}
Car.prototype.cc = "cccc"
Car.prototype.docc = function (){alert(this.cc)}
alert(Car.prototype.constructor.prototype.cc);//cccc
Car.prototype.constructor.prototype.docc();//cccc
alert(Car.prototype.constructor===Car);//true
</script>
大家看结果明白了吧
还有让大家比较头疼的问题就是call和apply的用法,
首先给大家做个解释,
function classA(scolor){
this.docc=function(){...}
}
function classB(){
//this.newMethod=classA;
//this.newMethod(scolor);
//delete this.newMethod();
//这三行与下面的call是一个效果,通过这个例子大家就应该明白call具体是怎样执行的了,等同于上面三行的实现,
一句this.newMethod(scolor);函数调用,就将classA中的关于this.的方法和属性就都归classB,因为此时classA中的
this指针在classB内部指向的就是classB本身,所以这也是实现继承的一种手段,
classA.call(this,scolor);
}
完整的例子:
<script language= "javascript">
function classA(scolor){
this.cc=scolor;
this.docc=function(){alert(this.cc)}
}
function classB(){
classA.call(this,"yellow");
}
var obj=new classB();
alert(obj.cc)//yellow
obj.docc();//yellow
</script>
此时大家想原型方法能够继承吗?其实就按照我上面的解释,大家也该明白函数调用this.newMethod(scolor)只调用函数本身,就象我们平时使用函数一样,不会牵扯到原型上去,所以
<script language= "javascript">
function classA(scolor){
this.cc=scolor;
this.docc=function(){alert(this.cc)}
}
classA.prototype.dd = "dddd"
classA.prototype.dodd = function (){alert(this.dd)}
function classB(){
classA.call(this,"yellow");
}
var obj=new classB();
alert(obj.dd)//undefined
obj.dodd();//出错没有该方法
</script>
那我们怎么办呢?很简单,只要仔细看了我上面的介绍,
<script language= "javascript">
function classA(scolor){
this.cc=scolor;
this.docc=function(){alert(this.cc)}
}
classA.prototype.dd = "dddd"
classA.prototype.dodd = function (){alert(this.dd)}
function classB(){
}
classB.prototype = new classA("yellow");
var obj=new classB();
alert(obj.cc)//yellow
obj.docc();//yellow
alert(obj.dd)//dddd
obj.dodd();//dddd
</script>
我再给大家举个合用的例子
<script language= "javascript">
function classA(scolor){
this.cc=scolor;
this.docc=function(){alert(this.cc)}
}
classA.prototype.dd = "dddd"
classA.prototype.dodd = function (){alert(this.dd)}
function classB(){
classA.call(this,"red");//初始化red后继承
}
classB.prototype = new classA("yellow");//初始化yellow后继承
var obj=new classB();
alert(obj.cc)//red
obj.docc();//red
alert(obj.dd)//yellow
obj.dodd();//yellow
</script>
为什么会是red不是yellow原因很简单,一个是在构造函数内实现了继承,一个是原型继承,而我们说过构造函数在
原型之前调用,所以会出现red而不是yellow。
最后借助风之石写的一个例子结束此次文章:
<html>
<body>
<button id=btTest>test</button>
</body>
</html>
<script>
if(!document.all){
HTMLElement.prototype.attachEvent=function(sType,foo){
this.addEventListener(sType.slice(2),foo,false)
}
}
Function.prototype.bindNode=function(oNode){
var foo=this,iNodeItem
//使用了全局数组__bindNodes,通过局部变量iNodeItem进行跨函数传值,如果直接传送oNode,也将造成闭包
if(window.__bindNodes==null)
__bindNodes=[]
__bindNodes.push(oNode)
iNodeItem=__bindNodes.length-1
//释放oNode
oNode=null
return function(e){
foo.call(__bindNodes[iNodeItem],e||event)
//需要注意的是调用了call本身就是一个调用了foo()函数的过程,所以上面返回的是一个函数
}
}
abc()
function abc(){
var bt=document.getElementById("btTest")
bt.attachEvent("onclick",function(){
//如果不经过bindNode处理,下面的结果将是undefined
alert(this.tagName)
}.bindNode(bt))
//释放bt
bt=null
}
</script>
大家可以自己回味一下call的用法,不明白或者有错误可以在回复中指出,匆匆忙忙写完一定会有不足之处,
请指教
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xiaolei1982/archive/2008/10/02/3010066.aspx