简单的this,麻烦的this

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

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

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

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

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

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

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

public class Point {
    private double x = 0.0;
    private double y = 0.0;
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

   public double distanceTo(Point that) {
        double dx = this.x - that.x;
        double dy = this.y - that.y;
        return Math.sqrt(dx*dx + dy*dy);
    }
}

 

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

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

Point p1 = new Point(1,1);
Point p2 = new Point(2,2);

// this 指向的是p1
p1.distanceTo(p2);  

// this 指向的是p2
p2.distanceTo(p1); 

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

class Point:
    def __init__(this, x, y):
        this.x = x
        this.y = y
    def distanceTo(this,point):
        dx = this.x - point.x
        dy = this.y - point.y
        return math.sqrt(dx**2+dy**2)

Java说:“你不是一直用自我,怎么现在是这个?” 

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

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

“那是我们的哲学,我们信奉明确胜过隐含。”  

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

p1 = Point(1,1)
p2 = Point(2,2)

p1.distanceTo(p2)
p2.distanceTo(p1)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 

class Point

    # 此处的Self 就是Point这个类
    puts "Self is :#{self}"

    # 定义一个Class级别(静态)的方法,self还是Point这个类
    def self.name
        puts "Self inside class method is: #{self}"        
    end
    # 定义一个实例方法, 此处的self 就是对象实例了
    def name
        puts "Self inside instance method is: #{self}"  
    end
end

 

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

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

 

function add(y){
    return this.x + y
}

 

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

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

 

function add(y){
    //此时的this 指向的是全局的对象,在浏览器运行就是window
    return this.x + y
}

x = 10
console.log(add(20))

 

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

JavaScript的说:“我还可以给添加函数传递一个对象当作这一点。”  

function add(y){
    //此时的this 指向的是对象obj,this.x 是20 ,不是10
    return this.x + y
}

x = 10

var obj = {x: 20};
//传递一个对象给add函数
add.call(obj,20)  // 40

 

大家更加吃惊了。 

JavaScript的又展示了一个例子: 

 

var obj = {
    x:100,
    print:function(){
       console.log(this.x); 
    }    
}

obj.print() //100

 

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

“对的,再来看一个:”

var obj = {
    x:100,
    y:{
        x : 200,
        print:function(){
            console.log(this.x); 
        }
    }        
}
obj.y.print() //200

 

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

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

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

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

var obj = {
    x:100,
    y:{
        x : 200,
        print:function(){
            console.log(this.x); 
        }
    }        
}

var point ={x:15,y:15, f: obj.y.print}

point.f() //输出什么?

var x = 10
g = obj.y.print
g()  //输出什么?

 

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

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

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

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

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

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

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

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

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

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值