이전 시리즈 글 : 코드 최적화 - 1. this.~ 문의 사용 보러가기 

이전 시리즈 글 : 코드 최적화 - 2. 유효성 검사 보러가기

 


 

개요

  • 개요는 시리즈 1과 동일 
  • 이하에서는 for문과 forEach문에 대해 구체적으로 정리함

 


 

1. 문법 

  • for
for (let j = 0; j < keypoints.length; j++) {
    let x = keypoint.x - 320;
    let y = keypoint.y - 240;
    console.log(`${keypoint.name}: [${x}, ${y}]`);
}
  • forEach
res.keypoints.forEach((keypoint) => {                
  let x = keypoint.x - 320;
  let y = keypoint.y - 240;
  console.log(`${keypoint.name}: [${x}, ${y}]`);
})

 


 

2. 비교

  for문  forEach문
장점 - 인덱스 제어 가능 - break, continue 사용 가능 - 배열 뿐만 아니라 객체의 속성에 대해서도 순회 가능 - 가독성 향상
단점 - 가독성 떨어짐 - 인덱스 제어 불가 - break, continue 사용 불가 (반복문을 보다 효율적으로 만들어주는 구성 요소) - 일반적으로 객체의 속성 순회 어려움

 

  • 객체의 속성 예시
// 객체 
const myObject = {
  name: 'John',
  age: 25,
  city: 'New York',
  gender: 'Male'
};

// 배열 
const myArray = ['name', 'age', 'city', 'gender']
  • 객체 = myObject, 객체는 key-value로 이루어져 있음, 따라서 객체의 속성 = value = John, 25, New York, Male을 의미함
  • 그러나 forEach 문은 배열을 순회하기에는 적합하지만, 객체의 속성까지 순회 불가
    : forEach 메서드는 처리 대상으로 배열을 기대, 그러나 객체는 key-value 쌍의 집합
  • 보완책
    1. 객체의 key들을 배열로 얻기 → 각 key에 대응하는 value에 접근
// Object.keys() 사용
const keys = Object.keys(myObject);
keys.forEach(key => {
  console.log(`${key}: ${myObject[key]}`);
});

// 프로젝트에 적용 
const FINGER_INDICES = {
    thumb: [0, 1, 2, 3, 4],
    indexFinger: [0, 5, 6, 7, 8],
    middleFinger: [0, 9, 10, 11, 12],
    ringFinger: [0, 13, 14, 15, 16],
    pinky: [0, 17, 18, 19, 20],
};
Object.keys(FINGER_INDICES).forEach(finger => {
    const points = FINGER_INDICES[finger].map(idx => res.keypoints[idx]);
    this._drawPath(ctx, points, false);
});

     

      2. 배열 요소가 객체인 경우, 배열을 순회하면서 객체의 속성에 접근
          ( 1-1의 객체의 key들을 배열로 얻는 과정 생략하여 보다 직관적인 방법 )

/** this._result의 형태 
this._result: 
	0:
		box: {xMin: 133.~, yMin: 140.~, xMax: 346.~, yMax: 391.~, width: 213.~}
		keypoints: Array(468)
			[0 ... 99]  //배열 요소가 객체
				0: {x: 193.~, y: 315.~, z: -33.~, name: 'lips'}
				1: ... 반복
				2: ...
				3: ...
**/

this._result = result;
this._result.forEach((res, i) => {  
  res.keypoints.forEach((keypoint) => {  //res.keypoints는 배열, 배열의 각 요소(keypoint)에 대해 순회, i는 현재 요소의 인덱스
      if (keypoint.name != undefined) {
          let x = keypoint.x - 320;  //keypoint.x 및 keypoint.y 를 사용하여 현재 요소의 속성에 접근
          let y = keypoint.y - 240;
          console.log(`${keypoint.name}: [${x}, ${y}]`);
      }
  })
})

       

      3. for…in 문 사용

  • 객체의 모든 속성에 대해 반복
  • 그러나 hasOwnProperty 를 이용하여 객체 자체의 속성인지 확인하는 것이 중요
  • 즉 프로토타입 체인을 따라 올라가서 속성을 가져오지 않고, 해당 객체의 속성에서만 확인하기 위함
  • for…in 문과 형태가 유사한 for…of 문은 이터러블 객체를 순회하는 데에 유용함.
    ( 이터러블 객체 : 여러 내장 객체. Array, String, Map, Set )
  • 그러나 객체는 원칙적으로 이터러블 객체가 아님. 단지 객체 내부에 배열이 있을 수 있는 것 뿐임
