#오늘 배운 것
생성자 내부에서 다른 생성자를 호출
this를 넘길 수 있기 때문. call과 apply를 통해 this를 유지 가능
function Person(name, gender) { //var ps = new person( )
this.name = name; //Person의 this가 아니라 student와Employee의 this다.
this.gender = gender;
}
function Student(name, gender, school) { //이름과,성별(person안에 있는것)이 다 필요하다
Person.call(this, name, gender); //person을 call(this)하면 반복해서 쓸 필요없다.
this.school = school; //student의 인스턴스를 person에 넣어주면 셋팅해 완성시킨다.
}
function Employee(name, gender, company) {
Person.apply(this, [name, gender]);
this.company = company;
}
var wj = new Student('원장', 'male', '서울대');
var tj = new Employee('투장', 'female', '삼성');
여러 인수를 묶어 하나의 배열로 전달할 때 apply 사용
최대/최솟값 예제
//비효율. number라는 배열의 최소값과 최대값 첫번째 부터 돌면서 비교
var numbers = [10, 20, 3, 16, 45];
var max = min = numbers[0];
numbers.forEach(function(number) {
if (number > max) {
max = number;
}
if (number < min) {
min = number;
}
});
console.log(max, min);
//효율
var numbers = [10, 20, 3, 16, 45];
var max = Math.max.apply(null, numbers); //인자값을 넣어주면 최대값을 반환해준다.배열이 들어가면X.
var min = Math.min.apply(null, numbers); //apply를 활요하면 null=this binding,number에 배열을 넣으면 됨.
console.log(max, min); //this : function, argArray를 넣어주면 된다.
//Spread Operation(ES6부터)
//https://paperblock.tistory.com/62
const numbers = [10, 20, 3, 16, 45];
const max = Math.max(...numbers);
const min = Math.min(...numbers);
console.log(max min);
bind 메서드
- call과 비슷하지만, 즉시 호출하지는 않고 넘겨받은 this 및 인수들을 바탕으로 새로운 함수를 반환하는 메서드
- 목적은 함수에 this를 미리 적용하는 것.부분 적용 함수 구현
var func = function (a, b, c, d) {
console.log(this, a, b, c, d);
};
func(1, 2, 3, 4); // window객체
var bindFunc1 = func.bind({ x: 1 }); //this
bindFunc1(5, 6, 7, 8); // { x: 1 } 5 6 7 8
var bindFunc2 = func.bind({ x: 1 }, 4, 5); //매개변수를 2개만 지정한다. binding1개와 1번째,2번째 매개변수는
bindFunc2(6, 7); // { x: 1 } 4 5 6 7 // 전달했기 때문에 4,5는 고정이다. 나머지 2개만 셋팅하면 된다.
bindFunc2(8, 9); // { x: 1 } 4 5 8 9
name 프로퍼티
bind 메서드를 적용해서 새로 만든 함수는 name 프로퍼티에 ‘bound’ 라는 접두 어가 붙음(추적하기가 쉬움)
this는 js내 에서 계속 바뀌기 때문에 추적하기 어렵다. name은 bind에 붙기 때문에 추적이 쉽다.
var func = function (a, b, c, d) {
console.log(this, a, b, c, d);
};
var bindFunc = func.bind({ x:1 }, 4, 5);
console.log(func.name); // func
console.log(bindFunc.name); // bound func
상위 컨텍스트의 this를 내부함수나 콜백 함수에 전달하기
내부함수
메서드의 내부함수에서 메서드의 this를 그대로 사용하기 위한 방법
self 등의 변수를 활용한 우회법보다 call, apply, bind를 사용하면 깔끔하게 처리 가능
var obj = {
outer: function() {
console.log(this); //this는 obj
var innerFunc = function () {
console.log(this);
};
innerFunc.call(this); //call을 사용하여 this를 할당해서 obj 유지
}
};
obj.outer();
//bind
var obj = {
outer: function() {
console.log(this);
var innerFunc = function () {
console.log(this);
}.bind(this);
innerFunc();
}
};
obj.outer();
콜백함수
콜백함수도 함수이기 때문에, 함수가 인자로 전달될 때는 함수 자체로 전달(this가 유실된다)
bind메서드를 이용해 this를 입맛에 맞게 변경 가능
var obj = {
logThis: function () {
console.log(this);
},
logThisLater1: function () { //정상동작X. setTimeout이 콜백함수인데 얘도 함수이기 때문에 this를 잃어버림
setTimeout(this.logThis, 500);
},
logThisLater2: function () { //this를 명확하게 넣어줬기 때문에 정상작동함.
setTimeout(this.logThis.bind(this), 1000);
}
};
화살표 함수의 예외사항
- 화살표 함수는 실행 컨텍스트 생성 시, this를 바인딩하는 과정이 제외
- 이 함수 내부에는 this가 아에 없으며, 접근코자 하면 스코프체인상 가장 가까운 this에 접근하게 됨
- this우회, call, apply, bind보다 편리한 방법
var obj = {
outer: function () {
console.log(this); //this = obj
var innerFunc = () => {
console.log(this); //innerFunc()함수 자체를 호출하게 되있어서 this를 잃어버렸는데
}; //화살표 함수를 쓰면 binding과정을 생략한다.
innerFunc();
};
};
obj.outer();
별도의 인자로 this를 받는 경우(콜백 함수 내에서의 this)
- 콜백 함수를 인자로 받는 메서드 중 일부는 추가로 this로 지정할 객체를 인자로 지정 할 수 있음
- 배열과 관련된 메서드에 많이 존재하며, set, map 등의 메서드에도 일부 존재함
// forEach 예시
var report = {
sum: 0,
count: 0,
add: function () { //add속성 - report로 되어있다.
var args = Array.prototype.slice.call(arguments);
//slice객체는 새로운 객체로 변환하는데 from to를 지정하지 않으면 객체(배열)을 그대로 지정한다.
//그러므로 args는 slice.call를 통해 args는 report배열로 바뀐다.
args.forEach(function (entry) { //report 배열이 들어가있다.
this.sum += entry; //콜백함수도 함수니까 window가 객체라 this를 사용할 수가 없는데
++this.count;
}, this); //,thisArgs - foreach문은 콜백함수 뒤에 thisArgs가 들어간다.
}, //설정하고자 하는 this를 넣으면 foreach문 안에서 활용이 가능하다. this : report다.
average: function () {
return this.sum / this.count;
},
};
report.add(60, 85, 95);
console.log(report.sum, report.count, report.average());
// 콜백 함수와 함께 thisArg를 인자로 받는 메서드
// forEach, map, filter, some, every, find, findIndex, flatMap, from, forEach(Set, Map)
콜백 함수란?
- 다른 코드의 인자로 넘겨주는 함수 (이 함수를 받는 주체가 있다. 넘겨받은 코드는 foreach.setTimeout 등등...필요에 따라 적절한 상황에 실행한다.제어권이 넘겨받은 코드가 가지고 있는 것)
- 콜백 함수를 넘겨받은 코드는 이 콜백 함수를 필요에 따라 적절한 시점에 실행(제어 권)
callback = call(부르다) + back(되돌아오다) = 되돌아와서 호출해줘!
- 즉, 콜백 함수는 다른 코드(함수 또는 메서드)에게 인자로 넘겨줌으로써 그 제어권 도 함께 위임한 함수. 콜백 함수를 위임받은 코드는 자체적으로 내부 로직에 의해 이 콜백 함수를 적절한 시점에 실행
ex. setT.. function(){},3000); -이 3000이 콜백함수라고도 할 수 있다.
제어권
var count = 0;
//timer : 콜백 내부에서 사용할 수 있는 '어떤 게 돌고있는지' 알려주는 id값
var timer = setInterval(function() {
console.log(count);
if(++count > 4) clearInterval(timer);// 콜백 함수
}, 300); //시간
var count = 0;
var cbFunc = function () { //function이라는 익명함수를 할당
console.log(count);
if (++count > 4) clearInterval(timer);
};
var timer = setInterval(cbFunc, 300); // 이게 없다면 사용자가 권한을 가진다.
//cbfunc를 인자로 넣는 순간 제어권은 setI으로 넘기게 된다.

