【问题标题】:In most OOP Languages, does "i" in an instance method refer first to local, and then to global, but never to an instance variable or class variable?在大多数 OOP 语言中,实例方法中的“i”是否首先指代本地,然后指代全局,但从不指代实例变量或类变量?
【发布时间】:2011-02-16 07:15:51
【问题描述】:

在以下代码中:

    <script type="text/javascript">

        var i = 10;

        function Circle(radius) {
            this.r = radius;
            this.i = radius;
        }

        Circle.i = 123;

        Circle.prototype.area = function() { alert(i); }

        var c = new Circle(1);
        var a = c.area();

    </script>

什么被警告?答案在这个问题的末尾。

我发现警报调用中的i 要么是指任何本地(如果有),要么是全局变量。即使没有定义局部变量和全局变量,它也不可能是实例变量或类变量。要引用实例变量i,我们需要this.i,而要引用类变量i,我们需要Circle.i。这对几乎所有面向对象的编程语言来说都是真的吗?有什么例外吗?有没有局部没有全局的情况下,先查找实例变量,再查找类变量作用域? (或者在这种情况下,那些称为范围?)

答案是:10 正在收到警报。

【问题讨论】:

  • wiki,因为它可能涉及不同的语言,可能会有不同的人提到的一些不同的案例
  • 这显然是您的 JavaScript 中的错误。
  • 这非常特定于 Javascript(或类似语言),与“大多数面向对象的语言”关系不大。
  • @deceze 在其他一些语言中会有什么不同?
  • 在基于类(C/Java 风格)的面向对象语言中,不能在类定义之外定义实例方法(为“实际情况做好准备”... ;)),因此它们的范围是明确限于它们所属的类/对象。基于原型的面向对象语言的工作方式大不相同,因为可以将方法从对象外部的范围附加到对象(就像您正在做的那样)。

标签: javascript oop instance-variables class-variables


【解决方案1】:

你看到的是一个闭包。

http://www.jibbering.com/faq/faq_notes/closures.html

如果你想要 this.i 或 Circle.i,你必须明确引用它们。

就像在 Python(self.x 和 cls.x)中一样,Javascript 没有实例或类/原型属性的语法糖。

【讨论】:

  • 是闭包吗?没有函数与作用域链一起创建。我认为闭包总是一个函数和一个作用域链?
  • 哦,对不起,它还在我的咖啡里 :-)
  • 等一下...再想一想,“Circle.prototype.area = function() { alert(i); }”这行实际上将函数引用分配给左侧,所以,创建一个函数,其作用域链包含全局作用域。所以实际上创建了一个闭包。只是作用域链没有本地作用域,因为没有调用任何函数,所以没有添加新作用域。
【解决方案2】:

在一般的面向对象编程语言中,实例变量(顾名思义)只能通过类的实例来访问(静态变量除外,可以通过类名访问)。因此,当您想要引用一个实例变量时,您需要拥有该类的对象(实例)。

【讨论】:

  • 我说的是在类外访问实例变量,而不是在类内。不好意思,忘了说
【解决方案3】:

要引用实例变量,您必须使用this.iCircle.i 指的是 Circle 构造函数上的静态属性——它不会影响 Circle 的实例。

【讨论】:

    【解决方案4】:

    不,那不是真的。

    大多数语言都允许您访问实例变量,而无需使用 this.i 之类的东西来指定它是一个实例变量。

    真正面向对象的语言,如 Java、C# 和 VB (7+),甚至根本没有任何全局变量。

    Javascript 并不是真正的面向对象语言,它是一种对面向对象支持有限的过程语言。由于它没有类,也就没有类范围,所以需要使用this关键字来指定对象范围。

    【讨论】:

    • Javascript 是一种了不起的面向对象语言!它只是不是一个基于类的 面向对象的语言。 :)
    • Javascript 使用原型而不是经典类。因此,虽然它不能在 Java/C++ 意义上被称为面向对象,但在有限的对象支持下将其称为过程是不正确的。
    • 引用 Doug Crockford “JavaScript 是无类的。它使用原型。[...] Java 不够强大,您可以用 Java 中的 JavaScript 样式编写;它还不够好。JavaScript 是,所以你可以反过来做,因为它是模型中更强大的。” developer.yahoo.com/yui/theater/video.php?v=crockonjs-2
    • @deceze:仅仅因为它支持面向对象并不能使它成为一种面向对象的语言。您可以使用任何语言进行面向对象编程,即使它不支持它。我什至在汇编器中做了一些...
    • @ymv:有什么不对的地方? Javascript 中对面向对象的支持确实受到限制。例如没有继承,这是 OOP 的基石之一。
    【解决方案5】:

    看:

    var i = 10;
    
    function Circle(radius) {
                var i = radius || 0;
                this.r = i;
                this.i = radius;
                this.toString = function(){ return i; };
            }    
    var nwCircle = new Circle(45);
    
    alert(nwCircle.r); //=>45;
    alert(nwCircle); //=>45 (toString found local i);
    alert(i); //=>10
    

    现在,在 Circle 构造函数中,您为(本地,属于对象本身)变量 i 创建了一个闭包。全局定义的i 不受影响。因此,在 javascript 中,这取决于您定义变量的位置。至少在 javascript 中,对i 进行自下而上的搜索(从本地范围到全局范围)并使用找到的第一个。因此,如果Circle 构造函数不包含名为i 的变量,则将使用全局i

    【讨论】:

      猜你喜欢
      • 2013-05-06
      • 1970-01-01
      • 1970-01-01
      • 2011-05-03
      • 2011-07-17
      • 1970-01-01
      • 1970-01-01
      • 2012-08-23
      • 2014-05-18
      相关资源
      最近更新 更多