// for...in 문 적용
for (let key in myObject) {
  if (myObject.hasOwnProperty(key)) {
    console.log(`${key}: ${myObject[key]}`);
  }
}

// 이터러블 객체에 for...of 문 적용 
const myString = "Hello";
for (const char of myString) {
  console.log(char);
}

const myMap = new Map([
  ['key1', 'value1'],
  ['key2', 'value2'],
  ['key3', 'value3']
]);
for (const [key, value] of myMap) {
  console.log(`${key}: ${value}`);
}

const mySet = new Set([1, 2, 3, 4, 5]);
for (const element of mySet) {
  console.log(element);
}

문제 인식

  • 이번 프로젝트 (hand-pose-detection, face-landmarks-detection, pose-detection) 기능 구현은 완료했음. 
  • 그러나 기능 구현이 된 코드가 매!우! 더러웠음. 난도질 수준... 따라서 본격적으로 코드 최적화를 고민하기 시작함
  • 이하 내용 및 시리즈로 작성할 내용들은 ①기존 회사 코드 ②각종 공식 문서 ③GPT 와 함께 최적화한 코드 중에서, 3번 이상 자주 사용한 내용임
  • 이하 글 및 코드의 근본적인 출처는 https://ko.javascript.info/object-methods#ref-272
 

메서드와 this

 

ko.javascript.info

 


 

1. 의미

  • 현재 객체. 따라서 기본적으로 메서드 내부에서 this 키워드를 사용하면 객체에 접근 가능
let user = {
  name: "John",
  age: 30,
  sayHi() {
    // 'this'는 '현재 객체'를 나타냅니다.
    alert(this.name);
  }
};
user.sayHi(); // John
  • 자바스크립트에서는 모든 함수에 this 사용 가능 (다른 프로그래밍 언어와 상이)
  • this 값은 런타임에 따라 결정됨. = 컨텍스트에 따라 달라짐. = 동일한 함수라도 다른 객체에서 호출했다면 this가 참조하는 값이 달라짐
let user = { name: "John" };
let admin = { name: "Admin" };

function sayHi() {
  alert( this.name );
}

// 별개의 객체에서 동일한 함수를 사용함
user.f = sayHi;
admin.f = sayHi;

// 'this'는 '점(.) 앞의' 객체를 참조하기 때문에
// this 값이 달라짐
user.f(); // John  (this == user)
admin.f(); // Admin  (this == admin)

admin['f'](); // Admin (점과 대괄호는 동일하게 동작함)

 


 

2. 프로젝트에 적용

  • _함수명을 호출할 때, this._함수명() 사용
_createDetector() {
  const model = SupportedModels.MediaPipeHands;
  const detector = createDetector(model, {
      runtime: "tfjs",
      modelType: "lite",
      maxHands: 2, // or 2~10.
      flipHorizontal: false,
      staticImageMode: false,
      detectorModelUrl:
          "/static/tensorflow-models/tfjs-model_handpose_3d_detector_lite_1/model.json",
      landmarkModelUrl:
          "/static/tensorflow-models/tfjs-model_handpose_3d_landmark_lite_1/model.json",
  });
  return detector;
}

// this._함수명 으로 호출 
detect(imageData) {
    if (!this._detector) {
        this._createDetector().then(detector => {
            this._detector = detector;
            console.log("model loading success!, detector: ", this._detector);
        })
    }
//... 중략
}
  • 생성자 함수에서 메서드, 프로퍼티 초기화할 때 사용 : 즉, 메서드는 객체로 this를 참조
class Animal {
  constructor(name) {
    this.speed = 0;
    this.name = name;
  }
  run(speed) {
    this.speed = speed;
    alert(`${this.name} 은/는 속도 ${this.speed}로 달립니다.`);
  }
  stop() {
    this.speed = 0;
    alert(`${this.name} 이/가 멈췄습니다.`);
  }
}

let animal = new Animal("동물");

 

+ Recent posts