论坛首页 Web前端技术论坛

javascript面向对象技术基础(五)

浏览 13287 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-12-08  

类变量/类方法/实例变量/实例方法
先补充一下以前写过的方法:
在javascript中,所有的方法都有一个call方法和apply方法.这两个方法可以模拟对象调用方法.它的第一个参数是对象,后面的
参数表示对象调用这个方法时的参数(ECMAScript specifies two methods that are defined for all functions, call()
and apply(). These methods allow you to invoke a function as if it were a method of some other object. The first
argument to both call() and apply() is the object on which the function is to be invoked; this argument becomes
the value of the this keyword within the body of the function. Any remaining arguments to call() are the values
that are passed to the function that is invoked).比如我们定义了一个方法f(),然后调用下面的语句:
f.call(o, 1, 2);
作用就相当于
o.m = f;
o.m(1,2);
delete o.m;
举个例子:

function Person(name,age) {  //定义方法
    this.name = name;
    this.age = age;
}
var o = new Object();   //空对象
alert(o.name + "_" + o.age); //undefined_undefined

Person.call(o,"sdcyst",18); //相当于调用:o.Person("sdcyst",18)
alert(o.name + "_" + o.age); //sdcyst_18

Person.apply(o,["name",89]);//apply方法作用同call,不同之处在于传递参数的形式是用数组来传递
alert(o.name + "_" + o.age); //name_89

 ---------------------------------

实例变量和实例方法都是通过实例对象加"."操作符然后跟上属性名或方法名来访问的,但是我们也可以为类来设置方法或变量,
这样就可以直接用类名加"."操作符然后跟上属性名或方法名来访问.定义类属性和类方法很简单:

Person.counter = 0;   //定义类变量,创建的Person实例的个数
function Person(name,age) {
    this.name = name;
    this.age = age;
    Person.counter++; //没创建一个实例,类变量counter加1
};

Person.whoIsOlder = function(p1,p2) { //类方法,判断谁的年龄较大
    if(p1.age > p2.age) {
        return p1;
    } else {
        return p2;
    }
}

var p1 = new Person("p1",18);
var p2 = new Person("p2",22);

alert("现在有 " + Person.counter + "个人");  //现在有2个人
var p = Person.whoIsOlder(p1,p2);
alert(p.name + "的年龄较大");   //p2的年龄较大

 

prototype属性的应用:
下面这个例子是根据原书改过来的.
假设我们定义了一个Circle类,有一个radius属性和area方法,实现如下:

function Circle(radius) {
    this.radius = radius;
    this.area = function() {
        return 3.14 * this.radius * this.radius;
    }
}
var c = new Circle(1);
alert(c.area());  //3.14

 假设我们定义了100个Circle类的实例对象,那么每个实例对象都有一个radius属性和area方法,
实际上,除了radius属性,每个Circle类的实例对象的area方法都是一样,这样的话,我们就可以
把area方法抽出来定义在Circle类的prototype属性中,这样所有的实例对象就可以调用这个方法,
从而节省空间.

function Circle(radius) {
    this.radius = radius;
}
Circle.prototype.area = function() {
        return 3.14 * this.radius * this.radius;
    }
var c = new Circle(1);
alert(c.area());  //3.14

 

现在,让我们用prototype属性来模拟一下类的继承:首先定义一个Circle类作为父类,然后定义子类
PositionCircle.

function Circle(radius) {  //定义父类Circle
    this.radius = radius;
}
Circle.prototype.area = function() { //定义父类的方法area计算面积
    return this.radius * this.radius * 3.14;
}

function PositionCircle(x,y,radius) { //定义类PositionCircle
    this.x = x;                    //属性横坐标
    this.y = y;	                   //属性纵坐标
    Circle.call(this,radius);      //调用父类的方法,相当于调用this.Circle(radius),设置PositionCircle类的
                                   //radius属性
}
PositionCircle.prototype = new Circle(); //设置PositionCircle的父类为Circle类

