2

高度なブラウザー機能を検出する自己完結型の JavaScript ユーティリティ オブジェクトを作成しています。理想的には、私のオブジェクトは次のようになります。

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

私が現在抱えている問題は、dataURI サポートを検出するWeston Ruter のサイトから採用しているコードを扱っています。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
    }        
};

しかし、それは本当にあなたが望んでいることではないと思います。値ではなく、プロパティを参照しようとしているようです。この場合、答えは「いいえ」です。JavaScriptメソッドには、保存されているプロパティを知る方法がありません。実際、複数のプロパティに同時に保存できます。例えば:

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

ここでSupportは、両方が同じメソッドを指す2つのプロパティがあります。ただし、メソッド自体には、どの参照が呼び出されたかを知る方法がありません。また、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==";

};

onloadただし、覚えておいてください。ソースを設定したときに、ハンドラーが同期して(すぐに)起動するという保証はまだありません(少なくとも私が知っていることonerrorです)。実際、それらが起動しないという保証さえあるかもしれません。したがって、Supportオブジェクトにコールバックを追加し、設定されたらそれを実行する可能性がありますdataURIonload次に、または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

関数内で this の代わりに prop を使用する必要があると思います。(これを引数 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 に答える