我正在创建一个自包含的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;
}();
};
答案 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();'。以下是这样的声明的工作原理:
fn()
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==";
};
但请记住:仍然无法保证(至少我知道)onload
和onerror
处理程序会在您设置源时同步(立即)启动 - 事实上,可能甚至可以保证他们不会!因此,您可能会向Support
对象添加回调,并在设置dataURI
后执行。但是,您必须防止同步执行onload
或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();
答案 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);