通过异步回调设置对象文字属性值。

时间:2010-12-23 20:17:15

标签: javascript object-literal

我正在创建一个自包含的javascript实用程序对象,可以检测高级浏览器功能。理想情况下,我的对象看起来像这样:

Support = {
    borderRadius : false, // values returned by functions
    gradient     : false, // i am defining 
    dataURI      : true
};

我目前的问题涉及一些我正在调整Weston Ruter's site的代码来检测dataURI支持。它尝试使用javascript来创建具有dataURI源的图像,并使用onload / onerror回调来检查宽度/高度。由于onload是异步的,我丢失了我的范围,返回true / false并没有为我的对象分配true / false。

这是我的尝试:

Support = {
    ...
    dataURI : function(prop) {
        prop = prop; // keeps in closure for callback
        var data = new Image();
        data.onload = data.onerror = function(){
            if(this.width != 1 || this.height != 1) {
                prop = false;
            }
            prop = true;
        }
        data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
        return -1;
    }(this)
};

我正在立即执行匿名函数,传递它(我希望它是对Support.dataURI的引用),但不幸的是引用了window对象 - 所以值总是-1。我可以通过使用外部定义的函数在创建Support对象后分配值来使其工作......但我不认为它是那么干净。有没有办法让它自成一体?对象文字的函数可以引用它所分配的属性吗?

编辑 -----------------------------------
不完全是我的问题的答案(如措辞)所以我不会发布额外的答案,但是......我决定使用单例对象而不是对象文字。这是工作代码:

Support = new function Support() {
    var that = this;
    this.dataURI = function() {
        var data = new Image();
        data.onload = data.onerror = function(){
            if(this.width != 1 || this.height != 1) {
                that.dataURI = false;
            } else {
                that.dataURI = true;
            }            
        }
        data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
        return that.dataURI;
    }();
};

3 个答案:

答案 0 :(得分:3)

  

对象文字的函数能否引用它所分配的属性?

是的,它可以。每个函数都有一个本地arguments变量,该变量具有引用被调用函数的callee属性。因此,如果您想引用Support.dataURI,您只需使用它:

var Support = {
    ...
    dataURI: function(prop)
    {
        // Do whatever here with arguments.callee
    }        
};

但是,我认为这不是你想要的。看起来您正在尝试引用属性 name ,而不是值 - 在这种情况下您的答案是否定的。 JavaScript方法无法知道它存储在哪些属性中;实际上它可以同时存储在多个属性中。例如:

var Support = {
    ...
    dataURI: function(prop)
    {
    }        
};
Support.somethingElse = Support.dataURI;

这里,Support有两个属性都指向同一个方法。然而,该方法本身无法知道调用哪个引用。由于尚未声明Support对象,因此无法引用它。

实际上(虽然你问“对象文字的函数[可以]引用它被分配给的属性”),但该函数甚至不存储在对象上:它的结果是。因此,该方法本身不会以任何方式与Support相关联。

我担心你能做到最好的声明对象,然后设置它的dataURI属性。


响应您的编辑

首先,在“功能”之前不需要“new”关键字。不过,我不知道这在任何浏览器中都能起作用。如果简化它,代码的第3-14行的形式为`this.dataURI = fn();'。以下是这样的声明的工作原理:

  1. 该值由执行fn()
  2. 确定
  3. 该值已分配给dataURI属性。
  4. fn()正在执行时,dataURI尚未分配,因此无法访问其(正确)值以返回它。

    此外,您有一个(至少可能的)异步进程(等待映像加载或错误),因此该值甚至不会被回调设置。基本上,您尝试将异步进程(onload事件)包装在同步进程(函数调用)中。

    最后,您无需在此处创建和执行函数。摆脱它:

    var Support = function() {
        var that = this;
    
        var data = new Image();
        data.onload = data.onerror = function(){
            if(this.width != 1 || this.height != 1) {
                that.dataURI = false;
            } else {
                that.dataURI = true;
            }            
        }
        data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
    
    };
    

    但请记住:仍然无法保证(至少我知道)onloadonerror处理程序会在您设置源时同步(立即)启动 - 事实上,可能甚至可以保证他们不会!因此,您可能会向Support对象添加回调,并在设置dataURI后执行。但是,您必须防止同步执行onloadonerror 的可能性。这样的事情应该有效:

    var Support = function() {
        var that = this;
    
        this.getDataURI = function()
        {
            var data = new Image();
            data.onload = data.onerror = function(){
                if(this.width != 1 || this.height != 1) {
                    that.dataURI = false;
                } else {
                    that.dataURI = true;
                }
                if (that.onDataURI)
                    that.onDataURI();
            }
            data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
        }
    };
    
    var mySupport = new Support();
    mySupport.onDataURI = function() { alert(mySupport.dataURI); }
    mySupport.getDataURI();
    

答案 1 :(得分:2)

在声明对象时无法引用对象。

相反,您需要在声明对象后调用您的函数:

var Support = { 
    ...
};

(function() {
    var data = new Image();
    data.onload = data.onerror = function(){
        Support.dataURI = this.width === 1 && this.height === 1;
    };
    data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
})();

答案 2 :(得分:0)

我猜你应该在你的函数中使用prop而不是this。 (你调用函数传递它作为参数prop的参数 - 但在你使用“this”的函数中?)。

dataURI : function(prop) {
    var data = new Image();
    data.onload = data.onerror = function(){
        if(prop.width != 1 || prop.height != 1) {
            that = false;
        }
        that = true;
    }
    data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
    return -1;
}(this);