javascript中面向对象的实现
javascript中的函数可以充当类的角色,我们用函数的prototype完成类的功能。
首先了解javascript中的对象是如何工作的,对象允许你定义一个变量然后可以在变量上设置任意多的属性
让我们看下一个简单的例子
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
var
myObj
=
new
Object;
myObj.a
=
5
;
myObj['b']
=
10
;
myObj.c
=
20
;
myObj.getTotal
=
function
(){
alert(
this
.a
+
this
.b
+
this
.c);
});
//
or
var
myObj
=
{a:
5
,b:
10
,c:
20
,getTotal:
function
(){alert(
this
.a
+
this
.b
+
this
.c);}};
这两个代码片段创建了相同的变量,myObj。
当你在一个对象中执行一个函数时,"this"指向对象的引用。
javascript中的对象非常有用,我们写一个animal对象
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
var
myAnimal
=
{
name:'felix',
species:'cat',
talk:
function
(){alert('Meow
!
');},
callOver:
function
(){alert(
this
.name
+
'ignoresyou');},
pet:
function
(){alert('Purr
!
');}
}
现在我们定义了一个变量 myAnimal,名字叫felix。当我们想创建另外一只猫,我们学要键入上述所有代码。于是面向对象思想该起作用了。用一个函数生成类似的对象而不是重复的键入代码。
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
function
Cat(name){
this
.name
=
name;
this
.species
=
'Cat';
this
.talk
=
function
(){alert('Meow
!
');}
this
.callOver
=
function
(){alert(
this
.name
+
'ignoresyou');},
this
.pet
=
function
(){alert('Purr
!
');}
}
var
felix
=
new
Cat('Felix');
var
sam
=
new
Cat('Sam');
var
patty
=
new
Cat('Patty');
felix.pet();
//
alerts'Purr!'
sam.callOver();
//
alerts'Samignoresyou'.Justlikeacat!
alert(patty.species);
//
alerts'cat'
上面的例子我们创建了一个函数cat,然后用函数创建了3个新的cat对象:felix,sam和patty。每个cat都有相同的函数:talk,callOver和pet,都有自己的species属性。
我们通常说felix,sam和patty是相同对象的实例。cat函数中的代码是构造函数。接收"name"用来设置this.name。但是在每个 cat构造的时候,我们实际上创建了每个方法的3个副本。由于talk,callOver和pet方法是相同的,我们只需每个方法的一个副本。
我们使用Prototyping重写cat函数
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
function
Cat(name){
this
.name
=
name;
}
Cat.prototype.species
=
'Cat';
Cat.prototype.talk
=
function
(){alert('Meow
!
');};
Cat.prototype.callOver
=
function
(){alert(
this
.name
+
'ignoresyou');};
Cat.prototype.pet
=
function
(){alert('Purr
!
');};
上面函数的语法和以前的有些不同。现在可以用Cat.prototype定义属性和方法,而不是在函数体内定义。虽然这样复杂了,但是它提供了很多优点。假设我们给现有的每个cat加一个新的方法sleep 有两种方法:
第一种是跟踪每个cat,给每个cat加入方法。
第二种是使用prototype,我们可以同时为每个cat加入sleep方法
Cat.prototype.sleep = function(){ alert(this.name+' falls asleep'); };
这种方法不但快捷,而且不需要跟踪每个cat去添加sleep方法。
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
function
Cat(name){
this
.name
=
name;
}
Cat.prototype
=
{
species:'Cat',
talk:
function
(){alert('Meow
!
');},
callOver:
function
(){alert(
this
.name
+
'ignoresyou');},
pet:
function
(){alert('Pet
!
');}
}
需要注意的是使用prototype设置方法会替代以前设置的方法。如果我们通过这种方式添加一个sleep方法
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
Cat.prototype
=
{
sleep:
function
(){alert(
this
.name
+
'fallsasleep');}
}
我们前面的prototypes,species,talk,callOver和pet都将被清除,我们cat的原型方法只有sleep
Prototypes也可以用来扩展javascript内置的对象。我们能实现一个String.prototype.reverse方法
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
String.prototype.reverse
=
function
(){
var
out
=
'';
for
(
var
i
=
this
.length
-
1
;i
>=
0
;i
--
){
out
+=
this
.substr(i,
1
);
}
return
out;
}
alert('asdf'.reverse());
如果恰当的使用它,将会很有用。
强烈建议不要在array和object中使用prototype,因为这样会影响"for-in"语句的使用。看看下面的例子:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
var
myArray
=
[
1
,
2
,
3
];
for
(n
in
myArray)alert(n);
//
alerts0,1and2-theindexesofthearray.
Array.prototype.something
=
function
(){};
for
(n
in
myArray)alert(n);
//
alerts'something',0,1and2.
有其他方法可以达到相同的效果,我个人不喜欢使用prototype扩展array
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
Array.find
=
function
(ary,element){
for
(
var
i
=
0
;i
<
ary.length;i
++
){
if
(ary[i]
==
element){
return
i;
}
}
return
-
1
;
}
alert(Array.find(['a','b','c','d','e'],'b'));
//
alerts1
如你所见,我们使用Array.find(ary, e)替代ary.find(e),额外的一点代码换来的是不破坏现有javascript的功能性。
Private, Public 和 Static 变量
Private |
Declared with 'var variableName' or 'function functionName' inside of the object. Can only be accessed by other private or privileged functions. |
Public |
Declared with 'this.variableName' inside of the object. Can be changed by any function or method. |
Privileged |
Declared with 'this.functionName = function(){ ... }' inside of the object. Can be accessed by any function or method and can call reference or change any Private variable. |
Prototype |
Declare with 'Class.prototype.variableName' or 'Class.prototype.functionName'. Functions declared this way will have access to any public or prototype variables. Attempts to change variable created this way will instead create a new public variable on the object and the prototype variable will be unavailable. |
Static |
Declare with 'Class.variableName' or 'Class.functionName'. Can be changed by any function or method. This method is rarely used. |
为了理解不同级别,看看下面的例子
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
function
Cat(name,color){
/*
Constructor:anycodeinhereisrunwhentheobjectiscreated
*/
Cat.cats
++
;
/*
Privatevariablesandfunctions-mayonlybeaccessedbyprivateorprivilegedfunctions.
Notethat'name'and'color',passedintotheClass,arealreadyprivatevariables.
*/
var
age
=
0
;
var
legs
=
4
;
function
growOlder(){
age
++
;
}
/*
Publicvariables-maybeaccessedpubliclyorprivately
*/
this
.weight
=
1
;
this
.length
=
5
;
/*
Privilegedfunctions-maybeaccessedpubliclyorprivately
MayaccessPrivatevariables.
CanNOTbechanged,onlyreplacedwithpublicversions
*/
this
.age
=
function
(){
if
(age
==
0
)
this
.length
+=
20
;
growOlder();
this
.weight
++
;
}
}
/*
PrototypedFunctions-maybeaccessedpublicly
*/
Cat.prototype
=
{
talk:
function
(){alert('Meow
!
');},
callOver:
function
(){alert(
this
.name
+
'ignoresyou');},
pet:
function
(){alert('Pet
!
');}
}
/*
PrototypedVariables-maybeaccessedpublicly.
Maynotbeoverridden,onlyreplacedwithapublicversion
*/
Cat.prototype.species
=
'Cat';
/*
Staticvariablesandfunctions-maybeaccessedpublicly
*/
Cat.cats
=
0
;
这里有许多访问限制级别,所有的private,privileged和public函数和变量都会在创建新的实例时被拷贝。通常可以使用prototype和public变量可以完成所有的任务。