【问题标题】:JS and methods in class emulation类仿真中的 JS 和方法
【发布时间】:2012-12-18 17:49:55
【问题描述】:

我是新手,所以我会尽量详细。

我正在使用函数创建一个 JS 类。

function Bandstar(p, id)
{
  var numberOfSides, Xcenter, Ycenter;
  var canvas;
  var circlesInt;
  var linesInt;
  var lines;
  var linesInt2;
  var linesMidToEdge; 
.....

说到方法,我只是这样声明它们:

this.IAset = function(a) 
{
   for (var i =0; i<= this.numberOfSides-1;i++)
   {
      if (parseInt(a[i]) == a[i])
         this.circles[i].value = a[i];
      else
         return false;
    }

    this.IArepaint();
    return true
}

差不多就是这样。

现在的问题是,当我创建一个特定的方法时:

this.moveFunc = function(e)
{
   var p = e.target;
   this.IAmove(p);
};

IAmove 方法声明如下:

this.IAmove = function(p)
{
   var m = (p.oTop - this.Ycenter ) / (p.oLeft - this.Xcenter);
   var linea = m * ( p.left - p.oLeft) + p.oTop;
   var ejeX = p.left;
   ...
} 

编译器只是不断抛出这个错误:

Uncaught TypeError: Object function (e)   {     var p = e.target;     this.IAmove(p);   } has no method 'IAmove'

所以,问题是我将moveFunc 声明为一个函数,但是当我尝试使用this 属性时,它实际上并没有使用它上面的类的实例,(Bandstar ),但它本身(显然moveFunc 没有一个名为IAmove 的方法,它正在创建的类是)...

我认为这就像它一样有效,但我一定没有正确理解 JS 中的继承和类形态的概念。

如何从同一个类中的另一个方法访问一个类中的方法?如果我只写IAmove(p),它只会说方法IAmove() 是未定义的(因为它不是,它是Bandstar 命名空间的一部分。

我知道这一定是我没有看到的愚蠢的东西。有什么建议吗?

【问题讨论】:

    标签: javascript html oop


    【解决方案1】:

    函数内的上下文可能会根据您的调用而改变。所以this 不可能是原始对象。

    您应该添加一个私有变量,例如:

     function Bandstar(p, id)
    {
      var numberOfSides, Xcenter, Ycenter;
      var canvas;
      var that = this; // add this line
    

    当你尝试调用原始对象的函数(或获取属性)时使用它

    this.moveFunc = function(e)
      {
        var p = e.target;
        that.IAmove(p); // change this line
      };
    

    一定要指向原始对象。

    编辑:根据 cmets,您可以在 Stuart's answer 中阅读更多信息

    【讨论】:

    • ...原因是js中的函数是对象,所以函数中this的值其实就是函数本身
    • 我不得不说,这简直就是假信息。 this 只会在您执行 fn.fn = fn; fn.fn();fn.bind(fn); fn(); 时指向被调用的实际函数,否则它将是调用时附加到函数的对象或全局命名空间 window
    • 斯图尔特我不明白你的意思。我只能说,上面的伎俩奏效了。似乎是在js中,当你在另一个函数内部创建一个函数方法时,它们不会被该方法内部创建的其他函数继承......所以你只能访问不是函数的变量......这就是我我理解,即使它可能是错误的。
    • 很遗憾,虽然“技巧”奏效了,但什么都没学到,而且您在不了解 this 范围或对 JavaScript 中的对象构造有更丰富的了解的情况下离开了。
    • @StuartWakefield mmh.. 这不是虚假信息。但不完整。在 OP 情况下,上下文发生变化,没有任何其他规范。如果我理解您的评论,您想在其他各种情况下扩展信息吗?
    【解决方案2】:

    假设所有这些方法都在构造函数中定义语法是正确的。以下fiddle 说明了它的工作原理,代码基于您的代码的简化版本...

    function Test() {
        this.move = function(p) {
            document.write("Moved to: " + p);
        };
        this.another = function(e) {
            this.move(e.target);
        };
    }
    
    var test = new Test();
    test.another({target: "The moon"});
    

    问题的原因可能是两个三件事之一:

    1. 如何调用moveFunc方法
    2. 当方法moveFunc被调用时
    3. 如何调用 IAmove 方法(导致该错误的可能不是 moveFunc 函数)。

    this 关键字将引用函数的范围,该范围通常是方法的所有者...

    var bandstar = new Bandstar(p, id);
    bandstar.moveFunc(e); // this should be bandstar
    

    可能不是这种情况的唯一原因是,如果您将 moveFunc 函数显式绑定到另一个对象,或者更常见的情况是函数被调用而没有附加到所有者...

    var bandstar = new Bandstar(p, id);
    var moveFunc = bandstar.moveFunc(e);
    moveFunc(e); // this will now be window
    

    如果所有者与其分离,this 关键字将默认为 window。您可以使用绑定函数。

    var bandstar = new Bandstar(p, id);
    var moveFunc = bandstar.moveFunc(e);
    moveFunc.bind(bandstar);
    moveFunc(e); // this will now be bandstar again
    

    在第二个问题中,必须在构造函数中定义两个方法,然后才能调用 moveFunc 函数

    this.moveFunc = function(e) { ... }
    this.moveFunc(e); // Will throw an error that IAmove does not exist in the object
    this.IAmove = function(p) { ... }
    

    您可以使用console.log(this); 记录this 对象以找出它是什么。

    从您的错误看来,您尝试在 moveFunc 函数上调用 IAmove。要导致此错误,您需要调用moveFunc,并将其自身作为所有者或绑定对象......这不太可能。

    我有一种预感,错误可能实际上与假设的moveFunc 中的this.IAmove(p); 调用无关。 发布堆栈跟踪,我们可以使用它来查找错误发生的位置。

    【讨论】:

    • 我尝试了相反的方法,但它实际上并没有改变任何东西。我的意思是,我先声明了 IAmove,然后是 moveFunc,每当我使用 moveFunc 时,它仍然给我同样的错误。
    【解决方案3】:

    您可能希望将这些方法添加到您的Bandstar 原型

    function Bandstar(p, id)
    {
       // ...
    }
    
    Bandstar.prototype.IAset = function(a) 
    {
       // ...
    }
    
    Bandstar.prototype.moveFunc = function(e)
    {
       var p = e.target;
       this.IAmove(p);
    };
    

    这样,您的方法将保留 Bandstar 上下文,this 将保留 Bandstar 实例引用。

    看看Object.prototype reference

    【讨论】:

    • 使用它仍然会给我同样的错误。我想这只是因为我在函数内部而不是外部声明原型。但是我需要在函数内部和构造函数内部声明它们,因为我在创建事物之前使用了其中一个函数。
    • @JuanVilar 你也可以使用.call() 方法来改变函数的上下文,以防你觉得这样更合适。 @Chumkiu 回答也是保持实例引用的常用技巧。
    猜你喜欢
    • 2015-05-25
    • 2022-01-21
    • 2021-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-13
    • 2016-01-10
    相关资源
    最近更新 更多