ソースコードの解釈に下線を引く:JSで2つの要素が「同じ」かどうかを判断する方法

アンダースコアを付ける理由

最近、underscore.jsのソースコードを調べ始め、underscore.jsのソースコードの解釈を2016年の計画に入れました。

いくつかの有名なフレームワークライブラリのソースコードを読むことは、マスターと話すようなものであり、多くのことを学びます。なぜアンダースコアなのですか?主な理由は、アンダースコアが短く簡潔(約1.5k行)で、100以上の便利なメソッドをカプセル化し、結合が少なく、メソッドごとの読み取りに非常に適しており、元のポスターのようなJavaScript初心者に適しているためです。そこから、未定義の書き換えを回避するために未定義の代わりにvoid 0を使用するなどのいくつかのトリックだけでなく、変数タイプの判断、関数のスロットリングと関数のデバウンス、および多くのブラウザーの互換性などの一般的な方法も学ぶことができます。ハック、あなたはまた、作者の全体的なデザインのアイデアとAPIデザインの原則(後方互換性)を学ぶことができます。

後で、ホストはソースコードの読み取りで学んだ知識をあなたと共有するために一連の記事を書きます。

ウォッチへようこそ〜(興味があれば、スター&ウォッチを歓迎します〜)あなたの注意は、ホストが書き続ける動機です

_.isEqual

この記事では、JavaScriptで2つのパラメーターが「同じ」であると判断する方法、つまり、下線付きのソースコードの_.isEqualメソッドについて説明します。この方法は、アンダースコアのソースコードに実装するのに最も複雑な方法(100行以上かかった)と言えますが、ほとんどありません。

では、「同じ」とはどういう意味ですか?たとえば、1と新しいNumber(1)は等しいと見なされ、[1]と[1]は等しいと見なされます(ただし、それらの参照は同じではありません)。もちろん、同じ参照を持つ2つのオブジェクトは等しくなければなりません。 。

では、この_.isEqual関数をどのように設計するのでしょうか。下線付きのソースコードに従い、その実装を段階的に見ていきます。以下のテキストでは、比較される2つのパラメータがaとbであると想定しています。

まず、a === bが真であると判断します.2つのケースがあります.1つはaとbが基本タイプであり、2つの基本タイプの値は同じであり、もう1つは2つの参照タイプであるため、これらは参照タイプです。参照は同じです。それで、a === bが真である場合、それはaとbが等しいことを意味しますか?実際、99%のケースはこのようなものであり、0と-0の特殊なケースを考慮する必要があり、0 === -0は真であり、0と-0は等しくないと見なされます。理由については、http://を参照してください。 wiki.ecmascript.org/doku.php?id=harmony:egal

コードのこの部分は、次のように表すことができます。


// Identical objects are equal. `0 === -0`, but they aren't identical.

// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).

// a === b 时

// 需要注意 `0 === -0` 这个 special case

// 0 和 -0 不相同

// 至于原因可以参考上面的链接

if (a === b) return a !== 0 || 1 / a === 1 / b;

次の状況は!== bの状況です。

aとbのいずれかがnullまたは未定義の場合、特別に判断でき、比較を続行する必要はありません。ソースコードの実装:


// A strict comparison is necessary because `null == undefined`.

// 如果 a 和 b 有一个为 null(或者 undefined)

// 判断 a === b

if (a == null || b == null) return a === b;

上記の判断フィルタリングによれば、a === bはfalseを返さなければならないため、ここに書かれていることは少し冗長だと個人的に感じています。

では、続けましょう。次に、aとbのタイプで判断できます。タイプが同じでない場合は、判断を続ける必要はありません。変数タイプを取得する方法は?そうです、魔法のObject.prototype.toString.call!

タイプがRegExpとStringの場合、比較のためにaとbをそれぞれ文字列に変換できます(Stringがすでに文字列である場合)。次に例を示します。


var a = /a/;

var b = new RegExp("a");

console.log(_.isEqual(a, b));  // => true

実際、下線の内側は次のように判断されます。


var a = /a/;

var b = new RegExp("a");

var _a = '' + a; // => /a/

var _b = '' + b; // => /a/

console.log(_a === _b); // => true

番号タイプはどうですか?これがもう1つの特殊なケースであるNaNです!ここでは、NaNはNaNと同じであり、他の数値タイプとは等しくないことが規定されています。ここでは、すべての参照タイプを基本タイプに変換します。次のコードを参照してください。


var a = new Number(1);

console.log(+a); // 1

そうです、+を追加するだけで解決します。他の人は理解するのが難しくありません、それらはすべてコメントにあります。


// `NaN`s are equivalent, but non-reflexive.

// Object(NaN) is equivalent to NaN

// 如果 +a !== +a

// 那么 a 就是 NaN

// 判断 b 是否也是 NaN 即可

if (+a !== +a) return +b !== +b;

// An `egal` comparison is performed for other numeric values.

// 排除了 NaN 干扰

// 还要考虑 0 的干扰

// 用 +a 将 Number() 形式转为基本类型

// 如果 a 为 0,判断 1 / +a === 1 / b

// 否则判断 +a === +b

return +a === 0 ? 1 / +a === 1 / b : +a === +b;

// 如果 a 为 Number 类型

// 要注意 NaN 这个 special number

// NaN 和 NaN 被认为 equal

次に、DateタイプとBooleanタイプを見てみましょう。数値タイプと同様に、+!を使用して基本タイプの数値に変換することもできます。次のコードを見てください。

var a = new Date();

var b = true;

var c = new Boolean(false);

console.log(+a); // 1464180857222

console.log(+b); // 1

console.log(+c); // 0

非常に簡単です。実際、+ new Date()(または+ new Dateと書くこともできます)は、1970年1月1日の0:00に現在の時刻とミリ秒数を取得します。タイムスタンプについて聞いたことがあるかもしれませんが、実際には時刻です。スタンプは、このデータを秒数である1000で割ったものです。アニメーションにキャンバスを使用する場合、タイムスタンプとして+ newDateを使用することがよくあります。

したがって、aとbの両方が日付タイプまたはブールタイプである場合、+ a === + bを使用してそれが等しいかどうかを判断できます。

プログラムは継続され、引き続き検討されていますが、まだ判断されていない重要なタイプが2つあるようです。そうです、配列とオブジェクト!アンダースコアは、比較のために再帰的な方法を使用します。

たとえば、栗をあげましょう。もっと直感的です。

aとbが次のとおりであると仮定します。


var a = {name: "hanzichi", loveCity: [{cityName: "hangzhou", province: "zhenjiang"}], age: 30};

var b = {name: "hanzichi", loveCity: [{cityName: "hangzhou", province: "zhenjiang"}], age: 25};

まず、aとbはオブジェクトであり、それぞれのキーと値のペアを比較できます。異なるキーと値のペアがある場合(またはキーと値のペアaとbがある場合)、aとbは等しくありません。配列の場合はどうなりますか?次に、1つの要素が1つずつ多くなります。配列はオブジェクトをネストする可能性があり、オブジェクトの値は配列である可能性があるため、ここでは再帰が使用されます。

上記の例を引き続き使用して、3つの比較に分割し、3つのキーの値が同じであるかどうかを比較できます。キーloveCityの値については、その値が再び配列であるため、この値を比較関数に渡し、この比較の結果を使用して最終的な比較結果を決定します。再帰はそのようなものです。大きなものは小さなものに分解でき、大きな結果は小さな結果に従って集約できます。

最後に、コードの場所が示されます。_.isEqualメソッドのソースコードについては、こちらを参照してください。

おすすめ

転載: blog.51cto.com/15080022/2588317