밑줄 소스 코드 해석 : JS에서 두 요소가 "동일"한지 판단하는 방법

왜 밑줄

최근에 저는 underscore.js의 소스 코드를 살펴보고 2016 년 계획에 underscore.js의 소스 코드를 해석하기 시작했습니다.

유명한 프레임 워크 라이브러리의 소스 코드를 읽는 것은 마스터와 대화하는 것과 같으며 많은 것을 배울 것입니다. 밑줄은 왜입니까? 주된 이유는 밑줄이 짧고 간결하여 (약 1.5k 줄) 100 개 이상의 유용한 메서드를 캡슐화하고, 낮은 커플 링, 메서드 별 읽기에 매우 적합하고, 원본 포스터와 같은 JavaScript 초보자에게 적합합니다. 이를 통해 undefined가 다시 작성되는 것을 방지하기 위해 undefined 대신 void 0을 사용하는 것과 같은 몇 가지 트릭을 배울 수있을뿐만 아니라 변수 유형 판단, 함수 제한 및 함수 디 바운스, 많은 브라우저 호환성과 같은 일반적인 방법도 배울 수 있습니다. 핵, 당신은 또한 저자의 전반적인 디자인 아이디어와 API 디자인의 원칙을 배울 수 있습니다 (역 호환성).

나중에 호스트는 소스 코드 읽기에서 배운 지식을 공유하기 위해 일련의 기사를 작성합니다.

시청에 오신 것을 환영합니다 ~ (관심이 있다면 스타와 시청하세요 ~) 여러분의 관심은 호스트가 글을 계속 쓰는 동기입니다.

_.는 같다

이 기사에서는 JavaScript에서 두 매개 변수가 "동일"하다는 것을 확인하는 방법, 즉 밑줄 소스 코드의 _.isEqual 메소드에 대해 설명합니다. 이 방법은 밑줄 소스 코드에서 구현하는 가장 복잡한 방법이라고 할 수 있습니다 (100 줄 이상 소요).

그래서 "동일"이란 무엇을 의미합니까? 예를 들어, 1과 new Number (1)은 같은 것으로 간주되고 [1]과 [1]은 같은 것으로 간주됩니다 (참조는 같지 않음). 물론 같은 참조를 가진 두 개체는 같아야합니다. .

그렇다면이 _.isEqual 함수를 설계하는 방법은 무엇입니까? 우리는 밑줄 소스 코드를 따라 단계별로 구현을 살펴 봅니다. 다음 텍스트에서는 비교할 두 매개 변수가 a와 b라고 가정합니다.

먼저 a === b가 참이라고 판단합니다. 두 가지 경우가 있습니다. 하나는 a와 b가 기본 유형이고 두 가지 기본 유형의 값이 동일하고 다른 하나는 두 가지 참조 유형이므로 참조 유형입니다. 참조는 동일합니다. 따라서 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;

다음 상황은 a! == 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

숫자 유형은 어떻습니까? NaN이라는 또 다른 특별한 경우가 있습니다! 여기서 NaN은 NaN과 동일하고 다른 Number 유형과 동일하지 않다고 규정합니다. 여기에서 모든 참조 유형을 기본 유형으로 변환합니다. 다음 코드를 참조하십시오.


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

다음으로 날짜 및 부울 유형을 살펴 봅니다. 숫자 유형과 유사하게 +!를 사용하여 기본 유형의 숫자로 변환 할 수도 있습니다. 다음 코드를보십시오.

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으로 나눈 것입니다. 애니메이션에 캔버스를 사용할 때 종종 타임 스탬프로 + new Date를 사용합니다.

따라서 a와 b가 모두 Date 유형이거나 Boolean 유형 인 경우 + a === + b를 사용하여 동일한 지 여부를 판단 할 수 있습니다.

프로그램은 계속되고, 우리는 그것을 계속해서 봅니다. 아직 심사되지 않은 두 가지 중요한 유형이있는 것 같습니다. 맞습니다, Array and Object! Underscore는 비교를 위해 재귀 적 방법을 사용합니다.

예를 들어 밤나무를 주자, 더 직관적입니다.

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는 같지 않습니다. 배열이면 어떨까요? 그러면 하나의 요소가 더 많습니다. 배열이 개체를 중첩 할 수 있고 개체의 값이 배열 일 수 있으므로 여기서는 재귀가 사용됩니다.

위의 예를 계속 사용하여 세 가지 비교로 분할하고 세 키의 값이 동일한 지 비교할 수 있습니다. loveCity 키 값의 경우 값이 다시 배열이므로이 값을 비교 함수에 전달하고이 비교 결과를 사용하여 최종 비교 결과를 결정합니다. 이것이 재귀의 방식입니다. 큰 것은 작은 것으로 나눌 수 있고, 작은 것은 요약하여 큰 것을 얻을 수 있습니다.

마지막으로 코드 위치가 제공됩니다. _.isEqual 메서드의 소스 코드는 여기를 참조하십시오.

추천

출처blog.51cto.com/15080022/2588317