interface Stack {
readonly size: number;
push(num: string): void;
pop(): string;
}
type StackNode = {
readonly value: string;
readonly next?: StackNode; //가리키는게 없을 수도 있으므로(=제일 마지막)
};
class StackImpl implements Stack {
private _size: number = 0;
private head?: StackNode;
//스택의 전체 크기
constructor(private capacity: number) {}
//외부에서 접근하는 용도로 getter 생성
get size() {
return this._size;
}
push(value: string) {
if (this.size === this.capacity) {
throw new Error('Stack is full');
}
//처음 value가 들어오면 이 value를 감싸는 노드를 만듦
const node: StackNode = {
value,
next: this.head,
};
//그러면 head는 새로 들어온 것을 가리키고 있어야 함
this.head = node;
this._size += 1;
}
pop(): string {
**//이 부분**
if (this.head == null) {
throw new Error('Stack is empty');
}
// 제거하고자 하는 노드 (현재 head가 가리키고 있는)
const node = this.head;
this.head = node.next;
this._size -= 1;
return node.value;
}
}
const stack = new StackImpl(10);
stack.push('1');
stack.push('2');
stack.push('3');
while (stack.size !== 0) {
console.log(stack.pop());
// 3
// 2
// 1
}
stack.pop(); //위에 심어놓은 throw new Error('Stack is empty') 발동
export {};
그렇지만 저 부분에서
pop을 호출할 때 바로 스택이 비어있는지 확인을 먼저 해주는 로직이 있다고 했는데
private head?: StackNode;
여기서 this.head값은 Optional 형태로 사용했므로 StackNode타입일 수도 , undefined일 수도 있습니다
그러면 왜 ===undefined로 안하고 ==null로 했을까요
TS는 strictNullChecks라는 기능이 존재해서 애초에 변수에
null , undefined가 할당되지 못합니다
그래서 만약에 예기치 못한 오류로 head에 undefined가 아닌 null값이 들어오게 되면 strictNullChecks 때문에 자동으로 이걸 막아줍니다
JS는 변수에 null , undefined가 자유롭게 할당될 수 있습니다
그래서 예기치 못한 에러로 null값이 들어오는 것을 막을 수 없으며,
만약 null값이 들어왔다면 ===undefined 조건문에서 통과가 되기 때문에
예상치 못한 연산이 진행될 수 있습니다
그래서 == null을 사용해서 null과 undefined둘 다 막는 것입니다