简单的this,麻烦的this

开发 开发工具
周末的Hello World咖啡馆总是热闹非凡。 Java , Python, Ruby, JavaScript围坐在一起,一边喝咖啡,一边海阔天空。

 周末的Hello World咖啡馆总是热闹非凡。 

Java , Python, Ruby, JavaScript围坐在一起,一边喝咖啡,一边海阔天空。   

C老头儿则待在一旁,冷眼旁观。 

聊着聊着,这话题不知怎么着转移到了“this”上来了。 

Java 说: “唉!你们不知道吧,对于一个初学Java的人来说,this 是非常难于理解的。”  

Python说:“this 在你那里已经够简单了啊。还难于理解?”

“我们都是支持面向对象编程的,在我这里,this 可以用到实例方法或者构造器中,表示对当前对象实例的引用。”  

  1. public class Point { 
  2.     private double x = 0.0; 
  3.     private double y = 0.0; 
  4.     public Point(int x, int y) { 
  5.         this.x = x; 
  6.         this.y = y; 
  7.     } 
  8.  
  9.    public double distanceTo(Point that) { 
  10.         double dx = this.x - that.x; 
  11.         double dy = this.y - that.y; 
  12.         return Math.sqrt(dx*dx + dy*dy); 
  13.     } 

“这不很容易理解吗? ” Ruby 问道。  

“对于***次接触面向对象编程的人来说,他分不清这个当前对象this到底是哪个对象。”  Java说,“我必须得再写一段代码给他掰扯一下。”  

  1. Point p1 = new Point(1,1); 
  2. Point p2 = new Point(2,2); 
  3.  
  4. // this 指向的是p1 
  5. p1.distanceTo(p2);   
  6.  
  7. // this 指向的是p2 
  8. p2.distanceTo(p1);   

“对啊,this必须得有个上下文才能准确理解。” Python说,“还有,你那个this吧,是个隐式的,像我是显式的:”  

  1. class Point: 
  2.     def __init__(this, x, y): 
  3.         this.x = x 
  4.         this.y = y 
  5.     def distanceTo(this,point): 
  6.         dx = this.x - point.x 
  7.         dy = this.y - point.y 
  8.         return math.sqrt(dx**2+dy**2) 

Java 说:“你不是一直用self吗,怎么现在是this?” 

Python笑道:“我这不是为了和你Java老弟保持一致嘛,反正只是个变量名,你想用this就用this,想用that就用that,只不过我们习惯于用self 。”  

Ruby说: “Python兄,你把this放到方法中作为一个参数,实在是太丑陋了,一点美感都没有。”  

“那是我们的哲学,我们信奉 Explicit is better than implicit。”  

“可是在调用的时候,怎么不把一个对象传给那个方法?你的self去哪里了?”

  1. p1 = Point(1,1) 
  2. p2 = Point(2,2) 
  3.  
  4. p1.distanceTo(p2) 
  5. p2.distanceTo(p1) 

 “你怎么不写成: distanceTo(p1,p2) ?” 

 “那不行,” Python说,“如果那样的话我们就不是面向对象了,而面向过程了。 ”

 “哼哼,” C老头儿在一旁冷笑一声,“说来说去,还不是披了一层面向对象的外衣,内部实现依然是面向过程的?!”  

“此话怎讲?” Java一直以正统的面向对象自居,不像Python, Ruby ,Java即使是想输出一个Hello World也得定义一个类不可。

 “就说你吧,Java小子,你的Java 源文件被编译以后变成了.class文件, 这个class文件被装载到了Java虚拟机的一个区域,这个区域叫什么?” C 老头儿出手不凡。 

 “当然是Method Area, 方法区了,这我会不知道?!”

 “对啊,它为什么叫方法区? 为什么不叫Class Area, 类区?”  C 老头儿真是别出心裁。  

“这…… ”  Java 语噻了,他从来就没有想过这个问题。

 “你的方法区是被各个线程所共享的,存储虚拟机加载类的信息,常量池,其中最主要的就是类中定义的方法相关的代码。 而你创建的对象呢,却是放在‘堆中’,虚拟机在执行的时候,要从方法区找到‘方法’,这些方法的字节码在运行的过程中,会操作位于堆中的对象。 ” 

 “所以你看,你的数据和方法是分离的,一个地方是方法(所以叫方法区),一个地方是数据,和我们C写出的程序是一样的,都是面向过程的!” C老头儿经过一系列证明后做了最终陈述。

Python也沉默了,他知道,自己在运行时也和这种方式差不多。

过了一会儿,Java 醒悟了过来:“不对,老头儿你这是混淆概念,我们是站在程序员的角度在谈论语言是不是面向对象的,而你则把我们拉到了实现层面,这是不对的。”  

Python也附和道:“对对,我们是面向对象的语言,抽象程度比你的面向过程要高!”

 “抽象? 哼哼,” C 老头儿又冷笑一声,“Linus 用C 写了Linux,用C 写了Git, 你觉得他没有做抽象? 笑话! 依我看来,抽象就是要在变化的东西中找到不变的东西,和具体的编程语言关系不大啊。”  C老头说了一句至理名言。

Java 悄悄对Python说: “老头儿主要做操作系统内核,操作系统中的那些虚拟内存,进程,线程,文件系统概念都很清晰, 并且很稳定,估计他没有接触到应用层变态的,不讲道理的业务逻辑。 ”  

C 老头儿说:“别以为你们面向对象有多么了不起,我告诉你,有很多程序员,用着面向对象的语言,写着面向过程的程序!关键是人!”  

Ruby 说:“两位兄台,算了,不和老头儿争论了,来看看我的this吧, 奥不, 是self, 我这里必须用self。 我的self 和你们的都不一样,在不同的位置表示不同的含义。比如说:”

  1. class Point 
  2.  
  3.     # 此处的Self 就是Point这个类 
  4.     puts "Self is :#{self}" 
  5.  
  6.     # 定义一个Class级别(静态)的方法,self还是Point这个类 
  7.     def self.name 
  8.         puts "Self inside class method is: #{self}"         
  9.     end 
  10.     # 定义一个实例方法, 此处的self 就是对象实例了 
  11.     def name 
  12.         puts "Self inside instance method is: #{self}"   
  13.     end 
  14. end 

Java 说:“你这搞得太麻烦了,定义一个静态方法,用static 不就结了?”  

半天都没有说话的JavaScript突然说道:“这也叫麻烦,来看看我是怎么处理this的!”

  1. function add(y){ 
  2.     return this.x + y 

熟悉面向对象的Java, Python看到这么古怪的代码,大为吃惊, 这是什么鬼? add函数中的这个this 到底指向谁? 

JavaScript说:“不要大惊小怪! 我的this和你们的this ,self都不一样,它是动态的,在定义时确定不了到底指向谁,只有等到函数调用的时候才能确定,this 指向的是最终调用它的那个对象,比如:” 

  1. function add(y){ 
  2.     //此时的this 指向的是全局的对象,在浏览器运行就是window 
  3.     return this.x + y 
  4.  
  5. x = 10 
  6. console.log(add(20)) 

在这里调用add函数的是全局上下文, 所以this指向的是全局对象,输出的值是30 。 

JavaScript说:“我还可以给add函数传递一个对象当作this。”  

  1. function add(y){ 
  2.     //此时的this 指向的是对象obj,this.x 是20 ,不是10 
  3.     return this.x + y 
  4.  
  5. x = 10 
  6.  
  7. var obj = {x: 20}; 
  8. //传递一个对象给add函数 
  9. add.call(obj,20)  // 40 

大家更加吃惊了。 

JavaScript又展示了一个例子: 

  1. var obj = { 
  2.     x:100, 
  3.     print:function(){ 
  4.        console.log(this.x);  
  5.     }     
  6.  
  7. obj.print() //100 

Python说: “这个很容易理解,这个this应该是指向obj这个对象实例, 所以print函数输出的x是100,对吧。” 

“对的,再来看一个:”

  1. var obj = { 
  2.     x:100, 
  3.     y:{ 
  4.         x : 200, 
  5.         print:function(){ 
  6.             console.log(this.x);  
  7.         } 
  8.     }         
  9. obj.y.print() //200 

Java 说道:“按照你的规则,这个this 指向的应该是最终调用它的对象,那就是y , 在y中,x是200,所以应该输出200 !” 

JavaScript说:“如果我把对象y中的x:200 给去掉,输出是什么? ” 

“难道是100 ? 不, 它不会向上一级去找,只会在y中寻找x 的值,如果没有,就是undefined, 唉!你这this规则实在是太麻烦。” 

 JavaScript笑了笑:“再来看个更古怪的例子:”

  1. var obj = { 
  2.     x:100, 
  3.     y:{ 
  4.         x : 200, 
  5.         print:function(){ 
  6.             console.log(this.x);  
  7.         } 
  8.     }         
  9.  
  10. var point ={x:15,y:15, f: obj.y.print} 
  11.  
  12. point.f() //输出什么? 
  13.  
  14. var x = 10 
  15. g = obj.y.print 
  16. g()  //输出什么? 

Python说:“这不还是一样嘛, 都应该输出200。”  

JavaScript说: “不,point.f() 应该输出15, 注意此时f 是对象point的一个函数,最终调用f 的是point对象,此时x = 15 了!   ”  

Java接口说:“我明白了,调用函数g()的是全局对象,x = 10 ,所以应该输出10 。” 

Python说:“你小子号称前端之王,就这么用this来折磨程序员?”  

JavaScript笑道:“其实吧,普通程序员直接操作this的机会也不太多,都被框架、类库封装好了!”

这时候就听到C老头儿在那里摇头晃脑: “简单就是美,简单就是美啊。你们这帮小子,把世界搞得这么复杂,让程序员们学习这么多不必要的复杂性,真是浪费生命啊。”  

“浪费生命? 没有我们这些语言,怎么可能创建出这么多Web应用程序出来? 你行吗?” 

“我是不行,我只知道你Java 虚拟机是用我C语言写的, 你Python解释器,Ruby解释器也是C语言写的, 就连JS的V8引擎也是用我的兄弟C++语言写的。” 

C 老头儿把手中的咖啡往桌子上狠狠一摔,转身就离开了咖啡馆。

【本文为51CTO专栏作者“刘欣”的原创稿件,转载请通过作者微信公众号coderising获取授权】

戳这里,看该作者更多好文

责任编辑:武晓燕 来源: 51CTO专栏
相关推荐

2017-02-06 15:43:52

2014-08-18 09:20:14

Android开放系统

2010-01-06 09:40:07

Ubuntu时间设置

2012-11-19 10:32:07

路由器ConsoleIP地址

2010-05-21 17:11:48

IIS窗口

2020-06-23 18:19:10

戴尔

2009-01-20 13:03:42

服务器虚拟化

2011-07-27 09:51:18

2013-01-06 09:26:06

Wi-Fi网络协议

2012-07-10 01:34:27

代码优化代码程序员

2018-07-13 16:09:03

数据中心审计物理设备

2010-09-07 15:31:53

数据中心

2010-05-20 14:50:46

IIS管理器

2019-03-05 10:03:17

阿里云云厂商硬盘

2024-07-01 09:23:39

2020-04-29 11:46:16

Actor多线程CPU

2016-09-06 09:45:43

华为HUAWEI CONN梯联网

2023-07-27 10:24:54

数字化转型NetOps

2020-04-29 22:46:04

线程Actor

2009-06-09 08:50:18

微软Windows 7操作系统
点赞
收藏

51CTO技术栈公众号