2

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

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

我当前的问题涉及我从Weston Ruter 的站点改编的一些代码,该站点检测到 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 的引用),但不幸的是引用了窗口对象——所以值总是-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;
    }();
};
4

3 回答 3

3

对象字面量的函数可以引用它分配给的属性吗?

是的,它可以。每个函数都有一个局部参数变量,该变量具有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属性。


回应您的编辑

首先,“function”之前不需要“new”关键字。不过,我看不出这在任何浏览器中如何工作。如果简化它,代码的第 3-14 行的格式为“this.dataURI = fn();”。以下是这样的语句的工作原理:

  1. 该值是通过执行来确定的fn()
  2. 该值被分配给dataURI属性。

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。但是,您必须防范onloador同步执行的onerror 可能性。像这样的东西应该工作:

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();
于 2010-12-23T21:33:05.033 回答
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==";
})();
于 2010-12-23T20:20:25.477 回答
0

我想你应该在你的函数中使用 prop 而不是 this 。(您调用将 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);
于 2010-12-23T20:50:05.833 回答