【问题标题】:property initialization in JavaScript [closed]JavaScript中的属性初始化[关闭]
【发布时间】:2012-12-15 15:50:22
【问题描述】:

我在 JavaScript 中创建了一个这样的类:

var Test = function(){
    this.element = null;
    this.init = function() {
        if(Test.html == "") {
            Test.loadHtml(this);
            return;
        }
        this.initElements();
        this.someMethodInternalCall();
    };
    this.initElements = function() {
        // append the loaded html to body
        // etc...
        this.element = $("some-element-contained-in-loaded-html-apended-to-body");
    }
    this.someMethodInternalCall = function() {
        this.element.css({some:style}); // works in this place
    }
    this.someMethodExternalCall = function() {
        this.element.css({some:style}); // dosn't work in this place
        // I mean here this.element is null. WHY?
    }
};
Test.html = "";
Test.loadHtml = function() {
    // load html content by an ajax request (jQuery $.ajax method)
    // and put it in Test.html
    // then recall the Test.init ethod
    return function(caller) {
        Test.html = // load html by ajax... etc...
        caller.init();
    };
}();

function someUsage(){
    var t = new Test();
    t.init();
    t.element.css({some:style}); // error: t.element is null WHY?
    t.someMethodExternalCall(); // error: this.element is null WHY?
}

如您所见,我在上面的代码中进行了解释。为什么我们在初始化后设置属性时,它只是在内部调用中生效?如何创建可以更改其值的属性?

更新:

看来我得解释一下我的代码了。问题是关于element 属性,而不是Test.html 也不是Test.loadHtml 方法或调用它。 Test.loadHtml 被立即触发(你可以测试它),Test.html 获取加载的 html,加载的 html 被附加到 body 等等。这是一个 JavaScript 模式(我忘了它的名字是什么)并且可以正常工作。唯一错误的是关于属性初始化 -element

【问题讨论】:

  • 你的代码是什么? Test.html = ""; 每当执行脚本时,Test.html 将等于 NULL...
  • 问题与Test.html 无关。大约是element
  • caller 不是undefined。请测试代码。直到第二次调用element
  • @apsillers +1 是的,在这个问题之后我明白了这一点。但问题是如何处理?我试过var self = this;self 而不是this 工作,但问题存在
  • 如果您可以在jsfiddle.net 之类的网站上发布您的代码的工作示例,将会非常有帮助。您当前的代码不起作用(例如,有一些伪代码并且您使用 Text.loadHtml 而不是 Test.loadHtml),因此很难解决您的问题。

标签: javascript oop class properties


【解决方案1】:

问题是异步性。当您要通过 AJAX 加载 HTML 时,其余功能将继续...

function someUsage(){
  var t = new Test();
  t.init();
  // The following carries on whilst the request is loading it does not wait
  t.element.css({some:style}); // This is why I am null
  t.someMethodExternalCall(); // This is why I am also null
}

要解决这个问题,您可以使用回调...

function someUsage(){
  var t = new Test();
  t.init(function() {
    // I do not continue until the loadHtml request has completed
    t.element.css({some:style}); // I am not null anymore
    t.someMethodExternalCall(); // I am not null anymore
  });
}

你需要修改你的 init 函数和你的 loadHtml 函数来调用回调而不是调用者对象的 init 方法,init 函数...

this.init = function(callback) {

  // Using blank Test.html to determine whether the html has been loaded
  if(Test.html == "") {
    var me = this;

    // Call loadHtml with a callback function
    Text.loadHtml(function() {

      // I want to keep the this reference to the object and callback argument
      me.init(callback);
    });

  // It is loaded so continue set up and then trigger the callback
  } else {
    this.initElements();
    this.someMethodInternalCall();
    callback();
  }
};

如果您创建了许多这样的 Test 类,仍然会导致问题,因为每个类都会在其他类加载时尝试获取 HTML。

要解决这个问题,您只需要在第一次调用时设置一个标志。任何后续调用都将被忽略,但会记录回调以在 HTML 完成加载时调用...

Test.loadHtml = function(callback) {

  // If already loading roll up callbacks
  if(Test.loading) {

    // Callback becomes a function that calls the original callback function 
    // and then the new one
    Test.callback = (function(original) {
      return function() {
        original();
        callback();
      }
    }) (Test.callback);

  // First time it has been called set the flag to prevent multiple loads 
  // and add the callback
  } else {
    Test.loading = true;
    Test.callback = callback;

    // Added to illustrate the AJAX callback functionality
    ajax("html", function(response) {
      Test.html = response;
      Test.callback();
    });
  }
}();

首选方法是在实例化时强制执行对象有效性,这可以防止这些竞争条件。如果无法有效地构造类,则会引发错误,这会从类中移动围绕操作顺序的复杂性。正如您在下面看到的那样,它并不那么漂亮,您必须自己调用加载步骤(或让其他东西触发它)。

new Test(); // Errors not loaded!
// We must perform the load step to use the class
Test.load(function() {
  new Test(); // Works!
});

更优雅的解决方案,尤其是对于大型应用程序,涉及管理对类的访问。您必须先执行加载步骤才能访问该类,这会强制加载始终在类实例化之前完成。

// views is some object managing the loading of view classes when asked for
// one or more views it will load the required HTML and return the class(es)
// so we can create instances...
views.load("Test", function(Test) {
  var t = new Test();
  t.element.css({some: style});
  t.someMethodExternalCall();
});

【讨论】:

  • +1 并接受非常感谢。欢呼
  • 没有问题,很高兴它有帮助
【解决方案2】:

你在loadHtml的ajax函数的回调中做caller.init();吗?

如果没有,您的 init 函数将在加载 html 之前添加到执行堆栈(这就是为什么 this.element 为空)

Test.loadHtml = function() {
    // load html content by an ajax request (jQuery $.ajax method)
    // and put it in Test.html
    // then recall the Test.init ethod
    return function(caller) {
      $.ajax({
        url: 'somethinghere',
        success: function(data) {
            Test.html = data;
            caller.init();
        }
      });
    };

【讨论】:

    猜你喜欢
    • 2023-03-24
    • 2013-10-28
    • 1970-01-01
    • 1970-01-01
    • 2015-12-20
    • 2019-01-25
    • 1970-01-01
    • 2017-06-19
    • 1970-01-01
    相关资源
    最近更新 更多