인자
map 함수 예제
//Array.prototype.map(callback[, thisArg])
//-> this 생략하면 전역객체 바인딩
//callback: function(currentValue, index, array)
//map : 배열의 모든 요소를 꺼내어 처음부터 끝까지 콜백함수 반복호출 + 새로운 배열 리턴
var newArr = [10, 20, 30].map(function (currentValue, index) {
//map : callback함수 내의 로직을 배열의 1번째 요소부터 돌리면서 새로운 객체를 return해준다.
console.log(currentValue, index);
return currentValue + 5;
});
console.log(newArr);
//if .var newArr = [10, 20, 30].map(function (index, currentValue) 로 변경해여 출력하면
//결과 5,6,7을 출력 : map이라는 메소드는 callback을 인자로 받는데 첫번째는 currentValue,두번째는 index로 받아야한다.
//순서와 위치를 잘 넣어야한다.
결론 :제어권이 넘어갈 map 함수의 규칙에 맞게 ‘나는’ 호출해야 합니다!
this
- 콜백 함수도 함수이기 때문에 기본적으로는 this가 전역객체를 참조
- 제어권을 넘겨받을 코드에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우 에는 그 대상을 참조
- 별도의 this를 지정하는 방식과 제어권에 대한 이해가 중요합니다
// Array.prototype.map을 직접 구현해봤어요!
Array.prototype.map = function(callback, thisArg) { //map은 func(callback,)를 할당
var mappedArr = [];
for (var i = 0; i < this.length; i++) { //thisArg가 첫인자이므로 있으면 이걸로 없으면 window로 binding해라.라는 뜻.
var mappedValue = callback.call(thisArg || window
, this[i], i, this); //배열[i], i , 배열
mappedArr[i] = mappedValue;
}
return mappedArr;
};
// 이제 this에 다른 값이 담기는 이유를 알 수 있겠죠?
// : call메소드를 통해 maps value를 재정비 하는데 thisarg가 있으면 그걸로 바꾸고 없으면 window로 변경.
// [1, 2, 3].map(function() { ~~~~~ }, this);
- setTimeout은 내부에서 콜백 함수를 호출할 때, call 메서드의 첫 번째 인자에 //전역객체를 넘겨요 //따라서 콜백 함수 내부에서의 this가 전역객체를 가리켜요
- forEach도 마찬가지로, 콜백 뒷 부분에 this를 명시해주지 않으면 전역객체를 넘겨요!
- addEventListener는 내부에서 콜백 함수를 호출할 때, call 메서드의 첫 번째 인자에 addEventListener메서드의 this를 그대로 넘겨주도록 정의돼 있어요(상속) 앞의 this를 콜백함수로 쓸 수 있도록 정의해준다.그러므로 this유지가 가능.
콜백 함수는 함수다
콜백 함수로 어떤 객체의 메서드를 전달하더라도, 그 메서드는 메서드가 아닌 함수 로 호출
var obj = {
vals: [1, 2, 3],
logValues: function(v, i) {
console.log(this, v, i);
}
};
//method로써 호출
obj.logValues(1, 2);
//callback => obj를 this로 하는 메서드를 그대로 전달한게 아니에요
//obj.logValues가 가리키는 함수만 전달한거에요(obj 객체와는 연관이 없습니다)
[4, 5, 6].forEach(obj.logValues); // 메소드로써의 호출이지만 text만 가지고 온 것이다.
콜백 함수 내부의 this에 다른 값 바인딩하기
if. 콜백 함수 내부에서 this를 사용하지 않은 경우 - 결과만 원한다면
var obj1 = {
name: 'obj1',
func: function () {
console.log(obj1.name); //obj1의 name을 다이렉트로 가져왔기때문에 출력은 된다..
}
};
setTimeout(obj1.func, 1000);
//위의 수정버전
var obj1 = {
name: 'obj1',
func: function() {
var self = this; //이 부분! obj2
return function () {
console.log(self.name); //funcetion() { console.log('obj2') }와 같다.
}; //this가 아닌 콜백함수로 지정했으니 obj2로 유지가 된다.
}
};
var obj2 = { // func의 실행 주체.
name: 'obj2',
func: obj1.func //function() {}와 같음.
};
var callback2 = obj2.func(); //호출 주체는 obj2이다.
setTimeout(callback2, 1500);
var obj3 = { name: 'obj3' };
var callback3 = obj1.func.call(obj3);//return값은 같지만 obj3로 주체를 정했기 때문에 obj.name이 된다.
setTimeout(callback3, 2000); //funcetion() { console.log('obj3') }
//위 방법은 번거롭긴 해도 this를 우회적으로나마 활용하여 원하는 객체를 바라보게 할 수 있었어요!
가장 좋은 방법 → bind메서드의 활용
var obj1 = {
name: 'obj1',
func: function () {
console.log(this.name);
}
};
//함수 잡채를 obj1에 바인딩
setTimeout(obj1.func.bind(obj1), 1000); //bind메소드를 통해 obj1객체를 binding한다.
var obj2 = { name: 'obj2' }; //call/apply는 즉시실행이였지만 bind는 새로운 함수를 리턴하므로 가능.
//함수 잡채를 obj2에 바인딩
setTimeout(obj1.func.bind(obj2), 1500);
콜백 지옥과 비동기 제어
- 콜백 함수를 익명 함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 헬 수준인 경우
- 주로 이벤트 처리 및 서버 통신과 같은 비동기적 작업을 수행할 때 발생.가독성, 수정도 어려움
동기 : synchronous .현재 실행중인 코드가 끝나야 다음 코드를 실행하는 방식 .처리가 끝나면 다음꺼 처리
비동기 : a + synchronous ⇒ async
- 실행 중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어가는 방식
- setTimeout, addEventListner 등
- 별도의 요청, 실행 대기, 보류 등과 관련된 코드는 모두 비동기적 코드
웹의 복잡도가 올라갈 수록 비동기적 코드의 비중이 늘어남 = 콜백 지옥
비동기 작업의 동기적 표현(1) - Promise(1)
//new 연산자로 호출한 Promise의 인자로 넘어가는 콜백은 바로 실행돼요
//그 내부의 resolve(또는 reject) 함수를 호출하는 구문이 있을 경우
//resolve(또는 reject) 둘 중 하나가 실행되기 전까지는
//다음(then), 오류(catch)로 넘어가지 않아요
//따라서, 비동기작업이 완료될 때 비로소 resolve, reject 호출하는 방법으로
//비동기 -> 동기적 표현이 가능합니다
new Promise(function (resolve) {
setTimeout(function () {
var name = '에스프레소';
console.log(name);
resolve(name);
}, 500);
}).then(function (prevName) {
return new Promise(function (resolve) {
setTimeout(function () {
var name = prevName + ', 아메리카노';
console.log(name);
resolve(name);
}, 500);
});
}).then(function (prevName) {
return new Promise(function (resolve) {
setTimeout(function () {
var name = prevName + ', 카페모카';
console.log(name);
resolve(name);
}, 500);
});
}).then(function (prevName) {
return new Promise(function (resolve) {
setTimeout(function () {
var name = prevName + ', 카페라떼';
console.log(name);
resolve(name);
}, 500);
});
});
//promise가 성공했을 경우 then. 그 다음 resolve가 성공하면 then으로 간다.
비동기 작업의 동기적 표현(2) - Promise(2)
var addCoffee = function (name) {
return function (prevName) {
return new Promise(function (resolve) {
setTimeout(function () {
var newName = prevName ? (prevName + ', ' + name) : name; //resolve를 만나기 전까지 함수는 계속 된다.
console.log(newName);
resolve(newName);
}, 500);
});
};
};
addCoffee('에스프레소')()
.then(addCoffee('아메리카노'))
.then(addCoffee('카페모카'))
.then(addCoffee('카페라떼'));
//직전 예제의 반복부분을 함수화 한 코드에요
//클로저 개념이 나왔지만, 여기서는 skip 하고, 다음 chapter에서 다루게 될거에요
비동기 작업의 동기적 표현(3) - Generator
var addCoffee = function (prevName, name) {
setTimeout(function () {
coffeeMaker.next(prevName ? prevName + ', ' + name : name);
}, 500);
};
var coffeeGenerator = function* () { //*이 붙어있는게 제너레이터함수.yield를 만나기 전까지 stop
var espresso = yield addCoffee('', '에스프레소');
console.log(espresso);
var americano = yield addCoffee(espresso, '아메리카노');
console.log(americano);
var mocha = yield addCoffee(americano, '카페모카');
console.log(mocha);
var latte = yield addCoffee(mocha, '카페라떼');
console.log(latte);
};
var coffeeMaker = coffeeGenerator();
coffeeMaker.next();
//*가 붙은 함수가 제너레이터 함수
//제너레이터 함수 실행 시, Iterator 반환(next()를 가지고 있음)
//iterator 은 객체를 next 메서드로 순환 할 수 있는 객체다.
//next 메서드 호출 시, Generator 함수 내부에서 가장 먼저 등장하는 yield에서 stop
//이후 다시 next 메서드를 호출하면 멈췄던 부분 -> 그 다음의 yield까지 실행 후 stop
//즉, 비동기 작업이 완료되는 시점마다 next 메서드를 호출해주면 Generator 함수 내부
//소스가 위 -> 아래 순차적으로 진행
비동기 작업의 동기적 표현(4) - Promise + Async/await
var addCoffee = function (name) {
return new Promise(function (resolve) {
setTimeout(function(){
resolve(name);
}, 500);
});
};
var coffeeMaker = async function () { //비동기 작업을 수행코자 하는 함수
var coffeeList = '';
var _addCoffee = async function (name) {
coffeeList += (coffeeList ? ', ' : '') + await addCoffee(name);
};
await _addCoffee('에스프레소'); //실질적으로 수행할때는 앞에 await를 붙이므로써 순서를 기다린다.
console.log(coffeeList);
await _addCoffee('아메리카노');
console.log(coffeeList);
await _addCoffee('카페모카');
console.log(coffeeList);
await _addCoffee('카페라떼');
console.log(coffeeList);
};
coffeeMaker();
//ES2017에서 새롭게 추가된 async/await 문을 이용했어요
//비동기 작업을 수행코자 하는 함수 앞에 async
//함수 내부에서 실질적인 비동기 작업이 필요한 위치마다 await
//Promise ~ then과 동일한 효과를 얻을 수 있어요
#원격강의
DOM - document(html)를 js가 이해할 수 있도록 obj형태로 modeling한 것.
js가 생긴 이유 - 브라우저에서 사용할려고 만든 크르비트 언어
node.js에서도 사용하는 이유 - 성능이 좋다보니 js로도 이용해서 만듬.
런타임 환경 - 컴퓨터가 실행되는 동안 프로세스나 프로그램을 위한 소프트웨어 서비스를 제공하는 가상 머신의 상태
브라우저가 html파일을 해석한다(html를 오브젝트로 만든다) - parsing
- 브라우저에서는 렌더링 엔진이 있는데 , 엔진이 html문서에 코드를 보며 해석한다 그리고 dom tree를 구성한다.(html > head,body > mata,title, h1,p...)
- css가 포함되어있으면 cssom tree구성 > dom tree랑 묶어써 render tree
dom 브라우저 내장 api : chrome, vs code - dom이 내장되어있어 js에 접근/제어할 수 있다.
dom(tree)의 node는 속성(ex.키와값),메서드(()가 있어야 메소드다.ex.객체 안 함수)를 소유하고 있다.
선택할 수 있는 방법 --> select + or
1.태그 2.id 3.class
document로 console시작하는 이유 : 시작이 document니까...
document.getElementById('') - id로 가져올 때
document.getElementsByclassName('') - class로 가져올 때는ts인 이유 : id는 식별자, class는 특성을 공유하는 군집이기 때문에 묶어서 활용할 수 있다.
queryselector는 id,class둘 다 가능하기 때문에 id와 class인지 알려줘야한다.
queryselectorAll하면 (li)로하면 li를 다 가져온다.
새로운 node를 생성하는 것 == 새로운 tree에 가지치기를 한다는 것
const div = document.createElement('div');
document.body.append(div);
document.querySeletor('h1').innerHTML = 'text'; - 안의 내용이 text로 변경.태그포함 수정하면 태그속성까지 적용
document.querySeletor('h1').innerText = 'text'; - 안의 내용이 text로 변경.태그포함 수정하면 태그도 text로 인식

document.querySeletor(' ').style.속성(ex.fontsize...color...) = ' '; - 별도의 css없이도 속성을 변경할 수 있다.
document.querySeletor(' ').setAttribute(attribute('class id'), value('changeyellow..')) - class나 id에 명을 추가해준다.
write - 잘못 사용하면 안된다...모든 요소가 없어지고 write태그만 남는다..
document.querySeletor(' ').addEventListner("이벤트 타입(ex.click)",함수 {}) - 태그에 이벤트를 더해준다.
'[내일배움캠프] > TIL' 카테고리의 다른 글
| 22.12.05)React와 es6, 후발대 2일차를 배운 26일차 (0) | 2022.12.05 |
|---|---|
| 22.12.02)CS특강과후발대1일차를 배운 25일차 (0) | 2022.12.02 |
| 22.11.30)record,outer와 this를 배운23일차 (1) | 2022.11.30 |
| 22.11.29)js 데이터타입과 실행컨텍스트를 배운 22일차 (1) | 2022.11.29 |
| 22.11.28)팀플이 끝난 21일차 (0) | 2022.11.28 |