从Javascript构造函数调用成员函数

时间:2010-06-24 04:29:53

标签: javascript

我遇到了以下问题,这让我感到难过:

我有

function SystemList(UID)
{
  this.refreshData();
}

SystemList.prototype.refreshData = function()
{
  this.systemDataObj({}, $.proxy(this.readSuccess, this));
}

当我尝试运行它时,我收到以下错误:Uncaught TypeError:Object#在构造函数中没有方法'refreshData'。

任何人都知道为什么会失败?在我看来它看起来应该有效。

编辑:

我如何创建实例的示例:

function UserMiniProfile(UID)
{
  this.UID = UID;
  this.systemList = new SystemList(this.UID);
  this.htmlID = 'user-'+this.UID+'-profile';
}

2 个答案:

答案 0 :(得分:14)

我认为你可能遇到了如何以及何时发生函数声明与逐步代码(规范称为语句代码)的问题。

这样的代码将以您描述的方式失败,例如:

var obj = new Thingy("Fred");

function Thingy(name) {
    this.setName(name);
}

Thingy.prototype.setName = function(name) {
    this.name = name;
};

...因为您在将setName函数添加到原型之前调用构造函数。请注意,在声明之前调用构造函数就好了,这只是因为构造函数正在使用由语句代码设置以后的函数存在问题。 JavaScript解释器尝试处理该代码的顺序是:

  1. 创建函数Thingy并使其可用于范围。
  2. 执行var obj = ....行,调用构造函数。
  3. 执行构造函数的代码(在这种情况下抛出异常,因为没有this.setName函数)。
  4. 执行Thingy.prototype.setName = ...行。 (如果在最后一步没有抛出任何异常,那就是。)
  5. 这些步骤发生在每个脚本块中(首先完成函数声明,然后按顺序执行语句代码),即使上面的例子非常明显,当你开始把各个不同位置的片段放在一起时,你可以不那么明显地创造这种情况。

    显然,解决方案是确保在设置setName属性之前不构造对象:

    function Thingy(name) {
        this.setName(name);
    }
    
    Thingy.prototype.setName = function(name) {
        this.name = name;
    };
    
    var obj = new Thingy("Fred");
    

    ......而且,上述情况相当明显,但在现实世界中创造这些情况的可能性相对较小。

    我怀疑这是你案件中发生的事情。很容易证明:在Firefox,VS.Net或IE的脚本调试器,Chrome的DevTools等上使用类似Firebug的调试器,在SystemList.prototype.refreshData = ...线上设置断点,并在您所在的线路上设置断点做你的new SystemList(...),看看先执行哪一个。

    以下是一些展示此问题的小提琴:This one在构造函数中失败,this one成功。

答案 1 :(得分:0)

您需要先分配您的课程:

SystemList = function(UID)
{
  this.refreshData();
}

SystemList.prototype.refreshData = function()
{
  this.systemDataObj({}, $.proxy(this.readSuccess, this));
}