var pc = new PositionCircle(1,2,1);
alert(pc.area());  //3.14
                   //PositionCircle类的area方法继承自Circle类,而Circle类的
                   //area方法又继承自它的prototype属性对应的prototype对象
alert(pc.radius); //1  PositionCircle类的radius属性继承自Circle类

/*
注意:在前面我们设置PositionCircle类的prototype属性指向了一个Circle对象,
因此pc的prototype属性继承了Circle对象的prototype属性,而Circle对象的constructor属
性(即Circle对象对应的prototype对象的constructor属性)是指向Circle的,所以此处弹出
的是Circ.
*/
alert(pc.constructor); //Circle    

/*为此,我们在设计好了类的继承关系后,还要设置子类的constructor属性,否则它会指向父类
的constructor属性
*/
PositionCircle.prototype.constructor = PositionCircle
alert(pc.constructor);  //PositionCircle
 
   发表时间:2008-12-09   最后修改:2008-12-09
引用
f.call(o, 1, 2);
作用就相当于
o.m = f;
o.m(1,2);
delete o.m;


在这里,我不敢苟同。
请用firebug调试器调试。调试时在f函数中设下断点,检查this对象,是否已经具有了o对象中的属性。

具体如何归纳总结,我想到时你心中有数。

在你后来的例子中由于你的o与f中的属性相同,给你了不全面的归纳总结 请楼主,执行下面的语句。

   function f(a,b){ 
        alert(a+''+b+'');
        alert(this.x);
    }
    var o={};
    o.a='3';
    o.x='d';
    f.call(o,1,2);
    alert("=====");

当上面执行后,你会发现f原本没有x属性,在这里居然有了x属性,其次还是"d".
将发现产生三次消息提示框。依次为:
12
d
=====

0 请登录后投票
   发表时间:2008-12-09  


按照某些人的做法,应该让你的这篇网文投一新手贴。

理由:会误导新手,把更多新手拉入阴沟。我这种新手都能发现错误。


转眼一想:论坛,是讨论的地方,难道就只能出最正确最完美的东东吗?
难道不允许在讨论中,发现问题、纠正问题、加深理解、完善总结吗?

不说了,我要进行我的桌面布局管理器了。在这里借楼主的贴,发点牢骚 。对

楼主说声Sorry!




0 请登录后投票
   发表时间:2008-12-09  
非常感谢您的意见,不过在这里我还是要坚持自己的观点:
我还是以你的例子为基础进行辩驳:

