js // type error (타입 오류)
# mdn정의
- 함수에 전달된 피연산자 또는 인수가 해당 연산자나 함수가 예상하는 타입과 호환되지 않을 경우
- 변경할 수 없는 값을 수정하려고 할 경우
- 부적절한 방법으로 값을 사용하려고 할 경우
# 일반적인 오류
- 바꿀수 없는 값(상수)
const value = 1;
value = 2;
상수 value를 바꾸려고할때 에러뜬다
- 이상한거 연산하려고할때
console.log(Symbol("hello") + 1);
심볼이랑 숫자는 더할수 없는데..
- 이상한거 참조하려고할때
console.log(null.hello);
console.log(undefined.hello);
null과 undefined에서 프로퍼티 참조하려면 에러뜸니다..
+ 참고로 선언하지 않은 변수에서 프로퍼티 참조하려하면
console.log(babo.hello);
타입에러가 아니라 참조에러뜸.
# 이중 객체 프로퍼티 참조
const obj = { key1: 1, key2: 2, key3: 3 };
console.log(obj.key1); //1
이런 객체 프로퍼티에 참조하려고 할때
key1프로퍼티 키에 접근하려고하면 당연히 1을 잘 가져온다.
그렇다면 없는 키값에 접근할때는 어떻게 될까?
const obj = { key1: 1, key2: 2, key3: 3 };
console.log(obj.key4); //undefined
없는 키값 key4에 접근하려 하면 undefined가 뜬다.
참조에러가 뜨는게 아니라 에러없이 undefined가 뜬다는거다.
즉 객체안에서 없는 프로퍼티에 접근하려하면 undefined로 뜬다.
참조코드와 동시에 객체내부에서 선언이되는건지 아닌건지 모르겠지만 이렇게 되는게
실제 코드를 써보면 더 편리하다.
+이중 객체에서의 참조
const obj = { key1: 1, key2: 2, key3: 3 };
console.log(obj.key4.secondKey);
위 obj에서 key4값은 undefined일것이다.
근데 이 key4가 객체라고 생각해서 그 안의 secondKey프로퍼티에 접근하려고하면
참조에러가 아닌 타입에러가 뜬다. 이땐 옵셔널체이닝써라.
const obj = { key1: 1, key2: 2, key3: 3 };
console.log(obj.key4?.secondKey);
이게 옵셔널 체이닝..
얕은 객체참조에선 그냥 undefined가 떠야 수월하고 깊은 객체참조에선 옵셔널체이닝을 사용하여 참조하는게
좋다는 말임.. 실제로 이거 웹사이트 개발할때 엄청 많이쓴다.
# 즉시실행 함수 개행문제 (세미클론)
const value = 1
(function () {
console.log("즉시실행함수");
})();
얘는 위에 어떤 코드가 있는지에따라 다른에러가 뜰수 있다.
내가 의도한 코드 :
const value = 1;
(function () {
console.log("즉시실행함수");
})();
멍청한 컴퓨터가 이해한 코드 :
const value = 1(function () {
console.log("즉시실행함수");
})();
이건 보통 vs코드 emet기능인가로 알아서 문제생기게 처리된다.
보통 자바스크립트에 ASI기능(automatic semicolon insertion)으로 세미클론 알아서 붙여주고
실행되는데 ASI가 위 즉시실행코드에는 안먹히므로 세미클론을 붙여주자.
# for 반복문의 조건에 const 를 쓴경우
for (const i = 0; i < arr.length; i++) {
console.log(arr[i]);
} // error
for in에서는 에러안뜸
for (const i in arr) {
console.log(i);
console.log(arr[i]);
} // const 써도 됨.
# for of 문을 객체로 돌려버렸을때
for (let i of obj) {
console.log(i);
}// 객체는 이터러블 아니라고 오류뜸
이터러블 아니라면서 안된다.
# forEach 반복을 객체로 돌려버렸을때
obj.forEach((i) => {
console.log(i);
}); //객체안에 forEach메서드 참조하는걸로 판단되서 타입에러뜸
# Array 프로토타입 메서드를 객체에 돌려버렸을때
every, some, find, findIndx, IndexOf 메서드도 다 동일함.
객체에 없는 메서드를 호출할때랑 걍 똑같다.
# 프로퍼티 어트리뷰트의 configurable을 false로 하고 다시 프로퍼티어트리뷰트를 재정의할때
const myHouse = {
dog1: "무찌",
dog2: "도리",
};
Object.defineProperty(myHouse, "dog1", {
configurable: false,
});
Object.defineProperty(myHouse, "dog1", {
configurable: true,
}); // 타입 에러뜸!!
단 writable이 true일때 value의 변경과, writable을 false로 바꾸는건 허용됨.
# 클래스를 new연산자 없이 호출할때
console.log(Dog_cls("무찌", 2)); // 타입에러 뜸
# 화살표함수에 없는 arguments, caller프로퍼티를 참조하려고할때
const arrow = () => {
return;
};
console.log(arrow.caller); //타입에러
console.log(arrow.arguments); //타입에러
프로퍼티 참조하려고할때 없으면 undefined가 떠야하는데 얘는 특별히 타입에러 뜨게해줌.
# 유사배열객체에 어레이메서드 쓰려고 할떄
const fucArguments = function () {
arguments.pop(); // 에러뜸!
};
fucArguments('무찌','도리') // 타입에러. arguments에는 pop프로퍼티가 없어서 undefined인데 호출하려하니.
arguments객체는 객체다. length프로퍼티, 넘버값 프로퍼티로 배열처럼 써먹을수있지만 배열이 아니라서 배열메서드를 쓸수 없다.
# __proto__에의한 상호참조 에러
const parent = {};
const child = {};
child.__proto__ = parent;
parent.__proto__ = child;
이렇게하면 child의 프로토타입메서드를 찾으려고 할때 parent객체를 찾아가고 여기에도 없으니 parent인스턴스의 프로토타입메서드를 검색하는데 이게 또 child인스턴스니까 무한하게 꼬이곘지?
근데 이렇게 생성자함수의 프로토타입을 서로 교환하는것은 된다. 이건 꼬이는게 아니라서..
const Child = function () {};
const Parent = function () {};
const child = new Child();
const parent = new Parent();
Child.prototype = parent.__proto__; // 작동됨
Parent.prototype = child.__proto__; // 작동됨
child.__proto__ = Parent.prototype; // 작동안함
parent.__proto__ = Child.prototype; // 작동안함
console.log(Child.prototype); // Parent 생성자 함수 / 제대로 바꼈음
console.log(Parent.prototype); // Child 생성자 함수 / 제대로 바꼈음
console.log(child.__proto__); // Child 생성자함수 / 안바꼈음
console.log(parent.__proto__); // Parent생성자 함수 / 안바꼈음
위 코드처럼 서로 다른 생성자함수로 각 인스턴스를 생성하고,
생성자함수의 prototype프로퍼티에 인스턴스의 __proto__로 접근한 객체를 할당해준건 제대로 작동하였다.
하지만 인스턴스의 __proto__로 접근자프로퍼티 메서드를 호출하고 이곳에 직접 다른 생성자 함수의 prototype프로퍼티 객체를 할당하는건 (정확히는 매개변수로 넣어서 set __proto__ (~~.prototype)으로 호출하는거) 바뀌지 않았다.
암튼 이렇게 생성자함수의 프로토타입을 서로 바꾸고 새로 인스턴스를 만들면,
const newChild = new Child();
console.log(newChild.__proto__); //얘는 프로토타입이 Parent.prototype으로 생성됨.
이렇게 Child생성자 함수로 newChild 인스턴스를 만들었지만 이 인스턴스의 프로토타입체인은 Parent.prototype객체를 1순위로 거쳐가게 된다.
뭐 이런 ㅈ같은 코드를 짜지는 않겠지만 접근자프로퍼티로 새로운객체를 넣는건 어느정도 내부로직으로 검열하는듯.
근데 이게 아예 set __proto__ (객체) 가 동작하지 않는다는 의미는 아니다.
const child = new Child();
child.__proto__ = { constructor: Parent };
console.log(child.__proto__); // Parent.prototype객체 / 이렇게는 작동함.
이렇게 객체리터럴로 넣어주면 또 된다. 참 ㅈ같이도 만들어놨다.
..................UPDATING.................