개발

자바스크립트 every 함수 구현 (feat. ECMA-262)

동고킴 2024. 4. 15. 00:20
반응형

ECMA-262 규격대로 every 함수 구현해 보기

자바스크립트 every는 배열의 모든 요소가 제공된 함수로 구현된 테스트를 통과하는지 테스트하는 함수다. ECMA-262에 나와있는 every 함수의 스펙대로 이 기능을 자바스크립트로 구현해 보자.

 

자바스크립트로 구현에 앞서 ECMA-262의 every 함수의 명세를 살펴보자.

every의 동작을 설명한 내용은 아래와 같다.

 

그리고 이 내용을 단계별로 의사코드(Pseudo-code)로 표현한 내용이다.

 

 

이걸 한글로 해석하면

1. O는 this이다.
2. O의 길이를 len으로 선언
3. 만약 callbackfn이 함수가 아니면 타입에러가 발생한다.
4. k를 0으로 선언
5. 길이가 k보다 크면 반복한다.
   a. k를 문자열 Pk로 선언
   b. O가 Pk 속성을 가지면 kPresnet로 선언
   c. 만약 kPresent가 참이면
        i. O[Pk] 값은 kValue로 선언
        ii. callbackfn 함수에 kValue, k, O 인자를 넘겨서 실행한 결과를 testResult 로 선언
        iii. testResult가 false이면 false를 반환
    d. k에 k+1 저장
6. true를 반환

 

v8 엔진의 every 함수 구현

v8 엔진에서는 Torque로 구현되어 있다. Torque는 v8에서 사용하는 언어다. CSA로 구현된 내용들을 Torque로 옮겨가고 있는데 이 이상의 자세한 건 굳이 알 필요 없다.

Torque 코드를 살펴보면 ECMA-262의 스펙대로 구현한 걸 볼 수 있다. 친절하게 주석까지 잘 달려있다.

코드 라인에 관계없이, 의사코드 순서대로 코드만 살펴보자.

코드를 보면 빈 배열일 경우에는 무조건 true를 반환한다. 왜 빈배열은 true를 반환하도록 명세를 작성했을까? 이에 대한 내용은 자바스크립트 every 함수가 빈 배열을 true로 반환하는 이유에서 확인할 수 있다.

 

자바스크립트로 every 함수 구현

이제 이걸 자바스크립트로 구현해 보자. 의사코드 그대로 구현하면 된다.

Array.prototype.every = function (callbackfn, thisArg) {
  const O = this // 1. Let O be ? ToObject(this value).
  const len = O.length // 2. Let len be ? LengthOfArrayLike(O).

  if (typeof callbackfn !== "function") {
    // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
    throw new TypeError("Callback isn't callable")
  }

  let k = 0 // 4. Let k be 0.

  while (k < len) {
    // 5. Repeat, while k < len,

    const Pk = String(k) // a. Let Pk be ! ToString(𝔽(k)).
    const kPresent = O.hasOwnProperty(Pk) // b. Let kPresent be ? HasProperty(O, Pk).

    if (kPresent) {
      // c. If kPresent is true, then

      const kValue = O[Pk] // i. Let kValue be ? Get(O, Pk).

      // ii. Let testResult be ToBoolean(? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »)).
      const testResult = Boolean(callbackfn.call(thisArg, kValue, k, O))

      if (testResult === false) {
        // iii. If testResult is false, return false.
        return false
      }
    }

    k = k + 1 // d. Set k to k + 1.
  }

  return true // Return true.
}

 

참고

반응형