简单的this,麻烦的this

栏目: Python · 发布时间: 7年前

内容简介:周末的Hello World咖啡馆总是热闹非凡。Java , Python, Ruby, JavaScript围坐在一起,一边喝咖啡,一边海阔天空。C老头儿则待在一旁,冷眼旁观。

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

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

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

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

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

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

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

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 问道。

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

Point p1 = new Point(1,1); 
Point p2 = new Point(2,2); 
 
// this 指向的是p1 
p1.distanceTo(p2);   
 
// this 指向的是p2 
p2.distanceTo(p1);   

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

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 说:“你不是一直用self吗,怎么现在是this?”

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

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

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

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

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文件, 这个class文件被装载到了Java虚拟机的一个区域,这个区域叫什么?” C 老头儿出手不凡。

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

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

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

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

简单的this,麻烦的this

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

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

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

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

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

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

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

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

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 说:“你这搞得太麻烦了,定义一个静态方法,用static 不就结了?”

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

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

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

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

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

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

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

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说: “这个很容易理解,这个this应该是指向obj这个对象实例, 所以print函数输出的x是100,对吧。”

“对的,再来看一个:”

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

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

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

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

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 是对象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 老头儿把手中的咖啡往桌子上狠狠一摔,转身就离开了咖啡馆。

简单的this,麻烦的this

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

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


以上所述就是小编给大家介绍的《简单的this,麻烦的this》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

JavaScript Patterns

JavaScript Patterns

Stoyan Stefanov / O'Reilly Media, Inc. / 2010-09-21 / USD 29.99

What's the best approach for developing an application with JavaScript? This book helps you answer that question with numerous JavaScript coding patterns and best practices. If you're an experienced d......一起来看看 《JavaScript Patterns》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试