[翻译]javascript学习笔记 (四)-面向对象的实现
javascript中面向对象的实现
javascript中的函数可以充当类的角色,我们用函数的prototype完成类的功能。
首先了解javascript中的对象是如何工作的,对象允许你定义一个变量然后可以在变量上设置任意多的属性
让我们看下一个简单的例子
这两个代码片段创建了相同的变量,myObj。
当你在一个对象中执行一个函数时,"this"指向对象的引用。
javascript中的对象非常有用,我们写一个animal对象
var myAnimal = {
name: 'felix',
species: 'cat',
talk: function(){ alert('Meow!'); },
callOver: function(){ alert(this.name+' ignores you'); },
pet: function(){ alert('Purr!'); }
}
现在我们定义了一个变量 myAnimal,名字叫felix。当我们想创建另外一只猫,我们学要键入上述所有代码。于是面向对象思想该起作用了。用一个函数生成类似的对象而不是重复的键入代码。
上面的例子我们创建了一个函数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函数
上面函数的语法和以前的有些不同。现在可以用Cat.prototype定义属性和方法,而不是在函数体内定义。虽然这样复杂了,但是它提供了很多优点。假设我们给现有的每个cat加一个新的方法sleep 有两种方法:
第一种是跟踪每个cat,给每个cat加入方法。
第二种是使用prototype,我们可以同时为每个cat加入sleep方法
Cat.prototype.sleep = function(){ alert(this.name+' falls asleep'); };
这种方法不但快捷,而且不需要跟踪每个cat去添加sleep方法。
需要注意的是使用prototype设置方法会替代以前设置的方法。如果我们通过这种方式添加一个sleep方法
我们前面的prototypes,species,talk,callOver和pet都将被清除,我们cat的原型方法只有sleep
Prototypes也可以用来扩展javascript内置的对象。我们能实现一个String.prototype.reverse方法
强烈建议不要在array和object中使用prototype,因为这样会影响"for-in"语句的使用。看看下面的例子:
有其他方法可以达到相同的效果,我个人不喜欢使用prototype扩展array
如你所见,我们使用Array.find(ary, e)替代ary.find(e),额外的一点代码换来的是不破坏现有javascript的功能性。
Private, Public 和 Static 变量
为了理解不同级别,看看下面的例子
这里有许多访问限制级别,所有的private,privileged和public函数和变量都会在创建新的实例时被拷贝。通常可以使用prototype和public变量可以完成所有的任务。
javascript中的函数可以充当类的角色,我们用函数的prototype完成类的功能。
首先了解javascript中的对象是如何工作的,对象允许你定义一个变量然后可以在变量上设置任意多的属性
让我们看下一个简单的例子
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.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对象
var myAnimal = {
name: 'felix',
species: 'cat',
talk: function(){ alert('Meow!'); },
callOver: function(){ alert(this.name+' ignores you'); },
pet: function(){ alert('Purr!'); }
}
function Cat(name){
this.name = name;
this.species = 'Cat';
this.talk = function(){ alert('Meow!'); }
this.callOver = function(){ alert(this.name+' ignores you'); },
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 'Sam ignores you'. Just like a cat!
alert(patty.species); // alerts 'cat'
this.name = name;
this.species = 'Cat';
this.talk = function(){ alert('Meow!'); }
this.callOver = function(){ alert(this.name+' ignores you'); },
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 'Sam ignores you'. Just like a cat!
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函数
function Cat(name){
this.name = name;
}
Cat.prototype.species = 'Cat';
Cat.prototype.talk = function(){ alert('Meow!'); };
Cat.prototype.callOver = function(){ alert(this.name+' ignores you'); };
Cat.prototype.pet = function(){ alert('Purr!'); };
this.name = name;
}
Cat.prototype.species = 'Cat';
Cat.prototype.talk = function(){ alert('Meow!'); };
Cat.prototype.callOver = function(){ alert(this.name+' ignores you'); };
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方法。
function Cat(name){
this.name = name;
}
Cat.prototype = {
species: 'Cat',
talk: function(){ alert('Meow!'); },
callOver: function(){ alert(this.name+' ignores you'); },
pet: function(){ alert('Pet!'); }
}
this.name = name;
}
Cat.prototype = {
species: 'Cat',
talk: function(){ alert('Meow!'); },
callOver: function(){ alert(this.name+' ignores you'); },
pet: function(){ alert('Pet!'); }
}
需要注意的是使用prototype设置方法会替代以前设置的方法。如果我们通过这种方式添加一个sleep方法
Cat.prototype = {
sleep: function(){ alert(this.name+' falls asleep'); }
}
sleep: function(){ alert(this.name+' falls asleep'); }
}
我们前面的prototypes,species,talk,callOver和pet都将被清除,我们cat的原型方法只有sleep
Prototypes也可以用来扩展javascript内置的对象。我们能实现一个String.prototype.reverse方法
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());
如果恰当的使用它,将会很有用。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"语句的使用。看看下面的例子:
var myArray = [1, 2, 3];
for(n in myArray) alert(n); // alerts 0, 1 and 2 - the indexes of the array.
Array.prototype.something = function(){ };
for(n in myArray) alert(n); // alerts 'something', 0, 1 and 2.
for(n in myArray) alert(n); // alerts 0, 1 and 2 - the indexes of the array.
Array.prototype.something = function(){ };
for(n in myArray) alert(n); // alerts 'something', 0, 1 and 2.
有其他方法可以达到相同的效果,我个人不喜欢使用prototype扩展array
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')); // alerts 1
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')); // alerts 1
如你所见,我们使用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. |
为了理解不同级别,看看下面的例子
function Cat(name, color){
/*
Constructor: any code in here is run when the object is created
*/
Cat.cats++;
/*
Private variables and functions - may only be accessed by private or privileged functions.
Note that 'name' and 'color', passed into the Class, are already private variables.
*/
var age = 0;
var legs = 4;
function growOlder(){
age++;
}
/*
Public variables - may be accessed publicly or privately
*/
this.weight = 1;
this.length = 5;
/*
Privileged functions - may be accessed publicly or privately
May access Private variables.
Can NOT be changed, only replaced with public versions
*/
this.age = function(){
if(age==0) this.length+=20;
growOlder();
this.weight++;
}
}
/*
Prototyped Functions - may be accessed publicly
*/
Cat.prototype = {
talk: function(){ alert('Meow!'); },
callOver: function(){ alert(this.name+' ignores you'); },
pet: function(){ alert('Pet!'); }
}
/*
Prototyped Variables - may be accessed publicly.
May not be overridden, only replaced with a public version
*/
Cat.prototype.species = 'Cat';
/*
Static variables and functions - may be accessed publicly
*/
Cat.cats = 0;
/*
Constructor: any code in here is run when the object is created
*/
Cat.cats++;
/*
Private variables and functions - may only be accessed by private or privileged functions.
Note that 'name' and 'color', passed into the Class, are already private variables.
*/
var age = 0;
var legs = 4;
function growOlder(){
age++;
}
/*
Public variables - may be accessed publicly or privately
*/
this.weight = 1;
this.length = 5;
/*
Privileged functions - may be accessed publicly or privately
May access Private variables.
Can NOT be changed, only replaced with public versions
*/
this.age = function(){
if(age==0) this.length+=20;
growOlder();
this.weight++;
}
}
/*
Prototyped Functions - may be accessed publicly
*/
Cat.prototype = {
talk: function(){ alert('Meow!'); },
callOver: function(){ alert(this.name+' ignores you'); },
pet: function(){ alert('Pet!'); }
}
/*
Prototyped Variables - may be accessed publicly.
May not be overridden, only replaced with a public version
*/
Cat.prototype.species = 'Cat';
/*
Static variables and functions - may be accessed publicly
*/
Cat.cats = 0;
这里有许多访问限制级别,所有的private,privileged和public函数和变量都会在创建新的实例时被拷贝。通常可以使用prototype和public变量可以完成所有的任务。