【问题标题】:JQuery AJAX and OOP JS Scope WoesJQuery AJAX 和 OOP JS 范围问题
【发布时间】:2012-08-12 02:30:01
【问题描述】:

因此,我创建了一个对象,该对象在初始化阶段进行 AJAX 调用以填充其属性。但是,我遇到了一个非常奇怪的行为:我可以在 $.ajax() 范围内打印并查看属性值,但是任何返回属性值的公共方法的返回值都是“未定义”。

JS 代码如下所示:

function MyFunction() {
   this.myProperty;
   this.init();
}

Myfunction.prototype.getPropertyValue = function () {
    alert(this.myProperty); // returns 'undefined'
}

Myfunction.prototype.init = function () { 
   $.ajax({
      type: 'get',
      url: "getProperty.php",
      dataType: "json",
      success: function(response) {
         this.myProperty = response[0].Property;
         alert(this.myProperty) // returns 'Property Name'
      }
   });
}

我的想法是在 $.ajax() 范围内,“this”实际上指的是其他东西。那么,我的问题是如何确保设置了“this.myProperty”并且一旦超出 AJAX 范围就不会失去其价值?

非常感谢任何帮助。

【问题讨论】:

    标签: javascript jquery ajax oop scope


    【解决方案1】:

    由于您建立价值的方式,您得到“未定义”的部分原因:

    var MyFunction = function () {
       this.myProperty;
       alert(this.myProperty); // undefined!
       this.init();
    };
    

    当您声明属性(或变量)而不指定值时,它们默认为“未定义”。而是:

    var MyFunction = function () {
       this.myProperty = false;
       alert(this.myProperty); // false
       this.init();
    };
    

    开始 ajax 调用。您是对的,回调的范围与对象不同。 this,在 ajax 成功函数中,指的是 jQuery 包装的 XHR 对象。当您调用this.myProperty = response[0].Property 时,您实际上是在 ajax 对象上创建一个新属性并设置 值。要更正此问题,您可以使用 jQuery ajax 对象的 context 选项,或者使用 javascript bind 方法绑定回调函数:

      success: function(response) {
         this.myProperty = response[0].Property;
      }.bind(this)
    

    ... 或:

       $.ajax({
          type: 'get',
          url: "getProperty.php",
          dataType: "json",
          context: this,
          success: function(response) {
             this.myProperty = response[0].Property;
          }
       });
    

    在这里试试:http://jsfiddle.net/SnLmu/

    文档

    【讨论】:

    • 那我该如何处理竞态条件呢?因为现在,该值为“假”(这是有道理的)。有没有办法强制 AJAX 调用同步运行? (据我所知,自 1.8 以来,async:false 已被弃用)
    • @steacha Javascript 不是多线程的,并且缺少 sleep 函数,因此“同步”调用仅意味着您阻塞直到完成。 javascript 中的阻塞是最糟糕的阻塞方式——UI 将被锁定并且页面无响应。如果您的阻塞循环太紧(例如while(!$condition) { continue; }),您甚至可能触发“此脚本执行时间过长”警告。您应该改用回调函数——由于这个限制,对象构造函数中的 ajax 调用可能不是构建类的最可靠方法。
    • @steacha 请参阅:hunlock.com/blogs/Snippets:_Synchronous_AJAX 获取想法,但您会看到他提到 UI 将被阻止。另请参阅 XMLHttpRequest 的文档 - developer.mozilla.org/en-US/docs/DOM/… - 您可以指定您的请求应该是同步的,只是不使用 jQuery 的 ajax()
    • 下面建议的类似adeno的回调函数?
    • (仅供参考,每次加载页面时,“above”和“below”都会发生变化,当答案具有相同的投票计数时)adeno 的建议路线是您可以解决问题的几种方法之一,具体取决于关于你将如何使用课程。如果您想尽快调用getPropertyValue 方法,可以将其放入success 回调中,或者将其作为构造函数参数传递,或者将其设置在计时器上......有很多方法,具体取决于关于你将如何使用这个类。就 adeneo 的解决方案而言,它确实基于猜测做出了假设。你没有给出任何上下文。
    【解决方案2】:

    部分问题在于 ajax 是异步的,因此当您尝试访问它们时可能无法设置属性(竞争条件)。另一个是ajax调用内部this的值不是Myfunction。您可以通过以下方式修复:

    Myfunction.prototype.init = function () { 
       var that = this;
       $.ajax({
          type: 'get',
          url: "getProperty.php",
          dataType: "json",
          success: function(response) {
             that.myProperty = response[0].Property;
             alert(that.myProperty) // returns 'Property Name'
          }
       });
    }
    

    或者您可以在 ajax 调用中使用context 设置。根据site

    这个对象将成为所有 Ajax 相关回调的上下文。经过 默认情况下,上下文是表示 ajax 设置的对象 在调用中使用($.ajaxSettings 与传递给的设置合并 $.ajax)。例如,指定一个 DOM 元素作为上下文将 将其作为请求完整回调的上下文,如下所示:

    Myfunction.prototype.init = function () { 
           var that = this;
           $.ajax({
              type: 'get',
              url: "getProperty.php",
              dataType: "json",
              context: Myfunction,
              success: function(response) {
                 this.myProperty = response[0].Property;
                 alert(this.myProperty) // returns 'Property Name'
              }
           });
        }
    

    【讨论】:

      【解决方案3】:
      var MyFunction = {
          myProperty: null,
          init: function() {
              var self = this;
              self.ajax(function(response) {
                  self.myProperty = response;
                  self.secondfunction(self.myProperty); //call next step only when ajax is complete
              });
          },
          ajax: function(callback) {
              $.ajax({
                  type: 'get',
                  url: "getProperty.php",
                  dataType: "json"
              }).done(function(response) {
                  callback(response[0].Property);
              });
          },
          secondfunction: function(prop) {
              alert(prop);
          }
      }
      
      $(function() {    
          MyFunction.init();
      });
      

      【讨论】:

      • 请注意:此对象不等同于 OP 代码中的对象。两者都是完全有效的方法,并且根据用例,任何一种都可能是合适的。这是一个对象字面量,问题代码显示了一个基于原型的对象。
      • @chris - 你当然是对的,这不是基于原型的答案,我确实开始用原型输入一些东西,但是基于 init() 函数的设置方式和 ajax调用最有可能需要回调,看起来对象文字会更合适,这就是我会这样做的方式,所以我决定展示如何这样做?
      猜你喜欢
      • 1970-01-01
      • 2015-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多