3

未定義の変数のチェックを少し簡単にするために、小さなヘルパー メソッドをすぐに作成しました。

Object.prototype.is = function() {
   for(var i in arguments) {
       if(this === arguments[i]) {
           return true;
       }
   }
   return false;
};

次のように使用するように設計されています: foo.is(undefined, false)foo が未定義か false かをチェックします。私が使用したテストケースは次のとおりです。

var a = false;
a.is(false);
> false

少し混乱したので、もう少しいじってみました。一部の console.logging は、比較されている 2 つのオブジェクトが同じではないため、同等性チェックが失敗していることを明らかにしました。

Boolean {is: function} === false
> false

そのため、曽祖父の Object.prototype からメソッドをa継承していましたが、比較内では継承していませんでした。isfalse

オブジェクトの新しいインスタンスを確実に作成するusing を使用して継承を強制できると考えましnew Boolean(false)た (オブジェクトのプロトタイプが拡張される前に作成されたオブジェクトへの参照で発生する可能性のあるリスクを回避できることを願っています)。結果:

Boolean {is: function} === Boolean {is: function}
> false

等価性チェックが失敗するのはなぜですか?

ここで何が起こっているのかを解明するプロセスの一環として、単一のブール値を引数として関数が呼び出された後に引数配列を調べたところ、長さが 2 であり、余分な引数が次のis関数であることがわかりました。 Object.prototype 内で宣言されました。

a.is(false);
arguments -> [false, is: function]

それはどうやってそこに行き着いたのですか?

参考までに、このようなサルパッチは悪い考えだと私は知っています! これは製品コードではありません。興味があるだけです。

4

1 に答える 1

5

どうしたの?

thisこれは、値がオブジェクトに強制されている場合のもう 1 つの問題です。モンキー パッチを'use strict'関数の先頭に追加すると、この強制が発生しなくなります。ただし、古いブラウザはこのディレクティブを認識しない場合があります。

関数が厳密でない場合、基本的に次のようになります。

var a = false;
Object.prototype.is.call(Object(a), undefined, false);

aを ( を呼び出して) オブジェクトに変換すると、Object(a)ブール値とは異なるブール オブジェクトになります。たとえば、次のようにします。

false === new Boolean(false); // false

また、オブジェクトが等しいのは、同じオブジェクトを参照している場合のみです。

new Boolean(false) === new Boolean(false); // false
var test = new Boolean(false);
test === test; // true, they are the same object

発生するもう 1 つの問題は、is()関数がnull(厳密ではない) で呼び出されると失敗することです。

Object.prototype.is.call(null, null); // becomes window === null (false)

これについて何ができますか?

これを厳密な関数にする代わりに、両方のオブジェクト値を比較することが含まれます (ただし、これによりnew Boolean(false).is(false)new Boolean(false).is(new Boolean(false))が true になり、意図しない可能性があります。

あなたが取ることができる別の代替手段は、それを非プロトタイプ関数にすることです。つまり、Object.is代わりに次のようなものにすることです(ただし、ES6 はObject.is、あなたのものとは異なる動作をするネイティブ関数を定義する可能性があることに注意してください)。

Object.oneIsEqual = function (arg, compare)
{   for(var i = 0; i < compare.length; ++i) if (arg === compare[i]) return true;
    return false;
};

編集に関する注意:

ループで元の関数を取得していた理由はfor-in、プロトタイプで定義したためであり、列挙可能です (詳細については後述します)。

オブジェクトにはのargumentsプロトタイプがありObject.prototype、 でis関数にアクセスできますarguments

Object.prototype.is = function() {
   for(var i in arguments) {
       if(this === arguments[i]) {
           return true;
       }
   }
   return false;
};
(function () { return arguments.is; })(); // is the same function as to Object.prototype.is

デフォルトでは (「通常」に定義した場合)、すべてのプロパティ (オブジェクト上またはプロトタイプ チェーン上にあるもの) が列挙可能になります。つまり、for-inループやその他の同様の構造で表示できます。ただし、これは (ほとんどの場合) 望ましい動作ではありません。ほとんどのネイティブ プロトタイプ関数は列挙できません。これを回避するには、プロパティではなく、関数のインデックスを実行する必要があります。

for (var i = 0; i < arguments.length; ++i) // code here
于 2013-11-07T04:23:32.153 に答える