
딱히 유용하진 않음.
const object=new Object();
인스턴스간 동일한 함수를 계속 중복 생성해야 한다!!
const circle={
radius:5,
getDiameter(){ return 2* this.radius; }
}
객체를 위한 클래스처럼 사용 가능!
function Circle(radius){
this.radius=raidus;
this.getDiameter=function(){return 2*this.radius';};
}
const circle1 = new Circle(1); //이건 생성자.. js엔진이 암묵적으로 인스턴스를 생성+초기화+반환해줌
const circle2 = Circle(1); //이건 일반함수.. return이 없으니까 undefined
console.log(radius); //여기에서의 this는 전역객체이므로 windows.radius = 15
👇 this 바인딩
- 일반 함수의 this = 전역 객체 (windows)
- 메서드의 this = 매세드 호출 객체
- 생성자 함수의 this = 생성자 함수가 미래 생성할 인스턴스
🚥 생성자 함수로 객체가 생성되는 순서
- 빈 인스턴스 객체 생성
- 빈 인스턴스 객체를 this에 바인딩
----런타임------ 생성자 함수의 내용 실행 = 초기화
- this 반환
👉 명시적 객체 return이 있다면 그쪽이 우선된다.
👉 명시적 원시값 return은 무시되고 this가 반환된다.
생성자 함수로써 호출할 수 있다! (=객체 생성 가능)
function foo(){}
foo.prop=10; //일반 객체처럼 속성 추가 가능 = 일반객체의 내부 슬롯과 내부 메서드 가짐
foo(); //일반 객체와 달리 호출 가능 = 함수 객체의 내부슬롯과 내부 메서드 가짐
🤗 쉽게 말하자면..
new를 붙일 수 있으면 constructor고 아니면 non-constructor다!
function add(x,y){return x+y;} //일반 함수
let inst=new add(); //생성자 함수로 동작
console.log(inst); //원시값은 반환 무시, {} 빈 객체 반환
function createUser(name, role){return {name, role} } //생성자 함수
inst=new createUser("name", "role"); //생성자 함수로 동작
console.log(inst); //객체 반환 유효, {"name", "role"} 반환
😲 일반 함수와 생성자 함수를 어떻게 구별하나요?
사실..기본적으로 형식적인 차이는 없다! 따라서 생성자 함수는 파스칼 케이스(첫글자 대문자)로 명명해서 일반 함수와 구분될 수 있게 하자.
function thisisjustFunction(a,b) { return a+b; } //일반 함수 function ThisisConstructor(a,b ) {return {a, b}} //생성자 함수
함수가 생성자로 사용되었는지 일반 함수로 사용되었는지 알려주는 함수
🌍 메타 프로퍼티
constructor인 모든 함수 내부에서 암묵적인 지역변수로 사용되는 변수.
ex)this, new.target ..
IE와 같이 new.target을 사용하지 못하는 경우 해당 패턴을 이용하여 무조건 생성자 함수로 사용하도록 하는 패턴
function Circle(radius){
if(!(this instanceof Circle) //생성자 함수로 사용하지 않으면 this = 전역객체인 점을 이용!
return new Circle(radius); // 무조건 생성자 함수로 인스턴스를 생성한 뒤 리턴하게 한다
}
👉 Object, Function 생성자 함수는 이와 같이 new를 사용하지 않아도 생성자 함수로 쓸 수 있다.
JS의 함수는 일급 객체!

함수 호출시 전달되니 인수들을 저장하는 유사배열객체.
함수가 호출되면 암묵적으로 매개변수가 선언되고 undefined로 초기화된 후 인수를 할당받는다.
😴 undefined 연산
undefined간 연산을 수행하면 NaN이 반환된다!
선언한 매개변수 개수
함수의 이름.
익명함수의 경우 함수 객체를 가리키는 식별자를 갑승로 가진다
Object.prototype에게 상속받은 접근자 프로퍼티.
모든 객체는 [[Prototype]]이라는 내부 슬롯을 가지고 자신의 프로토타입 객체를 값으로 가진다.
_ _proto__ 접근자를 이용해서만 [[Prototype]]의 값인 자신의 프로토타입 객체에 접근이 가능하다.
🥴 접근자 프로퍼티를 통해 프로토타입에 접근하는 이유
상호 참조를 통해 서로가 자신의 프로토타입이 되는 비정상적인 순환 프로토타입 체인이 만들어지면, 프로퍼티 검색을 위해 프로토타입 체인을 타고 상위로 올라갈 때 무한 루프가 발생한다!
👉 프로토타입 체인은 오직 단방향 링크드리스트로 구현되어야 한다!
constructor 함수 객체만이 가지고 있는 프로퍼티.
생성자 함수가 생성하는 인스턴스의 프로토타입 객체를 가리킨다.



Circle.prototype = circle1.__proto__
//생성자 함수로써 가지는 프로토타입 = 자신의 원본 형태를 찾아가는 [[Prototype]] 내부슬롯
모든 프로토타입은 constructor 프로퍼티를 가진다.
👉 프로토타입과 생성자 함수는 단독으로 존재할 수 없고 쌍으로 존재한다.
프로토타입과 생성자 함수는 언제나 쌍으로 존해자므로,
프로토타입은 생성자 함수가 constructor로 평가되어 함수 객체를 생성하는 시점에서 생성된다.
👉 이때 생성되는 프로토타입의 프로토타입은 항상 Object.prototype!
Object, String, Number...
전역 객체가 생성되는 시점에 빌트인 생성자 함수가 생성되고,
빌트인 생성자 함수가 생성되는 시점에 빌트인 프로토타입이 생성도니다.
🌏 전역 객체
코드가 실행되기 이전 단계에 JS 엔진에 의해 생성되는 특수한 객체 (window, global..)

Object.prototype은 언제나 프로토타입 체인의 종점.
여기에서도 프로퍼티를 못 찾으면 undefined를 반환한다.
🔗 프로토타입 체인과 스코프 체인
- 프로토타입 체인: 상속과 프로퍼티 검색을 위한 메커니즘
- 스코프 체인: 식별자 검색을 위한 메커니즘

하위 프로퍼티의 오버라이딩에 의해 상위 프로퍼티 값이 가려지는 현상
상위 클래스가 가지고 있는 메서드를 하위 클래스가 재정의해 사용하는 방식
😎 하위 객체는 프로토타입의 프로퍼티를 조작할 수 없다!
프로토타입 프로퍼티를 조작하려면 하위 객체를 통해 프로토타입 체인으로 접근해서는 안 되고, 프로토타입에 직접 접근해야 한다!
부모 객체인 프로토타입을 동적으로 변경하여 상속 관계를 변경하는 것이 가능하다.
prototype 프로퍼티를 이용한 프로토타입 교체
const Person=(
function(){ //익명함수를 넣어서 즉시실행되게 하는 생성자 함수
function Person(name){this.name=name;}
Person.prototype={ //프로토타입을 sayHello로 교체합니다
constructor: Person, //교체될 함수에는 constructor 프로퍼티가 없으므로 명시적 추가
sayHello(){console.log(this.name);}
}; //생성자함수 Person의 prototype 프로퍼티를 교체.
return Person();
}());
👉 Person.prototype을 교체한 것으로 Person 생성자 함수와의 연결은 여전히 유지됨!

_ _proto__를 이용한 프로토타입 교체
const Person(name){this.name=name;}
const me = new Person("홍길동");
const parent={
constructor: Person, //교체될 함수에는 constructor 프로퍼티가 없으므로 명시적 추가
sayHello(){console.log(this.name);}};
Person.prototype=parent; //Person.prototype을 parent로 교체하여 Person 생성자 함수와 연결
Object.setPrototypeOf(me, parent);
//인스턴스의 __proto__에 접근하여 아까 만든 parent로 해당 인스턴스의 프로토타입 교체
me.sayHellog(); //홍길동
👉인스턴스의 [[Prototype]]을 교체한 것으로 Person 생성자 함수는 교체된 parent와 아무런 접점이 없음!
👉Person 생성자 함수의 prototype에는 여전히 인스턴스와 연결이 끊어진 Person.prototype이 연결되어 있다. 이것을 parent로 교체해 주어야 함.

객체 instanceof 생성자함수
우변의 생성자 함수 프로토타입이 좌변 객체 프로토타입 체인 상에 존재하면 true!
프로토타입 체인만 확인하고 생성자 함수와의 연결에는 영향x.
me.constructor===Person; //false
me instanceof Person; //true
me instanceof Object; //true
😧 Person을 parent로 교체했는데 왜 여전히 me의 프로토타입 체인에 Person이 존재하나요?
코드를 잘 읽어 보자! 우리가 한 건 Person와 parent를 스왑한 것이 아니라 Person.prototype에 parent를 넣은 것!
Person.prototype=parent;즉, Person은 여전히 존재하고
명시적으로 프로토타입을 지정하여 직접적으로 상속받는 새로운 객체를 생성하는 메서드
해당 객체의 프로토타입에 매개변수의 프로토타입을 넣어 사용한다.
let obj=Object.create(null); //Object.prototype도 상속받지 않는다!
//프로토타입 체인의 종점에 위치하는 객체가 된다.
obj = Object.create(Object.prototype); //Object.prototype은 상속받는다
obj = Object.create(Object.prototype,
{x:
{value: 1,
wirtable: true,
enumerable: true,
configurable: true}}); // ={x:1}
let proto={x:10};
obj = Object.create(proto); //proto 상속 (obj->proto->Object->null)
function Person(name){this.name=name;}
obj = Object.create(Person.prototype); //Person 상속 (obj->Person.prototype->Object.prototype)
const proto={x:10};
const obj={y:20, __proto__: proto}; //obj = {y:20, x:10}
생성자 함수에서만 참조/호출할 수 있는 프로퍼티/메서드.
해당 생성자 함수로 만든 인스턴스에서는 사용할 수 없다.
function Person(name){this.name=name;}
Person.prototype.sayHello=function(){console.log(this.name)};
//정적 프로퍼티
Person.staticProp = "static prop";
//정적 메서드
Person.StaticMethod=function(){console.log("static Method")};
const me = new Person("홍길동");
Person.staticMethod(); //static Method
me.staticMethod(); //에러!
😑 왜 인스턴스에서는 생성자 함수의 정적 메서드를 사용할 수 없나요?
인스턴스에서 상속으로 사용할 수 있으려면, 해당 메서드가 인스턴스의 프로토타입 체인 내에 존재해야 상속받을 수 있다.
생성자 함수의 정적 프로퍼티/메서드는 프로토타입 체인이 아닌 Person 생성자 함수가 소유하고 있으므로 인스턴스가 사용할 수 없다.
객체 내에 특정 프로퍼티가 존재하는지 여부를 확인
해당 객체 내에 없을시 프로토타입 체인을 타고 올라가며 해당 프로퍼티를 찾는다
const person={name:"홍길동"};
console.log("name" in person); //true
console.log(Reflect.has(person, name)); //true
console.log(person.hasOwnProperty("name")); //true. 상위 프로토타입 검색x
strict mode는 언어의 문법을 좀 더 엄격히 적용하고
오류 발생 여지가 있는 코드에 대해 명시적인 에러를 발생시킨다.
strict mode는 스크립트(< script >) 단위로 적용된다
<script>
'use strict'
//엄격 모드 적용
</script>
<script>
//엄격모드 적용x
</script>
function foo(){x=10;}
foo();
console.log(x);
개발자의 의도와 상관없이 발생한 암묵적 전역은 오류를 발생시킬 위험이 크다!
delete 연산자로 변수, 함수, 매개변수를 삭제하면 오류가 발생한다.
strict mode를 적용하면 일반 함수에서의 this에 undefined가 바인딩된다.
strict mode를 적용하지 않으면 일반 함수에서의 this에 자신이 바인딩된다.
매개변수로부터 전달된 인수의 재할당이 반영되지 않는다.
ECMAScript 사양에 정의된 객체로 애플리케이션 전역의 공통 기능을 제공한다.
전역 객체 프로퍼티로써 제공되어 별도의 선언 없이 전역 변수처럼 사용이 가능하다.
ECMAScript 사양에는 정의되어 있지 않지만 JS 실행환경에서 추가로 제공하는 객체.
DOM. BOM, fetch, SVG, Web storage 등이 여기에 속한다.
원시값 중 string, number, boolean, symbol 값에 대해 객체처럼 접근하면 생성되는 임시 객체를 말한다.
const str="string";
console.log(str.length); // 이때 래퍼 객체(String 생성자 함수의 인스턴스)가 생성된다
//래퍼 객체의 프로퍼티나 메서드를 사용한 후 다시 원시값으로 되돌려진다.
//이후 래퍼 객체는 가비지 컬렉션에 의해 정리된다.

window, global..
코드가 실행되기 이전 단계에 JS 엔진에 의해 어떤 객체보다도 먼저 생성되는 객체.
어떤 객체에도 속하지 않는 최상위 객체이다.
🚨 키워드 별 전역 객체 특징
var로 선언한 전역 변수와 전역 함수는 전역객체의 프로퍼티가 된다.
let, const로 선언한 전역 변수는 전역객체의 프로퍼티가 아니며, 전역 렉시컬 환경의 선언적 환경 레코드 내에 존재하게 된다. (뭔 소리고..)
Infinity, NaN, undefined..
전역 객체의 프로퍼티.
eval, isFinite, isNaN..