TypeError: Cannot read properties of undefined 에러(feat. 문자열 비교 과제)

Uhan33·2024년 1월 2일
0

TIL

목록 보기
5/72

오늘 나를 힘들게 만든 녀석이 있었다.
2주차 숙제로 배열 안의 단어들을 각 단어의 n번째 인덱스의 문자와 비교해서 정렬하는 문제였는데 어렵지 않게 풀 것만 같았던 이 문제가 한 녀석때문에 망가져버렸다.

Cannot read properties of undefined

javascript로 코드를 짜다 보면 자주 보이는 에러 문구이다. 이 오류는 보통

객체가 null 또는 undifined인 상태에서 속성이나 메서드에 접근하려고 할 때 발생한다.

자바스크립트는 객체의 속성이나 메서드에 접근이 가능하지만 객체가 정의되지 않은 경우에 이 오류가 발생하게 된다.

일반적으로 위 오류가 발생하는 경우는 아래 처럼 몇 가지가 있다.

1. 변수에 null이나 undifined 값 할당(실수)

2. 객체에 존재하지 않는 속성에 접근

3. 객체를 선언했지만 초기화를 하지 않음

4. 비동기 작업에서 객체가 아직 준비되지 않은 경우

위 같은 경우에 오류가 발생하게 된다.

상황에 따라 다르겠지만 해결 방법으로는

  • 조건문을 활용한 접근 제어
  • 객체의 타입 체크 (typeof)
  • 변수의 초기화 체크

등등 이 있는데... 나같은 경우는 위에 해당되는 상황은 없었기에 해결할 수 없었다..
일반적인 해결법은 위와 같지만 나의 경험으로 해결한 상황을 적어보려고 한다.


오류 발생 지점 확인

우선 내가 하고 있던 과제는
배열 안의 단어들을 각 단어의 n번째 인덱스의 문자와 비교해서 정렬하는 문제 였다.
만약 n번째 인덱스의 문자열이 같다면 같은 문자열 끼리는 사전식으로 정렬해준다.

우선 배열인 strings와 문자열 인덱스 n을 입력받으면
select를 지정하여 배열 내 자리 하나를 선택하고 나머지와 하나씩 비교하여 자리를 바꿔주는 방식으로 풀어보기로 했다.

숫자로 비교하자면 이런 느낌이랄까..? 위처럼 select를 0번 인덱스로 지정하고 끝까지 돌면 0번 인덱스자리는 최솟값이 있을 것이고 select는 한칸 옆(5자리)으로 이동하여 나머지와 똑같이 비교를 시작한다.

function sortArray(strings, n) {
    let i = 0;
    let select = 0;
    while((select + 1) < strings.length) {
        let first = strings[select];
        let second = strings[i+1];
        if(first.charAt(n) > second.charAt(n)) {
            let temp = strings[select];
            strings[select] = strings[i+1];
            strings[i+1] = temp;
        }

i는 비교할 인덱스를 선택하는 용도고,
select는 0번부터 n-1까지만 지정하면 되므로
select+1이 배열의 길이와 같아지기 전 까지만 비교를 해주며,

select번째 문자열과 i+1번 째 문자열을 비교 할 것임으로
first와 second로 지정해주었다.

이 중 n번째 문자를 비교하기 위해 charAt(n)으로 n번째 문자를 서로 비교해준다.
그러고서 만약!
first의 n번째 인덱스 문자가 second의 n번째 문자보다 크다면? 두 자리를 바꿔준다.

		else if(first.charAt(n) === second.charAt(n)) {
            let equalstr = [strings[select], strings[i+1]];
            equalstr.sort();
            strings[select] = equalstr[0];
            strings[i+1] = equalstr[1];
        }

n번째 문자가 서로 같은 문자라면?
두 문자열을 가지고 배열을 새로 만들어준 뒤,
javascript에 내장된 sort() 함수를 사용해서 사전식 정렬을 해주고
정렬된 equalstr[0]부터 앞자리에 넣어준다.

		i++;
		if(i === strings.length) {
			i = ++select;
    	}
	}
    console.log(strings);
}
let strings1 = ["sun", "bed", "car"];
let strings2 = ["abce", "abcd", "cdx"];
sortArray(strings1, 1);
sortArray(strings2, 2);

비교가 한 번 끝나면 i는 1씩 증가시키고, 증가시킨 i의 자리가 배열의 마지막 인덱스라면
select를 1 증가시킴과 동시에 i의 값을 증가시킨 select로 초기화해준다.

이렇게 코드를 완성시키고 바로 됐다는 생각에 실행하였는데...

정의되지않은 속성 charAt을 읽을 수 없다고 한다.. 그럴리가 없는데...
그래서 charAt을 []로 바꾸어보기도 하고, 이것저것 시도를 해보았다.
(사실 first와 second도 시도하면서 바꿔본 것이다. 원래 strings[select].charAt(n) 이었음..)

내가 오류를 해결한 방법

사실 오류를 해결했다기보단 실수를 바로잡았다고 하는게 맞는 것 같다.

		i++;
		if(i+1 === strings.length) { 		//여기!!!
			i = ++select;
    	}
	}
    console.log(strings);
}
let strings1 = ["sun", "bed", "car"];
let strings2 = ["abce", "abcd", "cdx"];
sortArray(strings1, 1);
sortArray(strings2, 2);

저 위에있던 코드를 가져온 것인데 한 가지를 수정했다.
바로 if문 안의 i를 i+1로 고쳐준 것..!

i가 배열의 마지막 부분이 될 때 i를 초기화 시켜주게되면
i가 초기화되기 바로 직전에서 while문을 돌 때,
second부분인 strings[i+1] 에서 배열 인덱스 범위를 넘어가게 되어
second가 undifined가 되어버리고...
undifined가 되어버린 second에서 charAt을 사용하려 하니 당연히!!
정의되지 않은 속성값이라고 나올 수 밖에 없는것이다..

결론적으로 해결한 방법은 실수한 부분을 찾은 것이었다.
찾는 과정도 쉽지 않았는데,
로직 중간중간 log를 출력하여 어느정도까지 진행되는지, 어디에서 막히는지 확인하는 것
실수나 오류가 발생한 부분을 정확히 짚을 수 있어서 잘 활용하면 좋을 듯 하다.

마치며...

간단한 과제라고 생각하고 풀었지만 오류가 발생했고,
이 오류를 해결하는데 상당한 시간이 걸렸다.

구글에 아무리 검색해도 해결되지 않는다면
자신이 작성한 코드를 차근차근 곱씹어보면서
잘못된 부분이 있는지 확인해보자!

0개의 댓글