어떤 객체의 프로퍼티를 참조하거나 값을 할당할 때 해당 객체에 프로퍼티가 없을 경우, 그 객체의 프로토타입 객체를 연쇄적으로 보면서 프로퍼티를 찾는 방식 을 프로토타입 체인이라고 한다. 단, 참조할 때와 값을 할당할 때의 메커니즘이 다르니 기억해두어야 한다.
- 프로퍼티를 참조할 때
- 찾고자 하는 프로퍼티가 객체에 존재하면 사용한다.
- 없으면
[[Prototype]]
링크를 타고 끝까지 올라가면서 해당 프로퍼티를 찾는다.- 찾으면 그 값을 사용하고 없으면
undefined
를 반환한다.- 프로퍼티에 값을 할당할 때
- 찾고자 하는 프로퍼티가 객체에 존재하면 값을 바꾼다.
- 프로퍼티가 없고[[Prototype]]
링크를 타고 올라가서 해당 프로퍼티를 찾았을 경우
- 그 프로퍼티가 변경가능한 값, 즉writable: true
라면 새로운 직속 프로퍼티를 할당해서 상위 프로퍼티가 가려지는 현상이 발생한다.
- 그 프로퍼티가 변경불가능한 값, 즉writable: false
라면 비엄격 모드에선 무시되고 엄격 모드에선 에러가 발생한다.
- 해당 프로퍼티가 세터(setter) 일 경우, 이 세터가 호출되고 가려짐이 발생하지 않는다.
여기서 말하는 "가려짐" 이란, 상위 프로토타입 객체에 동일한 이름의 프로퍼티가 있는 경우, 하위 객체의 프로퍼티에 의해 가려지는 현상을 말한다.
function Student() { // this = {} this.name = "son"; this.age = 20; this.gender = "male"; this.introduce = function () { return `hello, my name is ${this.name}`; }; // return this } const student2 = new Student(); console.log(student1); //__proto__ : 생성자 함수의 prototype 객체를 가리(참조)킵니다 console.log(student1.__proto__); Student.prototype.introduce = function () { return `hello, my name is ${this.name}`; }; const student1 = { name: "son", age: 20, gender: "male", height: 185, introduce: function () { return `hello, my name is ${this.name}`; }, }; for (let key in student1) { console.log(student1[key]); } console.log(student["super age"]); // 마침표 연산자로 접근
자바스크립트는 클래스가 없다. 기존의 문법을 활용해서 편의상이나 기능을 더 한 문법을 -> 슈가 신테스(syntactic sugar)라고 한다 ES6에서 클래스가 추가되었지만, 그것은 문법적인 설명이다 자바스크립트는 프로토타입 기반의 언어이다 function Shape(color) { this.color = color; this.getColor = function () { return `이 도형의 색상은 ${this.color}입니다`; }; } const shape1 = new Shape("red"); console.log(shape1.color); console.log(shape1.getColor()); function Rectangle(color, width, height) { super.call(this, color); this.color = color; this.width = width; this.height = height; this.getArea = function () { return this.width * this.height; }; } class Car { // 정적 속성 static CREATED = "2002"; constructor(name, speed) { this.name = name; this.speed = speed; } set speed(speed) { if (speed < 0) { throw new Error("속도는 음수가 될 수 없습니다"); } this._speed = speed; } get peed() { return this._speed; } getCarName() { return `차 이름은 ${this.name}입니다`; } getSpeed() { return `현재 속도는 ${this.speed}입니다`; } 정적 메서드 static getSpec() { return "차는 타이어 4개와 문 4개가 있습니다."; } } const car1 = new Car("benz", 100); car1.name = "아우디" 이렇게하면 밑에 속성은 "차 이름은 아우디 입니다" console.log(car1); console.log(car1.getCarName()); // 차 이름은 benz입니다 console.log(car1.getSpeed()); // 현재 속도는 100입니다 console.log(car1.getSpec()); // 현재 속도는 100입니다 console.log(Car.getSpec()); // 정적 메서스 사용할때
동기(synchronous)란, 어떤 작업을 실행할 때 그 작업이 끝나기를 기다리는 방식을 의미한다. 즉, 작업이 완료될 때까지 다음 코드의 실행을 멈추고 기다리는 것이다. 이러한 방식은 작업의 순서를 보장하고, 작업이 끝날 때까지 결과를 기다리는 것이 가능하다.
비동기(asynchronous)란, 어떤 작업을 실행할 때 그 작업이 완료되지 않더라도 다음 코드를 실행하는 방식을 의미한다. 즉, 작업이 완료되지 않았더라도 결과를 기다리지 않고 다음 코드를 실행하는 것이다. 이러한 방식은 작업이 오래 걸리는 경우 시간을 절약하고, 병렬적인 작업 처리가 가능하다.
동기 방식으로 파일을 읽는다면 파일을 읽기 시작한 이후에 다음 코드를 실행하지 않고 파일이 읽혀지기를 기다린다. 반면에 비동기 방식으로 파일을 읽는다면 파일을 읽는 작업이 실행되는 동안 다른 작업을 수행할 수 있다.
**동기** 코드가 순차적으로 실행되는 것 코드의 순서가 보장이 되는 것 **비동기** 코드가 순차적으로 실행되지 않는 것 코드의 순서가 보장이 되지 않습니다. 자바스크립트는 싱글 스레드 언어입니다. 싱글 스레드 언어는 한번에 하나의 작업만 처리할 수 있습니다. 자바스크립트는 동기적으로 실행되는 언어입니다. 자바스크립트처럼 싱글 스레드 언어는 비동기적으로 실행되는 코드가 필요하다.
function test() { for (let i = 0; i < 10000; i++) { console.log(1); } console.log(2); } 콘솔에 2가 찍히려면 1만 번의 1이 찍힐 때까지 기다려야 한다.
function task1() { console.log("task1 시작"); // ... 시간이 엄청 오래걸리는 작업 setTimeout(() => { console.log("task1 시작"); }, 1000); } function task2() { console.log("task2 시작"); } task1(); task2();
**콜백함수** 콜백함수는 다른 함수의 매개변수로 전달되어 그 함수가 실행되는 동안 특정시점에 호출되는 함수를 말합니다. 동기 콜백 함수 콜백 함수가 동기적으로 실행되는 형태
function greeting(callback) { console.log("Hello"); callback(); } function goodbye() { console.log("goodbye"); } greeting(goodbye); 비동기 콜백 함수 비동기 작업이 끝난 다음에 호출되는 형태 function task1() { console.log("task1 시작"); // ... 시간이 엄청 오래걸리는 작업 setTimeout(() => { console.log("task1 시작"); callback(); }, 1000); } function task2(callback) { console.log("task2 시작"); callback(); } function task3() { console.log("task2 시작"); } function task4() { console.log("task2 시작"); } **콜백 지옥** task1(() => { task2(() => { task3(() => { task4(() => { console.log("작업 끝"); }); }); }); }); task1(task2);
비동기 작업을 처리할 수 있게 도와주는 객체 pending: 비동기 처리가 아직 수행되지 않은 상태 fulfilled: 비동기 처리가 수행된 상태 rejected: 비동기 처리가 실패한 상태 then, catch, finally
const myPromise = new Promise((resolve, reject) => { // 구현.. }) Promise 는 성공 할 수도 있고, 실패 할 수도 있다. 성공 할 때에는 resolve 를 호출해주면 되고, 실패할 때에는 reject 를 호출해주면 된다
1초 뒤에 성공시키는 예제 const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve(1); }, 1000); }); myPromise.then(n => { console.log(n); }); resolve 를 호출 할 때 특정 값을 파라미터로 넣어주면, 이 값을 작업이 끝나고 나서 사용 할 수 있다. 작업이 끝나고 나서 또 다른 작업을 해야 할 때에는 Promise 뒤에 .then(...) 을 붙여서 사용하면 된다
1초뒤에 실패하는 예제 const myPromise = new Promise((resolve, reject) => { setTimeout(() => { reject(new Error()); }, 1000); }); myPromise .then(n => { console.log(n); }) .catch(error => { console.log(error); }); reject 를 사용하고, .catch 를 통하여 실패했을시 수행 할 작업을 설정 할 수 있다
callback -> Promise 로 function task1() { return new Promise((resolve) => { setTimeout(() => { console.log("task1 시작"); resolve(); }, 1000); }); } function task2() { return new Promise((resolve) => { resolve(); }); } task1() // .then(() => task2()) .then(() => console.log("모든 작업 끝"));
async/await 문법은 ES8에 해당하는 문법으로서, Promise 를 더욱 쉽게 사용 할 수 있게 해준다 function apple(a) { return new Promise(resolve => setTimeout(resolve, a)); } async function phone() { console.log('안녕하세요!'); await apple(1000); // 1초쉬고 console.log('반갑습니다!'); } phone();
async/await 문법을 사용할 때에는, 함수를 선언 할 때 함수의 앞부분에 async 키워드를 붙인다, 그리고 Promise 의 앞부분에 await 을 넣어주면 해당 프로미스가 끝날때까지 기다렸다가 다음 작업을 수행 할 수 있다. 위 코드에서는 apple 이라는 함수를 만들어서 파라미터로 넣어준 시간 만큼 기다리는 Promise 를 만들고, 이를 phone 함수에서 사용함. 함수에서 async 를 사용하면, 해당 함수는 결과값으로 Promise 를 반환하게 됨
function apple(a) { return new Promise(resolve => setTimeout(resolve, a)); } async function phone() { console.log('안녕하세요!'); await apple(1000); // 1초쉬고 console.log('반갑습니다!'); } phone().then(() => { console.log('작업이 끝났어요!'); });
async 함수에서 에러를 발생 시킬때에는 throw 를 사용하고, 에러를 잡아낼 때에는 try/catch 문을 사용함
function apple(a) { return new Promise(resolve => setTimeout(resolve, ms)); } async function makeError() { await apple(1000); const error = new Error(); throw error; } async function phone() { try { await makeError(); } catch (e) { console.error(e); } } phone();