function f(a,b){  
    alert(a+'_'+b); 
    alert(this.x); 

f(2,3);  //2_3   undefined
var o={}; 
o.a='3'; 
o.x='d'; 
f.call(o,1,2);  //1_2  d
/**
下面的例子是根据文章中提到的模拟call的作用
*/
o.m = function(a,b) {
    alert(a+'_'+b); 
    alert(this.x);
}
o.m(1,2);  //1_2  d
delete o.m;

希望你能帮我解释一下上面的例子和文章中的内容有什么冲突.


0 请登录后投票
   发表时间:2008-12-09  
yunhaifeiwu 写道

按照某些人的做法,应该让你的这篇网文投一新手贴。理由:会误导新手,把更多新手拉入阴沟。我这种新手都能发现错误。转眼一想:论坛,是讨论的地方,难道就只能出最正确最完美的东东吗?难道不允许在讨论中,发现问题、纠正问题、加深理解、完善总结吗?不说了,我要进行我的桌面布局管理器了。在这里借楼主的贴,发点牢骚 。对楼主说声Sorry!

我真的希望你能给我指出错误之处,我好改正以免误导大家.说实话,写这样的东西我自己都没
有谱,而且很多东西我是按照原书的内容翻译后自己理解,如果出错的话我一定会改正过来,再次感谢!!
0 请登录后投票
   发表时间:2008-12-09   最后修改:2008-12-09
sdcyst 写道
非常感谢您的意见,不过在这里我还是要坚持自己的观点:
我还是以你的例子为基础进行辩驳:

function f(a,b){  
    alert(a+'_'+b); 
    alert(this.x); 

f(2,3);  //2_3   undefined
var o={}; 
o.a='3'; 
o.x='d'; 
f.call(o,1,2);  //1_2  d
/**
下面的例子是根据文章中提到的模拟call的作用
*/
o.m = function(a,b) {
    alert(a+'_'+b); 
    alert(this.x);
}
o.m(<script type="text/javascript" src="http://www.iteye.com/javascripts/tinymce/themes/advanced/langs/zh.js"></script><script type="text/javascript" src="http://www.iteye.com/javascripts/tinymce/plugins/javaeye/langs/zh.js"></script>1,2);  //1_2  d
delete o.m;

希望你能帮我解释一下上面的例子和文章中的内容有什么冲突.




测试了,你的这种也是正确的。从中受教了。感谢中!
0 请登录后投票
   发表时间:2008-12-09  
yunhaifeiwu 希望不要给自己挖坑, 楼主是欢迎讨论的. 你有问题可以指出. 我想楼主这么耐心地在这一系列每个贴里都有耐心的回答. 决不会排斥异议的.
0 请登录后投票
   发表时间:2008-12-09  
srdrm 写道
yunhaifeiwu 希望不要给自己挖坑, 楼主是欢迎讨论的. 你有问题可以指出. 我想楼主这么耐心地在这一系列每个贴里都有耐心的回答. 决不会排斥异议的.



首先申明:没有针对楼主。到javascript是因为高手多,从中学习来着。学习过程,不可能不出现理解性的偏差,发现了及时纠正过来罢了。
0 请登录后投票
   发表时间:2008-12-09  
yunhaifeiwu 写道


测试了,你的这种也是正确的。从中受教了。感谢中!



f.call(o, 1, 2);
作用就相当于
o.m = f;
o.m(1,2);
delete o.m;

上面这个例子是原文中的,后来我测试的时候也是这样.你可以找到原书看一下.
我非常害怕自己的帖子会对别人产生误导,所以非常感谢你的意见.

扣个字眼:你在回复中说,"你的这种测试也是正确的",但是我还是没弄明白你原来
想要表达的意思,包括你觉得那个例子.
0 请登录后投票
   发表时间:2008-12-09  
sdcyst 写道
yunhaifeiwu 写道


测试了,你的这种也是正确的。从中受教了。感谢中!



f.call(o, 1, 2);
作用就相当于
o.m = f;
o.m(1,2);
delete o.m;

上面这个例子是原文中的,后来我测试的时候也是这样.你可以找到原书看一下.
我非常害怕自己的帖子会对别人产生误导,所以非常感谢你的意见.

扣个字眼:你在回复中说,"你的这种测试也是正确的",但是我还是没弄明白你原来
想要表达的意思,包括你觉得那个例子.


你说的
引用
f.call(o, 1, 2);
作用就相当于
o.m = f;
o.m(1,2);
delete o.m;


揭示f.call的含义,这是从等价代码的角度上揭示的。如果用文字进行描述又是怎样的呢?
msdn上的描述很准确,很严密,但是理解有点困难。
因此我站到我测试得到的结果,进行总结归纳: 
  f.call(o,1,2)的含义是:
  1 调用了函数f .其实际参数是 1,2
  2 在f函数执行时也仅在f函数执行时,f中的this参数中具有o中的属性。如果原来有与o相同的属性,
则会被覆盖掉。

申明:以上仅仅是个人对call的自我总结,目的是辅助理解,准确的定义请看相关权威教材。三人行必有

我师,如果有误,请指出,我会及时更正。在技术论坛上,谢绝因观点不一样,而进行人身攻击。




0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics