728x90
728x90

 

 

 

01 콜백 함수 callback function

 

요약 : 다른 코드의 인자로 넘겨주는 함수. 필요에 따라 넘겨받은 후 적절한 시점에 시행되며 제어권과 연관이 있다
어떤 이벤트가 발생한 후, 수행될 함수를 의미

 

다른 코드 (함수 또는 메서드)에게 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수
콜백 함수를 위임받은 코드는 자체적인 내부 로직에 의해 콜백 함수를 적절한 시점에 실행
JS에서 함수는 1급객체이므로, 인자 전달 시 함수를 전달할 수 있기 때문에 콜백함수가 가능

 

 

일급 객체는 ...

  • 변수나 데이터 구조 안에 담을 수 있다.
  • 파라미터로 전달 할 수 있다.
  • 반환값으로 사용 할 수 있다.
  • 런타임에 생성될 수 있다.

 

 

 

CallBack 뜻

call(부르다, 호출하다, 실행하다) + back (뒤돌아오다, 뒤돌다)
// 구글링에서는 called at the back ..이게 더 이해가 잘 간다.

= 함수 X를 호출하면서 특정 조건일 때 함수 Y를 실행해서 나에게 알려달라고 명령하는 것
-> 함수X는 해당 조건이 갖춰졌는지 여부를 스스로 판단하고 Y를 직접 호출한다

 

예 : 자동적으로 정해진 시간에 울리는 기상알람

-> 요청할 때마다 수동적으로 시간 정보를 제공할 필요 없이 
요청을 받은 뒤 자체적으로 수행하다가 적절한 시점에 수행 
즉 함수에게 요청을 하면서 일을 하는 명령에 대한 '제어권'을 스마트폰에게 넘긴 것

예 2 : 콜백 함수의 동작 방식은 일종의 식당 자리 예약과 같습니다. 일반적으로 맛집을 가면 사람이 많아 자리가 없습니다. 그래서 대기자 명단에 이름을 쓴 다음에 자리가 날 때까지 주변 식당을 돌아다니죠. 만약 식당에서 자리가 생기면 전화로 자리가 났다고 연락이 옵니다. 그 전화를 받는 시점이 여기서의 콜백 함수가 호출되는 시점과 같습니다. 손님 입장에서는 자리가 날 때까지 식당에서 기다리지 않고 근처 가게에서 잠깐 쇼핑을 할 수도 있고 아니면 다른 식당 자리를 알아볼 수도 있습니다.

자리가 났을 때만 연락이 오기 때문에 미리 가서 기다릴 필요도 없고, 직접 식당 안에 들어가서 자리가 비어 있는지 확인할 필요도 없습니다. 자리가 준비된 시점, 즉 데이터가 준비된 시점에서만 저희가 원하는 동작(자리에 앉는다, 특정 값을 출력한다 등)을 수행할 수 있습니다.

//https://joshua1988.github.io/web-development/javascript/javascript-asynchronous-operation/

 

 

 

즉시 실행 되는 동기식 콜백 예시 :

실행하면 이름을 입력하라는 알람창이 뜨고 입력했을 시에만 'Hello ' + name 이 뜨게 된다

 

function greeting(name) {
  alert('Hello ' + name);
}

function processUserInput(callback) {
  var name = prompt('Please enter your name.');
  callback(name);
}

processUserInput(greeting);

//https://developer.mozilla.org/en-US/docs/Glossary/Callback_function

 

실습 : https://jsfiddle.net/

 

 

 

비동기식 콜백 예시 : 


아래 예시는 submitBtn 클래스를 가진 요소를 클릭했을 때, 콜백 함수가 실행되는 jQuery 코드이다.
(jQuery : HTML의 클라이언트 사이드 조작을 단순화 하도록 설계된 크로스 플랫폼의 자바스크립트 라이브러리)

비동기 이벤트인 click에 대한 이벤트 리스너로 콜백 함수가 작성되었고 알림창을 띄우는 alert()를 호출중
click의 콜백 함수는 naming을 할 필요가 없는 익명함수로 대부분의 콜백 함수는 이렇게 익명함수로 작성됨

 

$(".submitBtn").click(function(){
    alert("제출버튼을 클릭했습니다!");
})
//https://victorydntmd.tistory.com/48

 

 

 

비동기 처리 :  특정 코드의 연산이 끝날때까지 기다려주지 않고 다음 코드가 먼저 실행된다.

비동기 관련 메서드 : setTimeout(),  .then(), fetch() 등등 아래에서 다룰 것이다. setTimeOut()은 대충 얼마간 기다려주는 함수 느낌인데 비동기 처리 방식의 간단한 문제점으로는 setTimeout()메서드가 실행되고 n초를 기다릴동안, 그 다음 코드는 기다려 주지않고 실행되기 때문에-즉, 비동기로 처리되기 때문에 문제가 있을 수 있다.

콜백함수를 통해 특정함수가 처리가 된 이후에 처리시킬 함수를 콜백함수화 시키면 비동기처리의 문제점을 해결 할 수 있다. 비동기방식을 사용하는 ajax 통신 코드도 콜백 함수로 개선할 수 있다.

 

결론 : 콜백함수는 특정 로직이 끝났을때 원하는 동작을 실행시키는 함수라고 이해하면 된다.
콜백함수를 통해 특정함수가 처리가 된 이후에 처리시킬 함수를 콜백함수화 시키면 비동기처리의 문제점을 해결 할 수 있다.

 

 

 

 

02 제어권

 

4-2-1 호출 시점

 

var count = 0;
var timer = setInterval(function(){
	console.log(count);
	if(++count > 4) clearInterval(timer);
}, 300);

 

setInterval을 호출할 때 두 개의 매개변수를 전달 (익명 함수, 300) 했습니다.
setInterval의 구조는 다음과 같습니다.

 

var intervalID = scope.setInterval(func, delay [, param1, param2, ...]);

 

scope : Window 객체나 Worker의 인스턴스가 들어옵니다. (두 객체 모두 setInterval 메서드 제공)
func, delay : 값 전달 필수. 세 번째 매개변수([ ] 안의 것들) 부터는 선택
delay : 밀리초(ms) 단위의 숫자. 매 ms마다 func에 넘겨준 함수가 실행
param1, param2, .. : func 함수 실행 시 매개변수로 전달할 인자

setInterval을 실행하면 반복적으로 실행되는 내용 자체를 특정할 수 있는 고유한 ID 값이 반환됩니다.
setInterval 함수는 리턴 값 없이 매개변수안에 있는 실행구문을 실행시켜주고 끝이 아니라, 코드 내 유일한 timer id를 int 형태로 반환합니다. (timer id값은 clearInterval 함수로 타이머 함수를 종료시킬 때도 사용 가능한 유니크 키 값)


 

 

 

같은 코드를 좀 수정했습니다. timer 변수에는 setInterval의 ID 값이 담깁니다. setInterval에 전달한 첫 번째 인자 cbFunc 콜백 함수는 0.3초마다 자동 실행됩니다. 콜맥 함수 내부에서 count 값을 출력하고 , 1 증가시킨 뒤 그 값이 4보다 크면 반복 실행을 종료합니다.

 

var count = 0;
var cbFunc = function(){
	console.log(count);
	if(++count > 4) clearInterval(timer);
};
var timer = setInterval(cbFunc, 300);

 

cbFunc()의 호출 주체와 제어권은 모두 사용자이며, setInterval의 호출주체와 제어권은 setInterval입니다. setInterval이라는 다른 코드에 첫 번째 인자로 cbFunc 함수를 넘겨주자 제어권을 넘겨받은 setInterval이 스스로 판단, 적절한 시점에 익명 함수를 실행합니다 => 콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수 호출 시점에 대한 제어권을 가짐

 

 

 

 

4-2-2 인자

 

var newArr = [10, 20, 30].map(function(currentValue, index) {
	console.log(currentValue, index);
	return currentValue + 5;
});
console.log(newArr);
var newArr = [10, 20, 30].map(function(currentValue, index) {
	console.log("1", currentValue, index);
	return currentValue + 5;
});
console.log("2",newArr);

 

 

map 메서드의 동작 방식을 알기 위해 Array의 prototype에 담긴 map 메서드의 구조를 알아보겠습니다. 

 

Array.prototype.map(callback[, thisArg]);
callback: function(currentValue, index, array)

 

map 메서드는 첫 번째 인자로 callback 함수를 받고, 생략 가능한 두 번째 인자로 콜백 함수 내부에서 this로 인식할 대상을 특정할 수 있습니다. 생략할 경우 일반 함수처럼 전역객체가 바인딩됩니다.

map 메서드는 메서드의 대상이 되는 배열의 모든 요소들을 처음부터 끝까지 하나씩 꺼내 콜백 함수를 반복 호출하고,
콜백 함수의 실행 결과들을 모아 새 배열을 만듭니다.

콜백 함수의 인자에는 순서대로 배열의 요소 중 현재값, 현재값의 인덱스, map 메서드의 대상이 되는 배열 자체가 담깁니다. 콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수를 호출할 때 인자에 어떤 값들을 순서로 넘길 것인지에 대한 제어권을 가집니다.

 

 

 

 


4-2-3 this

 

별도의 this를 지정하는 방식과 제어권에 대한 이해를 높이기 위해 임의로 map 메서드를 직접 구현합니다.

 

Array.prototype.map = function(callback, thisArg) {
	var mappedArr = [];
	for(var i=0; i<this.length; i++) {
		var mappedValue = callback.call(thisArg || window, this[i], i, this);
		mappedArr[i] = mappedValue;
	}
	return mappedArr;
};

 

메서드 구현의 핵심은 call/apply 메서드에 있습니다. this에는 thisArg 값이 있을 경우 thisArg 값을, 없을 경우 전역객체를 지정합니다.

첫 번째 인자에는 메서드의 this가 배열을 가리킬 것이므로 배열의 i번째 요소 값을, 두 번째 인자에는 i값을, 세 번째 인자에는 배열 자체를 지정해 호출합니다. 그 결과가 변수 mappedArr 에 담겨 mappedArr의 i번째 인자에 할당됩니다.

제어권을 넘겨받을 코드에서 call/apply 메서드의 첫 번째 인자에 콜백 함수 내부에서의 this가 될 대상을 명시적으로 바인딩하기 때문에 this에 다른 값이 담기는 것입니다.

 

setTimeout(function() {console.log(this); }, 300);   // (1) Window { ... }

[1,2,3,4,5].forEach(function (x) {
	console.log(this);  // (2) Window { ... }
});

document.body.innetHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a').addEventListener('click', function(e) {
	console.log(this, e);  // (3) <button id="a">클릭</button>
	}   // MouseEvent { isTrusted: true, ... }
);

 

각각 콜백 함수 내 this를 살펴보겠습니다.

(1)의 setTimeout은 내부에서 콜백 함수를 호출할 때 call 메서드의 첫 번째 인자에 전역객체를 넘기기 때문에 콜백함수 내부에서의 this는 전역객체입니다.

(2)의 forEach는 '별도의 인자로 this를 받는 경우'지만 별도의 인자로 this를 넘기지 않았기 때문에 전역객체를 가리킵니다.

(3)의 addEventListener내부에서 콜백 함수를 호출할 때 call 메서드의 첫 번째 인자에 addEventListener 메서드의 this를 그대로 넘기도록 정의되어 있어서 콜백 함수 내부에서의 this가 addEventListener를 호출한 주체인 HTML Element를 가리키게 됩니다.

 

 

 

 

 

03 콜백 함수는 함수다

 

콜백 함수로 어떤 객체의 메서드를 전달하든 관계없이 그 메서드는 함수로서 호출됩니다.

 

// 4-7 메서드를 콜백 함수로 전달한 경우

var obj = {
	vals : [1, 2, 3],
	logValues : function(v, i) {
		console.log(this, v, i);
	}
};

obj.logValues(1, 2);
// 메서드로 정의 및 호출
// this는 obj, 인자는 1과 2
// { vals: [1, 2, 3], logValues: f } 1 2

[4, 5, 6].forEach(obj.logValues);
// forEach 함수의 콜백함수로 전달 
// obj.logValues가 가리키는 함수만 전달했는데 이 함수는 메서드로서 호출할 때가 아니면
// obj와의 연관이 없다
// this는 window (전역객체)
// 메서드로 정의되어 있지만 콜백으로 넘어가면 함수가 된다
// Window { ... } 4 0
// Window { ... } 5 1
// Window { ... } 6 2

 

● 메서드와 함수의 차이 (클래스 함수 vs 함수)

함수가 더 포괄적인 의미입니다. 메서드는 클래스/구조체/열거형 내부에 작성된 것

 

 

 

 

 

04 콜백 함수 내부의 this에 다른 값 바인딩하기

 

객체의 메서드를 콜백 함수로 전달하면 해당 객체를 this로 바라볼 수 없지만, 콜백 함수 내부에서 this가 객체를 바라보게 하려면 별도의 인자로 this를 받는 함수는 원하는 값을 넘기면 되고 그렇지 않은 경우 this의 제어권도 넘겨주게 되므로 사용자가 임의로 원하는 값을 바꿀 수 없습니다.

그래서 this를 다른 변수에 담아 콜백 함수로 활용할 함수에서 그 변수를 사용하고, 이를 클로저로 만드는 방식을 많이 씁니다.

 

// 4-8 콜백 함수 내부의 this에 다른 값을 바인딩하는 방법(1)

var obj1 = {
	name : 'obj1',
	func : function() {
		var self = this;
		return function() {
			console.log(self.name);
		};
	}
};

var callback = obj1.func();
setTimeout(callback, 1000);

 

obj1.func 메서드 내부에서 self라는 변수에 this를 담고 익명 함수를 선언과 동시에 반환합니다.
obj1.func를 호출하면 내부 함수가 반환되어 callback 변수에 담깁니다.
callback을 setTimeout 함수에 인자로 전달하면 1초 뒤 callback이 실행되면서 'obj1'을 출력합니다.

 

// 4-9 콜백 함수 내부에서 this를 사용하지 않은 경우

var obj1 = {
	name : 'obj1',
	func : function() {
		console.log(obj1.name);		
	}
};

setTimeout(obj1.func, 1000);

 

this를 사용하지 않고 같은 결과를 도출하는 예입니다. 간결하나 this의 다양한 활용은 물 건너 갔습니다.
obj1를 다른 객체에 재활용하는 상황의 코드입니다.

 

// 4-10 예제 4-8의 func 함수 재활용

var obj1 = {
	name : 'obj1',
	func : function() {
		var self = this;
		return function() {
			console.log(self.name);
		};
	}
};

var callback = obj1.func();
setTimeout(callback, 1000);

var obj2 = {
	name : 'obj2',
	func : obj1.func
};

var callback2 = obj2.func();
setTimeout(callback2, 1500);

var obj3 = { name: 'obj3' };
var callback3 = obj1.func.call(obj3);
setTimeout(callback3, 2000);

 

callback2에는 obj1.func를 복사한 obj2.func를 실행한 결과를 담아 콜백으로 사용했습니다.
callback3은 obj1.func를 실행하면서 this를 obj3가 되도록 지정해 콜백으로 사용했습니다.
실행 시점으로부터 1.5초 후 'obj2', 2초 후에는 'obj3'이 출력됩니다.

 

// 4-11 콜백 함수 내부의 this에 다른 값을 바인딩하는 방법 (2) - bind 메서드 활용

var obj1 = {
	name : 'obj1',
	func : function() {
			console.log(self.name);		
	}
};

setTimeout(obj1.func.bind(obj1), 1000);

var obj2 = { name: 'obj2' };
setTimeout(obj1.func.bind(obj2), 1500);

 

위와 같이 ES5의 bind 메서드를 활용하는 방법도 있습니다.

 

 

 

 

 

05 콜백 지옥과 비동기 제어

 

콜백 지옥이란 콜백 함수를 익명 함수로 전달하는 과정이 반복되는 것으로 JS에서 흔히 발생하는 문제입니다. 이벤트 처리나 서버 통신 등 비동기 작업을 수행하기 위해 이 형태가 등장하는데 가독성이 떨어지며 코드 수정이 어려운 문제점이 있습니다.

동기적인 코드는 현재 실행중인 코드가 완료되고 나서 다음 코드를 실행하는 방식이며 비동기적인 코드는 현재 실행중인 코드의 완료 여부와 무관하게 다음 코드로 넘어가는 것입니다.

CPU의 계산에 의해 즉시 처리 가능한 대부분의 코드는 동기적 코드입니다.
반면 사용자의 요청에 의해 특정 시간이 경과되기 전까지 어떤 함수의 실행을 보류하거나 사용자의 직접적 개입이 있을 때 어떤 함수를 실행하도록 대기하거나, 웹브라우저 외 별도의 대상에 무언가를 요청하고 응답을 받았을 때 어떤 함수를 실행하도록 대기하는 등 별도의 요청, 실행 대기, 보류 등과 관련된 코드는 비동기적 코드입니다.

 

// 4-12 콜백 지옥 예시

setTimeout(function (name) {
	var coffeeList = name;
	console.log(coffeeList);
    
	setTimeout(function(name) {
		coffeeList += ', ' + name;
		console.log(coffeeList);

		setTimeout(function(name) {
			coffeeList += ', ' + name;
			console.log(coffeeList);

			setTimeout(function(name) {
				coffeeList += ', ' + name;
				console.log(coffeeList);
			}, 500, '카페라떼');
		}, 500, '카페모카');
	}, 500, '아메리카노');
}, 500, '에스프레소');

 

 

0.5초마다 커피 목록을 수집해 출력하는 결과를 보입니다. 각 콜백은 커피 이름을 전달하고 목록에 이름을 추가합니다.
값이 전달되는 순서가 아래에서 위로 향하고 있어 어색하며 가독성도 좋지 않습니다.

이를 해결하는 방법은 익명의 콜백 함수를 모두 기명함수로 전환하는 것입니다.

 

// 4-13 콜백 지옥 해결 - 기명 함수로 변환

var coffeeList = '';

var addEspresso = function(name) {
	coffeeList = name;
	console.log(coffeeList);
	setTimeout(addAmericano, 500, '아메리카노');
};

var addAmericano = function(name) {
	coffeeList += ', ' + name;
	console.log(coffeeList);
	setTimeout(addMocha, 500, '카페모카');
};

var addMocha = function(name) {
	coffeeList += ', ' + name;
	console.log(coffeeList);
	setTimeout(addLatte, 500, '카페라떼');
};

var addLatte = function(name) {
	coffeeList += ', ' + name;
	console.log(coffeeList);
};

setTimeout(addEspresso, 500, '에스프레소');

 

코드의 가독성이 좋아지고 순서대로 함수를 읽는 데에도 어려움이 없습니다.
변수의 외부 노출 문제도 즉시 실행 함수 등으로 전체를 감싸는 것으로 해결 가능합니다.

일회성 함수를 변수에 할당하는 것이 단점인데, 
ES6의 Promise, Generator 등과 ES2017의 async/await 등으로 수정해 볼 수 있습니다.
아래 코드는 이해가 어렵다면 패스해도 됩니다.

 

// 4-14 비동기 작업의 동기적 표현(1) - Promise(1)

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 + ', 아메리카노';
			consoel.log(name);
			resolve(name);
			}, 500);
	});
}).then(function (prevName) {
	return new Promise(function (resolve){
		setTimeout(function () {
			var name = prevName + ', 카페모카';
			consoel.log(name);
			resolve(name);
			}, 500);
	});
}).then(function (prevName) {	
	return new Promise(function (resolve){
		setTimeout(function () {
			var name = prevName + ', 카페라떼';
			consoel.log(name);
			resolve(name);
			}, 500);
	});
});

 

new 연산자와 함께 호출한 Promise의 인자로 넘겨주는 콜백 함수는 호출할 때 바로 실행되지만 그 내부에 resolve 또는 reject 함수를 호출하는 구문이 있을 경우 둘 중 하나가 실행되기 전까지 다음(then) 또는 오류 구문(catch)로 넘어가지 않습니다.

따라서 비동기작업이 완료될 때, resolve/reject 를 호출하는 방법으로 비동기 작업의 동기적 표현이 가능합니다.

 

// 4-15 비동기 작업의 동기적 표현(2) - Promise(2)

var addCoffee = function(name) {
	return function(prevName) {
		return new Promise(function (resolve) {
			setTimeout(function() {
				var newName = prevName ? (prevName + ', ' + name) : name;
				console.log(newName);
				resolve(newName);
			}, 500);
		});
	};
};

addCoffee('에스프레소')()
	.then(addCoffee('아메리카노'))
	.then(addCoffee('카페모카'))
	.then(addCoffee('카페라떼'));

 

 

 

4-15는 4-14를 더욱 짧게 표현했는데, 2~3번째 줄은 클로저가 사용되었습니다. 클로저는 차후 다룹니다.

 

// 4-16 비동기 작업의 동기적 표현(3) - Generator

var addCoffee = function(prevName, name) {
	setTimeout(function (){
    	coffeeMaker.next(prevName ? prevName + ', ' + name : name);
	}, 500);
};

var coffeeGenerator = function* () { //제너레이터 함수
	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();

 

제너레이터(generator)를 사용하면 여러 개의 값을 필요에 따라 하나씩 반환(yield)할 수 있습니다.
제너레이터 함수를 실행하면 Iterator가 반환되는데, Iterator는 next라는 메서드를 가지고 있습니다.

iternator : 배열이나 유사한 자료 구조 내부의 요소를 순회(traversing)하는 객체입니다.
build-in object 중 iterable을 갖고 있는 객체는 아래 5가지입니다.

 

Array.prototype[@@iterator]()
TypedArray.prototype[@@iterator]()
String.prototype[@@iterator]()
Map.prototype[@@iterator]()
Set.prototype[@@iterator]()


이 next 메서드를 호출하면 Generator 함수 내부에서 가장 먼저 등장하는 yield에서 함수의 실행을 멈춥니다.
이후 다시 next 메서드를 호출하면 멈췄던 부분부터 시작해서 그 다음에 등장하는 yield에서 함수의 실행을 멈춥니다.
즉, 비동기 작업이 완료되는 시점마다 next 메서드를 호출해준다면 Generator 함수 내부의 소스가 위에서부터 아래로 순차 진행됩니다.

yield : 제너레이터 함수(function*  또는 레거시 generator 함수)를 중지하거나 재개하는데 사용
(재개 시 expression 의 값은 제너레이터의 caller로 반환)|

 

[rv] = yield [expression];

 

ES2017에서는 가독성이 뛰어나면서 작성법도 간단한 기능의 async/await 추가되었습니다.
비동기 작업을 수행하고자 하는 함수 앞에 async를 표기하고, 함수 내부에서 실질적인 비동기 작업이 필요한 위치마다 await를 표기하는 것만으로 뒤의 내용을 Promise로 자동 전환하고, 해당 내용이 resolve 된 이후에 다음으로 진행합니다.
Promise의 then과 흡사한 효과를 얻을 수 있습니다.

 

// 4-17 비동기 작업의 동기적 표현(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('에스프레소');
	console.log(coffeeList);
	await _addCoffee('아메리카노');
	console.log(coffeeList);
	await _addCoffee('카페모카');
	console.log(coffeeList);
	await _addCoffee('카페라떼');
	console.log(coffeeList);
};
coffeeMaker();
728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
함수의 기본 메소드 중 중요한 call, apply, bind에 대해서.

 


함수의 실행은 1)선언 후 호출하거나 (함수 뒤에 () 붙이기) 2)call, apply해서 할 수 있다

함수는 함수객체라고 불린다. 객체는 (변수)프로퍼티와 함수형태인 프로퍼티를 갖는데 여기서 함수인 프로퍼티를 메서드라고 부른다. 객체는 .(점 연산자)를 통해 자신의 프로퍼티인 메서드를 사용할 수 있다.

함수이름.call() , 함수이름.apply() , 함수이름.bind()

//https://velog.io/@rohkorea86/this-%EC%99%80-callapplybind-%ED%95%A8%EC%88%98-mfjpvb9yap

 

부모인 Function.Prototype으로 부터 call,apply,bind을 물려받았기 때문이다. 자바스크립트는 프토토타입을 기반의 언어로 객체를 상속하는 언어이다. 그래서 모든 함수(function)는 call,apply,bind(프로퍼티)를 호출 할 수 있다.

call, apply, bind는 함수 자신의 실행"환경"을 외부 this로 설정할 수 있는 것이 주요한 특징이다.
첫번째 인수 없이도 에러 없이 작동하는데 없을 경우 자동적으로 전역객체를 가리키게 된다.

 

 

bind

경우에 따라서 this는 획획 바뀔 수 있기 때문에 this를 고정시키는 방법이 존
bind함수를 사용하면 this는 내가 정한 object로 고정된다.

어떠한 함수이건 메소드이건 bind라는 함수를 사용할 수 있다.
bind 함수는 함수가 가리키는 this만 바꾸고 호출하지는 않는다.

 

bind는 직역하면 묶는다. 결속시키다. 서로의 관계를 맺게 한다.” 로 해석

태그등에 특정 사건이 일어 났을 경우, 원하는 함수를 실행시켜 주는 명령어
bind
이벤트 타입과 함수가 매개 변수들로 들어간다. 이벤트 타입은 클릭, 마우스 오버 등의 사건을 지칭하며, 함수는 이러한 사건이 일어 났을 때 실행될 함수를 의미 한다.

보통, bind에 들어 가는 함수명은 on으로 시작하거나 Handler로 끝나는 경향이 있다. 꼭 그렇게 정해진 것은 아니나 on Handler로 이름이 정해지면,  bind와 연결된 함수라는 것을 직관적으로 인지 할 수 있기 때문이다.

onDown, onPlaneMouseDown, downHandler, planeMouseDownHandler ...


unbind bind와 반대되는 개념이라고 보면 된다. bind로 연결된 함수를 제거한다.

 

 

 

 

call, apply

bind와 같은 역할 (this 고정) +실행까지 한다.
공통적으로 가진 null 인자의 역할은 this를 대체하는 것이다.

call : 보통 함수와 똑같이 인자를 넣어 파라미터를 하나씩 넘기고
apply : 인자를 하나로 묶어 배열로 넘긴다

 

var example = function (a, b, c) {
  return a + b + c;
};
example(1, 2, 3);
example.call(null, 1, 2, 3);
example.apply(null, [1, 2, 3]);

 

아래 예시를 보면 다른 객체의 함수를 자기 것마냥 사용한다.
call,apply,bind메서드는 외부에서 할당하는 첫번째 인자가 그 함수의 this가 된다. 

 

var obj = {
  string: 'zero',
  yell: function() {
    alert(this.string);
  }
};
var obj2 = {
  string: 'what?'
};
obj.yell(); // 'zero';
obj.yell.call(obj2); // 'what?'

// https://www.zerocho.com/category/JavaScript/post/57433645a48729787807c3fd

 

주로 사용은 위 메소드들을 쓰는 예로, 함수의 arguments를 조작할 때 사용

arguments :함수라면 처음부터 갖고 있는 숨겨진 속성이며 바로 함수에 들어온 인자를 유사 배열 형식으로 반환 
유사배열은 배열의 메소드를 쓸 수 없어 call이나 apply과 함께join, slice, concat 등의 메소드를 사용한다.

 

function example() {
  console.log(arguments);
}
example(1, 'string', true); // [1, 'string', true]

// https://www.zerocho.com/category/JavaScript/post/57433645a48729787807c3fd

 

 

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

https://www.it-swarm.asia/ko/javascript/%ec%9d%b4%eb%a6%84%ec%9c%bc%eb%a1%9c-%ec%bf%a0%ed%82%a4-%ea%b0%80%ec%a0%b8-%ec%98%a4%ea%b8%b0/1066889074/

 

javascript — 이름으로 쿠키 가져 오기

나는 이렇게했다. 그래서 내가 값을 분리하기 위해 접근 할 객체를 얻는다. 이걸로 부모에게 쿠키를 넘겨 줄 수 있고, 그런 다음에 키로 값에 접근 할 수있다. var cookies=getCookieVal(mycookie); alert(cookies.mykey); function getCookieVal(parent) { var cookievalue = $.cookie(parent).split('&'); var obj = {}; $.each(cookieval

www.it-swarm.asia

 

 

http://magic.wickedmiso.com/72

 

[JavaScript] Cookie 생성, 삭제 및 읽어오기

■ 쿠키 개요 -. 쿠키는 키와 값이 들어 있는 작은 데이터 조각으로 이름, 값, 파기 날짜와 경로 정보를 가진다. -. 쿠키는 서버와 클라이언트에서 모두 저장하고 사용할 수 있다. -. 쿠키는 일정 기간 동안 데이..

magic.wickedmiso.com

https://jonnung.tistory.com/12

 

[Javascript] 쿠키(cookie) 생성,보기,삭제 예제 소스_펌


http://jun.hansung.ac.kr/CWP/Javascript/JavaScript%20Cookies.html

 

JavaScript Cookies

JavaScript Cookies 쿠키(Cookies) 는 웹 페이지에 사용자 정보를 저장할 수 있게 해줍니다. What are Cookies? 쿠키(Cookies)는 사용자의 컴퓨터에 작은 텍스트 파일에 저장된 데이터입니다. 웹 서버가 브라우저에 웹 페이지를 전송한 경우, 연결이 종료된 후, 서버는 사용자에 대한 모든 것을 잊게 된다. 쿠키는 "어떻게 사용자에 대한 정보를 기억할 것인가?" 라는 문제를 해결하기 위해 발명되었다 : 사용자가 웹 페이지를

jun.hansung.ac.kr

https://epthffh.tistory.com/entry/JavaScript-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%B0%B0%EC%97%B4-Cookie-%EC%A0%80%EC%9E%A5%ED%95%98%EA%B8%B0

 

[JavaScript] 문자열, 배열 Cookie 저장하기

/** * 쿠키저장 * @param cname 키값 * @param cvalue 저장할 문자열 * @param exdays 쿠키 저장 일수 */ setCookie: function( cname, cvalue, exdays ) { var d = new Date(); d.setTime(d.getTime() + (exdays*..

epthffh.tistory.com

https://panocafe.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8B%A4%EC%A4%91-%EC%BF%A0%ED%82%A4-%EC%A0%80%EC%9E%A5-%EB%B0%8F-%EC%9D%BD%EC%96%B4%EC%98%A4%EA%B8%B0

 

[자바스크립트]다중 쿠키 저장 및 읽어오기

쿠키이름 : txtName, 쿠키값: 레드 쿠키이름 : txtemail, 쿠키값: test@a.com

panocafe.tistory.com

https://lktprogrammer.tistory.com/39

 

08 쿠키를 사용한 로그인 상태 유지하기

쿠키를 이용한 로그인 상태 유지하기 웹 사이트의 기본 기능 중 하나는 로그인/로그아웃 기능입니다. 로그인을 하지 않은 상태에서 웹 사이트에 연결을 하면 로그인을 하도록 유도를 하는데, 이는 로그인을 했는지..

lktprogrammer.tistory.com

https://zero-gravity.tistory.com/245

 

[jQuery/javascript] 쿠키(Cookie)를 이용한 ID 저장.

보통 로그인을 할 때 보면 아이디를 입력하는 칸 오른쪽에 id저장하기 체크박스가 있는 것을 볼 수 있다. 체크를 하면 다음에 그 페이지를 열었을 때, 다시 입력하지 않아도 저장된 아이디가 입력되어있다. 아래..

zero-gravity.tistory.com

 

https://zero-gravity.tistory.com/299

 

[Java] 쿠키(Cookie) 생성/조회/삭제

쿠키는 javascript로도 다룰 수 있지만, 자바스크립트로는 간단하게만 구현할 수 있어서 쿠키로 좀더 뭔가를 하기 위해선 자바를 사용할 수밖에 없다. 아래의 예들을 구현하기 위해 사용한 자바 소스를 공유한다...

zero-gravity.tistory.com

 

http://moonstoneit.blogspot.com/2013/06/blog-post.html

 

오늘본 상품 소스

여기저기 돌아다니다가 보고 만든 코드.. 오른쪽 상단에 떠있는 레이어로 나오도록 추가했다. 1.=============================================== 쿠키를 굽는 소스, 상품상세페이지 첫상단에 코드를 추가해주면 된다. ...

moonstoneit.blogspot.com

 

https://jangjeonghun.tistory.com/entry/javaScript-%EC%B5%9C%EA%B7%BC-%EB%B3%B8-%EC%83%81%ED%92%88

 

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
상황별로 this가 어떻게 달라지는지, 왜 그런지, 예상과 다른 대상을 가르킬 경우 원인을 효과적으로 추적하는 방법을 정리했습니다.

 

 

다른언어와 자바스크립트 this 의 차이점

대부분 객체지향언어 this : 클래스로 생성한 인스턴스 객체클래스에서만 사용할 수 있다
자바스크립트
this : 어디서든 사용 가능하며 상황에 따라 this가 바라보는 대상이 달라진다.

따라서 정확한 작동 방식을 이해해야 의도한 대상을 가리키게 할 수 있다.
함수와 객체(메서드)의 구분이 느슨한 자스에서 this는 이 둘을 구분하는 실질적으로 거의 유일한 기능

 

 

01 상황에 따라 달라지는 this

this는 실행컨텍스트가 생성될 때(함수를 호출할 때) 함께 결정 => this는 함수를 호출할 때 결정된다.
함수를 어떤 방식으로 호출하냐에 따라 값이 달라짐

 

1. 전역 공간에서의 this

전역 컨텍스트를 생성하는 주체가 전역 객체이기 때문에 전역공간에서 this는 전역 객체를 가리킨다.
전역 객체는 자바스크립트 런타임 환경에 따라 다른 이름과 정보를 가진다.
(브라우저 환경에서 전역객체는 window이고 Node.js 환경에서는 global이다.)

console.log(this === window);

 

전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로 할당한다.  => 변수이면서 객체의 프로퍼티
자바스크립트의 모든 변수는 특정 객체의 프로퍼티로서 동작하여 1을 출력하게 된다.

 

var a = 1;

// 모두 1
console.log(a);
console.log(window.a);
console.log(this.a);

 

사용자가 var 연산자를 이용, 변수를 선언할 때 실제 자바스크립트 엔진은 어떤 특정 객체의 프로퍼티로 인식하는 것
특정 객체실행 컨텍스트의 LexicalEnvironment실행컨텍스트는 변수를 수집해서 L.E의 프로퍼티로 저장한다.
이후 어떤 변수를 호출하면 L.E를 조회해서 일치하는 프로퍼티가 있을 경우 그 값을 반환하며 전역 컨텍스트의 경우 L.E는 전역객체를 그대로 참조하는 것. 더 정확하게는 GlobalEnv가 전역 객체를 참조하는데 전역 컨텍스트의 L.E가 GlobalEnv를 참조함

 


※ a를 직접 호출할 때도 1이 나오는 이유?

변수 a에 접근하고자 하면 스코프 체인에서 a를 검색
하다가 가장 마지막에 도달하는 전역 스코프의 L.E, 즉 전역객체에서 해당 프로퍼티 a를 발견해서 그 값을 반환한다. 편하게 window.가 생략된다고 받아들여도 된다. 
따라서 전역 공간에서는 var로 변수를 선언하는 대신 window의 프로퍼티에 직접 할당하더라도 똑같이 동작한다.

그러나 삭제의 경우 다른 결과를 불러올 수 있다. c, d처럼 처음부터 전역객체의 프로퍼티로 할당한 경우는 삭제가 되나 
전역변수로 선언한 경우 삭제가 되지 않는다. 혹시나 사용중 실수로 삭제할 것에서 방어하는 것으로 전역변수를 선언하면 자바스크립트엔진이 자동으로 전역객체의 프로퍼티로 할당하면서 해당 프로퍼티의 configurable 속성 (변경 삭제 가능성)을 false로 정의한다. 

var a = 1;
delete window.a; //false
console.log(a, window.a, this.a); //1 1 1

var b = 2;
delete b; //false  (window.b)
console.log(b, window.b, this.b); //2 2 2

window.c = 3;
delete window.c; //true
console.log(c, window.c, this.c); //Uncaught ErferenceError : c is not defined

window.d = 4;
delete d; //true
console.log(d, window.d, this.d); //Uncaught ErferenceError : D is not defined


delete 연산자는 객체의 속성을 제거합니다. 제거한 객체의 참조를 어디에서도 사용하지 않는다면 나중에 자원을 회수합니다.

-> var로 선언한 전역변수와 전역객체의 프로퍼티는 호이스팅 여부 및 configurable 여부에서 차이를 보인다.


 

 

2. 메서드로 호출할때 메서드 내부에서의 this

함수를 실행하는 일반적인 방법은 함수로서 호출하는 경우와 메서드로 호출 하는 경우가 있다.
함수와 메서드는 미리 정의한 동작을 수행하는 코드 뭉치로 이 둘의 차이는 독립성에 있다.
함수는 그 자체로 독립적인 기능을 수행하며, 메서드는 자신을 호출한 대상 객체에 관한 동작을 수행한다.

초보의 경우 메서드를 객체의 프로퍼티에 할당된 함수로 이해하나 
어떤 함수를 객체의 프로퍼티에 할당한다 해서 무조건 메서드가 되지는 않고
객체의 메서드로서 호출할 경우에만 메서드로 동작하고, 아니면 함수로 동작한다.

 

 

3. 함수로서

 

...

 

<발표>----------------------------------------------------------------------------------------------------

 

함수 호출이 발생할 때 상황에 따라 this가 자동으로 바인딩 되는 것을 알 수 있다.
자바스크립트는 내부적 this바인딩 외에도 명시적 this바인딩시키는 방법을 제공한다.

 


 

02 명시적으로 this를 바인딩하는 방법

앞의 규칙 외에 this에 별도의 대상을 바인딩 하는 방법도 있습니다.
이 메서드들은 모든 함수의 부모 객체인 Function.prototype 객체의 메서드이므로 모든함수에서 호출가능

 

2-1 call 메서드 

call 메서드는 메서드의 호출 주체인 함수를 즉시 실행하도록 하는 명령

Function.prototype.call(thisArg[, arg1[, arg2[, ...]]])

 

(1) 함수를 실행할 때

이 때 call 메서드의 첫 번째 인자를 this로 바인딩하고, 이후의 인자들을 호출할 함수의 매개변수로 함
함수를 그냥 실행하면 this는 전역객체를 참조하지만 call 메서드를 이용하면 임의의 객체를 this로 지정할 수 있다.

 

var func = function(a,b,c) {
	console.log(this, a, b, c);
};

func(1,2,3); // Window  1 2 3  ----this가 window
func.call({x:1}, 4,5,6); // Object 4 5 6   ---- this가 {x:1}

 

실습하기 : https://jsfiddle.net/

 

(2) 메서드를 실행할 때 

메서드일 경우도 객체의 메서드를 그냥 호출하면 this는 객체를 참조하지만 call메서드를 사용하면 임의의 객체를 this로 지정할 수 있다.

 

var obj = {
	a: 1,
	method: function (x,y) {
		console.log(this.a, x, y);
	}
};

obj.method(2, 3);  // 1 2 3
obj.method.call({a:4}, 5, 6); // 4 5 6

 

 

 

 

2-2 apply 메서드

Function.prototype.apply(thisArg[, argsArray])

 

call 메서드와 기능적으로 완전히 동일하나 call 메서드첫 번째 인자를 제외한 나머지 모든 인자들을 호출할 함수의 매개변수로 지정하는 반면, apply 메서드는 두 번째 인자를 배열로 받아 그 배열의 요소들을 호출할 함수의 매개변수로 지정한다.

 

var func = function(a,b,c) {
	console.log(this, a, b, c);
};


func.apply({x:1}, [4,5,6]); //{x:1} 4 5 6

var obj = {
	a:1,
	method: function(x,y) {
		console.log(this.a, x, y);
	}
};
obj.method.apply({a:4}, [5,6]); //4 5 6

 

실습하기 : https://jsfiddle.net/

 

 

 

 

2-3 call / apply 메서드의 활용

1)유사배열객체에 배열메서드 적용, 2)생성자 내부에서 다른 생성자를 호출,
3)여러 인수를 묶어 하나의 배열로 전달하고 싶을 때 사용한다.

 

1. 유사배열객체에 배열 메서드를 적용

 배열의 구조와 유사한 유사배열객체에 call / apply 메서드를 이용해 배열 메서드를 사용한다.

 

유사배열 객체란? array-like object

key가 0이나 양의 정수인 프로퍼티가 존재하고
length 프로퍼티의 값이0 또는 양의 정수인 객체
객체에는 배열 메서드를 직접 적용할 수 없다.



유사배열과 배열 차이

Array.isArray(이름); 을 돌려서 true/false 값으로 확인
유사배열 즉 객체의 경우 배열의 메서드를 쓸 수 없다.

 

배열 메서드인 push를 객체 obj에 적용해 프로퍼티 3에 'd'를 추가
slice메서드를 적용해 객체를 배열로 전환. call 메서드를 이용해 원본인 유사배열객체의 얕은 복사를 수행, slice가 배열 매서드이기 때문에 복사본을 배열로 반환

 

1) 유사배열객체에 배열 메서드를 적용

 

var obj = {
	0:'a',
	1:'b',
	2:'c',
	length : 3
};
Array.prototype.push.call(obj, 'd');  // push : 마지막에 추가
console.log(obj); // { 0:'a', 1:'b', 2:'c', 3:'d', length : 4}

var arr = Array.prototype.slice.call(obj);  // slice : 배열의 일부를 선택하여 새로운 배열을 만듦
console.log(arr); // ['a', 'b', 'c', 'd']

 

실습하기 : https://jsfiddle.net/

 

 

# 예시에 나온 새로운 함수
push() 메서드

배열의 끝에 하나 이상의 요소를 추가하고, 배열의 새로운 길이를 반환 참고
slice() 메서드

시작 인덱스값과 마지막 인덱스값을 받아 시작값부터 마지막값의 앞부분까지의 배열 요소를 추출하는 메서드
매개변수를 아무것도 넘기지 않으면 어떤 배열의 begin부터 end까지(end 미포함)에 대한 원본 배열의 얕은 복사본을 반환합니다. (원본 배열은 수정되지 않습니다.) 참고
jbAry.slice( 2, 5 ); // start, end

// jbAry 배열의 3번째 요소부터 5번째 요소까지 선택합니다.
// end에 값이 없으면 해당 배열의 마지막 요소까지 선택합니다. 
// 값이 음수면 마지막 요소를 기준으로 선택합니다.

 

 


2) arguments, NodeList에 배열 매서드를 적용

함수 내부에서 접근할 수 있는 arguments 객체도 유사배열객체이므로 위 방법으로 배열로 전환해서 활용할 수 있다. querySelectorAll, getElementsByClassName 등의 Node 선택자의 선택 결과인 NodeList도 마찬가지입니다.

function a() {
    var argv = Array.prototype.slice.call(arguments);
    console.log(arguments);  // length: 3 __proto__: Object 0: 1 1: 2 2: 3
    console.log(argv);  // length: 3 __proto__: Array(0)

    argv.forEach(function (arg) {
       console.log(arg);  //1 2 3
    });
}
a(1,2,3);

document.body.innerHTML = '<div>a</div><div>b</div><div>c</div>';  //뿌리기

var nodeList = document.querySelectorAll('div'); 
console.log(nodeList);  // length: 3 __proto__: NodeList

var nodeArr = Array.prototype.slice.call(nodeList);
console.log(nodeArr);  // length: 3 __proto__: Array(0)

nodeArr.forEach(function (node) {
	console.log(node);   // 세 개의 div 태그 안에 각각 감싸진 a b c 
});

 

실습하기 : https://jsfiddle.net/

 

 

 

 


3) 문자열에 배열 메서드 적용

 

배열처럼 인덱스와 length 프로퍼티를 지니는 문자열도 call/apply 메서드를 이용해서 배열 메서드를 적용 가능하나 문자열의 경우 length 프로퍼티는 읽기전용이라서 원본 문자열에 변경을 가하는 메서드인 push, pop, shift, unshift, splice 등은 에러가 나며 concat 처럼 대상이 반드시 배열이어야만 하는 경우에도 에러는 안나도 제대로된 결과를 뱉지 않음

 

var str = 'abc def';

Array.prototype.push.call(str, ', pushed string'); 
// Error : Cannot assign to read only pro

Array.prototype.concat.call(str, 'string'); //[String {"abc def"}, "string"]

Array.prototype.every.call(str, function(c) {return char !== ''; }); //false

Array.prototype.some.call(str, function(c) {return char !== ''; }); //true


var newArr = Array.prototype.map.call(str, function(c) {return char + '!'; });
console.log(newArr);

var newStr = Array.prototype.reduce.apply(str, [function(string, char, i) 
	{return string + char + i;}, '' ]);
console.log(newArr);

 

실습하기 : https://jsfiddle.net/

 

사실 call/apply 방법으로 형변환하는 것은 this를 원하는 값으로 지정해서 호출한다는 본래의 메서드 의도와는 다소 동떨어진 활용법이며 slice 메서드는 오직 배열 형태로 복사하기 위해서 사용됐다.

 

 

4) ES6의 Array.from 메서드

경험을 통해 뜻을 아는 사람이 아닌 이상 딱 봐선 모를 수 있으니ES6에서는 사배열객체 또는 순회 가능한 모든 종류의 데이터타입을 배열로 전환하는Array.from 메서드를 새로 도입했다.

Array.from() 메서드는 유사 배열 객체(array-like object)나 반복 가능한 객체(iterable object)를 얕게 복사해 새로운 Array 객체를 만듭니다.  참고

 

var obj = {
	0: 'a',
	1: 'b',
	2: 'c',
	length: 3
};
var arr = Array.from(obj);
console.log(arr);  // ['a', 'b', 'c']

 

다음과 같은 경우에 Array.from()으로새 Array를 만들 수 있습니다.

  • 유사 배열 객체 (length 속성과 인덱싱된 요소를 가진 객체)

  • 순회 가능한 객체 (Map, Set 등객체의 요소를 얻을 수 있는 객체)

 

console.log(Array.from('foo'));
// expected output: Array ["f", "o", "o"]

console.log(Array.from([1, 2, 3], x => x + x));
// expected output: Array [2, 4, 6]

 

실습하기 : https://jsfiddle.net/

 

 

 

2) 생성자 내부에서 다른 생성자를 호출

생성자 내부에 다른 생성자와 공통된 내용이 있을 시 call/apply를 이용해 다른 생성자를 호출하면 반복을 줄일 수 있다. 예문에서는 생성자 함수 내부에서 다른 생성자 함수를 호출해서 인스턴스의 속성을 정의했다

 

function Person(name, gender) {
	this.name = name;
	this.gender = gender;
}
function Student(name, gender, school) {
	Person.call(this, name, gender);
	this.school = school;
}
function Employee(name, gender, company) {
	Person.apply(this, [name, gender]);
	this.company = company;
}
var by = new Student('하나', 'female', '교대');
var jn = new Employee('보영', 'female', '구글');

console.log(by);  // Student {name: "하나", gender: "female", school: "교대"}
console.log(jn);  // Employee {name: "보영", gender: "female", company: "구글"}

 

실습하기 : https://jsfiddle.net/

 

 


3) 여러 인수를 묶어 하나의 배열로 전달하고 싶을 때

여러 개의 인수를 받는 메서드에게 하나의 배열로 인수들을 전달하고 싶을 때 apply를 사용한다.

 

예 > 배열에서 최대/최소값을 구해야 할 경우
var numbers = [10, 20, 3, 16, 45];
var max = min = numbers[0];

numbers.forEach(function(number){
	if(number > max) {
		console.log(max);    
		max = number;

  }
	if(number < min) {
		console.log(min);    
		min = number;
  }
});

console.log(max, min);  //45 3

 

실습하기 : https://jsfiddle.net/

 

 

ES5에서의 Math.max, Math.min 활용

 

Math.max / Math.min 메서드에 apply를 적용하면 코드가 많이 단축된다 

 

var numbers = [10, 20, 3, 16, 45];
var max = Math.max.apply(null, numbers);
var min = Math.min.apply(null, numbers);

console.log(max, min);  //45 3

 

Math.max() : 함수는 0이상의 숫자 중 가장 큰 숫자를 반환 
만약 아무 요소도 주어지지 않았다면 -Infinity로 반환
만약 인수 중 하나라도 숫자로 변환하지 못한다면 NaN로 반환
ex)Math.max(10, 20); // 20

Math.min() : 함수는 주어진 숫자들 중 가장 작은 값을 반환 
만약 주어진 인자값이 없을 경우, Infinity 가 반환
적어도 1개 이상의 인자값이 숫자형으로 변환이 불가능 한 경우, NaN 가 반환

 

 

ES6에서의 Math.max, Math.min 펼치기연산자 활용

Es6에서는 spread operator (펼치기연산자, 전개구문)를 이용하면 apply보다 더욱 간결함

 

var numbers = [10, 20, 3, 16, 45];
var max = Math.max(...numbers);
var min = Math.min(...numbers);

console.log(max, min);  //45 3

 

전개 구문을 사용하면 배열이나 문자열과 같이 반복 가능한 문자를 0개 이상의 인수 (함수로 호출할 경우) 또는 요소 (배열 리터럴의 경우)로 확장하여, 0개 이상의 키(key)-값(value)의 쌍으로 객체로 확장시킬 수 있다.
=> apply() 대체

인수 목록의 모든 인수는 전개 구문을 사용할 수 있으며, 여러번 사용될 수도 있습니다.

 

 

call/apply 메서드는 명시적으로 별도의 this를 바인딩하면서 함수나 메서드를 실행하는 좋은 방법이지만
이로 인해 this를 예측하기 어렵게도 만들어 코드 해석을 방해하는 단점이 있음
그러나 ES5 이하 환경에서는 대안이 없어 실무에서 광범위하게 사용된다

 

 

 

 

2-4 bind 메서드

 

ES5에서 추가된 기능
call과 비슷하나 즉시 호출하지 않고 넘겨받은 this와 인수들을 바탕으로 새로운 함수를 반환만 하는 메서드
새로운 함수를 호출할 때 인수를 넘기면 기존 bind메서드를 호출할 때 전달했던 인수들의 뒤에 이어서 등록

 

목적

  • 함수에 this를 미리 적용한다
  • 부분 적용 함수를 구현한다

 

var func = function (a, b, c, d){
	console.log(this, a, b, c, d);
};
func(1, 2, 3, 4);  
//Window {parent: global, opener: null, top: global, length: 0, frames: Window, …} 1 2 3 4

var bindFunc1 = func.bind({ x: 1 });
bindFunc1(5,6,7,8); //{x: 1} 5 6 7 8

var bindFunc2 = func.bind({ x: 1 }, 4, 5);
bindFunc2(6,7); //{x: 1} 4 5 6 7
bindFunc2(8,9);  //{x: 1} 4 5 8 9

 

실습하기 : https://jsfiddle.net/

 

 

 

name 프로퍼티

bind 메서드를 적용해서 새로 만든 함수는 name 프로퍼티에 bind의 수동태인 'bound'라는 접두어가 붙는다. 장점 : 코드 추적에 call이나 apply보다 수월하다.


예 ) bound xxx : 함수명이 xxx인 워본 함수에 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를 내부함수나 콜백 함수에 전달하기

이전의 self 변수를 활용한 우회법보다 call, apply, bind 메서드로는 더 깔끔한 처리 가능
아래는 call, bind내부함수에 this를 전달하는 방법

 

var obj = {
	outer: function(){
		console.log(this);  //{outer: ƒ}
		var innerFunc = function(){
			console.log(this);  //{outer: ƒ}
		};
    innerFunc.call(this);
    console.log(this); //{outer: ƒ}
    console.log(innerFunc(this)); //Window {parent: global, opener: null, top: global, length: 0, frames: Window, …}
  }
};
obj.outer();
var obj = {
	outer: function(){
		console.log(this);  //{outer: ƒ}
		var innerFunc = function(){
			console.log(this);  //{outer: ƒ}
		}.bind(this);
    innerFunc(this);
    console.log(this); //{outer: ƒ}    
  }
};
obj.outer();

 

 

콜백 함수를 인자로 받는 함수나 메서드 중에서 기본적으로 콜백 함수 내에서의 this에 관여하는 함수나 메서드에 대해서도 bind 메서드를 사용하면 this값을 사용자 편의에 따라 바꿀 수 있다

 

var obj = {
  logThis: function() {
    console.log(this); 
  },
  logThisLater1: function() {
    setTimeout(this.logThis, 500); 
  },
  logThisLater2: function() {
    setTimeout(this.logThis.bind(this), 1000); 
  },
};
obj.logThisLater1();  //Window {parent: global, opener: null, top: global, length: 0, frames: Window, …}
obj.logThisLater2();  //{logThis: ƒ, logThisLater1: ƒ, logThisLater2: ƒ}

 

실습하기 : https://jsfiddle.net/

 

 

 

2-5 화살표 함수의 예외사항

ES6에 새롭게 도입된 함수로 실행 컨텍스트 생성 시 this를 바인딩하는 과정이 제외
화살표 함수 내부에는 this가 아예 없으며 접근하고자 하면 스코프체인상 가장 가까운 this에 접근

 

var obj = {
	outer : function(){
		console.log(this);  //{outer: ƒ}
		var innerFunc = () => {
			console.log(this);  //{outer: ƒ}
		};
		innerFunc();  
	}
};
obj.outer();

 

상위 컨텍스트의 this를 내부함수나 콜백함수에 전달하기 예제를 화살표 함수로 바꾼 것
이렇게 하면 별도의 변수로 this를 우회하거나 call/bind/apply를 적용할 필요 없이 더욱 간결하고 편리하다

 

 

 

 

2-6 별도의 인자로 this를 받는 경우 (콜백 함수 내에서의 this)

 

콜백 함수는 다음 장에서 이어하기에 this와  관련된 부분만 간단히 짚는다
콜백 함수를 인자로 받는 메서드 중 일부는 추가로 this로 지정할 객체 (thisArg)를 인자로 지정할 수 있는 경우가 있다
이러한 메서드의 thisArt 값을 지정하면 콜백 함수 내부에서 this 값을 원하는 대로 변경할 수 있다

이런 형태는 여러 내부요소에 대해 같은 동작을 반복해야하는 배열 메서드에 많이 포진
ES6의 Set, Map 등 메서드에서도 일부 존재한다.

 

대표적인 배열 메서드인 forEach의 예

 

// report 객체의 프로퍼티 : sum, count  
// report 객체의 메서드 : add, average

var report = {
	sum: 0,
	count: 0,
    
	// add 메서드는 arguments를 배열로 변환해서 args 변수에 담고
	// 배열을 순회하면서 콜백 함수를 실행

	add: function(){
		var args = Array.prototype.slice.call(arguments);
        
        // 콜백 함수 내부에서의 this : forEach 함수의 두 번째 인자로 전달해준 this가 바인딩됨

		args.forEach(function (entry){
			this.sum += entry;
			++this.count;
		}, this);
	},
    
    // 메서드
    
	average : function(){
		return this.sum / this.count;
	}
};

// 괄호 안 숫자들을 인자로 삼아 add메서드를 호출하면 
// 세 인자를 배열로 만들어 forEach 메서드가 실행
// 콜백 함수 내부의 this는 이제 add 메서드에서의 this가 전달된 상태므로
// this(report)를 가리키고 있으므로 순회하면서 report.sum, report.count 값이 변경

report.add(60, 85, 95);
console.log(report.sum, report.count, report.average()); //240 3 80

 

실습하기 : https://jsfiddle.net/

 

 

콜백 함수와 함께 thisArg를 인자로 받는 메서드

forEach 외에도 thisArg를 인자로 받는 메서드는 여러개 있다

Array.prototype.forEach();
Set.prototype.forEach();
Map.prototype.forEach();

Array.prototype.map();
Array.prototype.filter();
Array.prototype.some();
Array.prototype.every();
Array.prototype.find();
Array.prototype.findIndex();
Array.prototype.flatMap();
Array.prototype.from();

 

 


 

요    약

 

 

명시적이지 않은 this

  • 전역 공간에서의 this는 전역객체를 참조
  • 어떤 함수의 메서드로서 호출한 경우 this는 메서드 호출 주체(메서드명 앞의 객체)를 참조
  • 어떤 함수를 함수로서 호출한 경우 this는 전역 객체를 참조 (메서드 내부함수에서도 같음)
  • 콜백 함수 내부에서 this는 해당 콜백 함수의 제어권을 넘겨받은 함수가 정의한 바에 따르며 정의하지 않은 경우 전역객체를 참조
  • 생성자 함수에서 this는 생성될 인스턴스를 참조

 

명시적 this 바인딩의 규칙

  • call, apply 메서드는 this를 명시적으로 지정하면서 함수 또는 메서드를 호출
  • bind 메서드는 this와 함수에 넘길 인수를 일부 지정해서 새로운 함수를 생성
  • 요소를 순회하면서 콜백 함수를 반복 호출하는 내용의 일부 메서드는 별도의 인자로 this를 받기도 함

 

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

 

01 실행 컨텍스트 execution context


실행컨텍스트는 자스에서 중요한 개념 중에 하나이며 클로저를 지원하는 언어에서 유사한 개념이 적용되어 있다.

실행컨텍스트란 실행할 코드에 제공할 환경 정보들을 모아놓은 객체
자바스크립트 언어의 동적 성격이 잘 드러나는 개념이다.

어떤 실행컨텍스트가 활성화되는 시점에 선언된 변수를 위로 끌어올리고 (호이스팅)
외부 환경 정보를 구성하고, this 값을 설정 하는 등의 동작을 수행하는데 여기서 고유 현상이 발생 (어떤 현상인지는 안나옴ㅋ)



스택 stack

세탁바구니에 세탁물을 넣는 것과 같은 구조다. 많은 프로그래밍 언어들은 스택이 넘칠 때 에러를 뱉는다.
비어있는 스택에 순서대로 데이터 a b c d 를 저장하면 꺼낼 때 반대 순서( d c b a)로 밖에 못 꺼낸다.

 

큐 queue

베란다 호스 안의 흐르는 물과 같다. 한 쪽은 입력만, 다른 한쪽은 출력만을 담당하는 구조로
비어있는 큐에 순서대로 데이터 a b c d 를 저장하면 꺼낼 때는 a b c d 순서로 밖에 못 꺼낸다.

 

동일한 환경(하나의 실행 컨텍스트를 구성할 수 있는 방법으로 전역공간, 함수, eval()함수 등) 에 있는 코드를 실행할 때
필요한 환경 정보들을 모아 컨텍스트를 구성하고
이를 콜 스택에 쌓아올렸다가 
가장 위에 쌓여있는 컨텍스트와 관련있는 코드들을 실행하는 식으로
전체 코드의 환경과 순서를 보장한다.

--> 자동으로 생성되는 전역공간과 eval을 제외하면 실행컨텍스트를 구성하는 방식은 통상적으로 함수를 실행하는 것.
그리고 ES6에서는 블록 [ ]에 의해서도 새로운 실행 컨텍스트가 생성된다.

 

var a = 1;
function outer(){
	function inner(){
		console.log(a); // undefined
		var a = 3;
	}
	inner(); 
	console.log(a); // 1
}
outer();
console.log(a); // 1

 

...38페이부터 볼 것

 

 

02 VariableEnvironment, LexicalEnvironment

서로 담기는 내용은 같지만 VariableEnvironment는 최초 실행 시의 스냅샷을 유지하는 차이점이 있다.


728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
브라우저에서 쿠키 조회


브라우저의 쿠키는 key, value로 이루어져 간단한 정보를 저장됩니다.
Web Site마다 별도의 Cookie를 생성하고 저장하며

왼쪽에는 name(key의 이름) 오른쪽에는 value(key의 값)이 있는 id=member 같은 형태로 저장됩니다.
가장 흔히 사용되는 경우가 자동로그인을 하기 위해서 id와 password를 기억해 두는 것입니다.

Cookie를 이용해서 이외에 다양한 작업들을 할 수 있지만,
사용자가 브라우저의 쿠키를 지워버리면 모든 정보가 없어지는 특징이 있으며
쿠키는 개인 정보를 노출할 수도 있어서 보안적인 측면에서 취약합니다. 
그래서 암호화해서 저장하기도합니다.

 

Internet Explorer에서 쿠키 조회하는 방법

Web Site에 접속 -> F12 -> 네트워크 -> url -> 쿠키를 선택 

 

우측란에 쿠키요청 / 응답 쿠키 란으로 나뉘어서 오고간 값이 나옵니다.

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

텍스트를 채워넣어야 할 때 의미없는 문장들을 만들어주는 사이트.
로렘입섬의 한글 버전이라고 보면 되겠습니다.

 

 

 

한글입숨 - 무의미한 한글 텍스트 생성기

한글판 로렘입숨. 무의미한 한글 텍스트를 생성해 줍니다.

hangul.thefron.me

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
javascript 배열 관련 메서드 push pop

 

 

Array.prototype.pop()

 

기능

pop()  메서드는 배열에서 마지막 요소를 제거하여 그 값을 호출자(caller)에게 반환합니다.

 

문법

arr.pop()

 

반환값

배열에서 제거한 나머지 요소.
빈 배열의 경우 undefined 반환 .

 

예시

const plants = ['broccoli', 'cauliflower', 'cabbage', 'kale', 'tomato'];

console.log(plants.pop()); // "tomato"
console.log(plants); // Array ["broccoli", "cauliflower", "cabbage", "kale"]

 

 

 

 

Array.prototype.push()

 

기능

push()  메서드는 배열의 끝에 하나 이상의 요소를 추가하고, 배열의 새로운 길이를 반환합니다.
배열을 닮은 객체에 call() 또는 apply()로 사용될 수 있습니다. (예시 참고)
만약 length 속성이 숫자로 변환 될 수 없다면 인덱스는 0을 사용합니다.

 

문법

arr.push(element1[, ...[, elementN]])

 

매개변수

elementN : 배열의 끝에 추가할 요소.

 

반환값

호출한 배열의 새로운 length 속성.

 

예시

const animals = ['pigs', 'goats', 'sheep'];

const count = animals.push('cows');

console.log(count); // 4. 두 개를 추가하면 5
console.log(animals); // Array ["pigs", "goats", "sheep", "cows"]

 

여러 배열을 합치기 : 두 번째 배열의 모든 element를 push하기 위해 apply() 사용

var vegetables = ['설탕당근', '감자'];
var moreVegs = ['셀러리', '홍당무'];

Array.prototype.push.apply(vegetables, moreVegs);
console.log(vegetables); // ['설탕당근', '감자', '셀러리', '홍당무']

 

 

 

 

 

Array.prototype.shift()

 

기능

shift() 메서드는 배열에서 첫 번째 요소를 제거하고, 제거된 요소를 반환합니다.
이 메서드는 배열의 길이를 변하게 합니다.

shift 메서드는 0번째 위치의 요소를 제거 하고 연이은 나머지 값들의 위치를 한 칸씩 앞으로 당기고 제거된 값을 반환 합니다. 만약 배열의 length가 0이라면 undefined를 리턴 합니다.

 

문법

arr.shift()

 

반환값

배열에서 제거한 요소.
빈 배열의 경우 
undefined 를 반환합니다.

 

예시

const array1 = [1, 2, 3];
const firstElement = array1.shift();

console.log(array1);// Array [2, 3]
console.log(firstElement); // 1

 

배열에서 한 요소 제거하기

 

var myFish = ['angel', 'clown', 'mandarin', 'surgeon'];

console.log('myFish before: ' + myFish);
// angel,clown,mandarin,surgeon"

var shifted = myFish.shift(); 

console.log('myFish after: ' + myFish); 
// clown,mandarin,surgeon" 

console.log('Removed this element: ' + shifted); 
// "angel"

 

shift() 메서드는 while 문의 조건으로 사용되기도 합니다. 아래 코드에서는 while 문을 한번 돌 때 마다 배열의 다음 요소를 제거하고, 이는 빈 배열이 될 때까지 반복됩니다.

 

var names = ["Andrew", "Edward", "Paul", "Chris" ,"John"];

while( (i = names.shift()) !== undefined ) {
    console.log(i);
}
// Andrew, Edward, Paul, Chris, John

 

 

 

 

 

 

Array.prototype.unshift()

 

기능

unshift() 메서드는 주어진 값인 새로운 요소를 배열 형태의 객체 시작점에 삽입하고, 새로운 길이를 반환합니다.
 

 

문법

arr.unshift([...elementN])

 

매개변수

메서드를 호출한 배열의 새로운 length 속성.

 

반환값

메서드를 호출한 배열의 새로운 length 속성.

 

예시

const array1 = [1, 2, 3];

console.log(array1.unshift(4, 5));  // 5  
console.log(array1); //  Array [4, 5, 1, 2, 3]

 

 

 

 

 

 

 

Array.prototype.splice()

 

기능

splice() 메서드는 배열의 기존 요소를 삭제 또는 교체하거나 새 요소를 추가하여 배열의 내용을 변경합니다. 

 

문법

array.splice(start[, deleteCount[, item1[, item2[, ...]]]])

 

매개변수

start : 배열의 변경을 시작할 인덱스입니다. 배열의 길이보다 큰 값이라면 실제 시작 인덱스는 배열의 길이로 설정됩니다. 음수인 경우 배열의 끝에서부터 요소를 세어나갑니다(원점 -1, 즉 -n이면 요소 끝의 n번째 요소를 가리키며 array.length - n번째 인덱스와 같음). 값의 절대값이 배열의 길이 보다 큰 경우 0으로 설정됩니다.

deleteCount (옵션기능) : 배열에서 제거할 요소의 수입니다. deleteCount를 생략하거나 값이 array.length - start보다 크면 start부터의 모든 요소를 제거합니다. deleteCount가 0 이하라면 어떤 요소도 제거하지 않습니다. 이 때는 최소한 하나의 새로운 요소를 지정해야 합니다.

item1, item2, ... (옵션기능) : 배열에 추가할 요소입니다. 아무 요소도 지정하지 않으면 splice()는 요소를 제거하기만 합니다.

 

반환값

제거한 요소를 담은 배열. 하나의 요소만 제거한 경우 길이가 1인 배열을 반환합니다. 아무 값도 제거하지 않았으면 빈 배열을 반환합니다. 만약 제거할 요소의 수와 추가할 요소의 수가 다른 경우 배열의 길이는 달라집니다.

 

예시

const months = ['Jan', 'March', 'April', 'June'];

months.splice(1, 0, 'Feb');  // inserts at index 1
console.log(months); //Array ["Jan", "Feb", "March", "April", "June"]

months.splice(4, 1, 'May'); / replaces 1 element at index 4
console.log(months); / Array ["Jan", "Feb", "March", "April", "May"]

 

 

 

 

참고 : https://developer.mozilla.org/

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

 

스터디 발표 정리 (1) - 코어자바스크립트 01.데이터타입

 

01 데이터타입의 종류

기본형 / 참조형 데이터타입의 차이는 기본형은 할당이나 연산 시 복제되고 참조형은 참조되는 것
그리고 기본형은 불변성을 띈다는 것인데 이를 이해하려면 메모리와 데이터에 대한 지식이 필요하고
식별자, 변수의 개념을 구분할 수 있어야 하므로 다음으로 넘어갑니다

기본형은 값이 담긴 주소값을 바로 복제하는 반면
참조형은 값이 담긴 주소값들로 이루어진 묶음을 가리키는 주소값을 복제합니다

 

기본형 

number, string, boolean, null, undefined, symbol

참조형

array, function, date, regexp, map, weakmap, set, weakset

 

 

02 데이터타입에 관한 배경지식

컴퓨터는 모든 데이터를 0과 1로 바꿔 기억하는데, 이 하나의 메모리 조각을 비트라고 합니다
메모리는 많은 비트들로 구성되며 각 비트는 고유한 식별자를 통해 위치를 확인합니다

비트의 묶음 단위로 묶으면 효율적이며 표현할 수 있는 데이터의 개수도 늘어나나 낭비도 발생합니다
잘 안사용하는 데이터표현을 위한 빈공간보다는 표현 가능한 개수에 제약이 있어도 자주 사용하는 맞춤형 공간 구획이 나으므로
바이트 단위가 생성되었습니다

비트의 묶음 단위 바이트는 8개의 비트로 구성됩니다 **
1비트마다 0 1 두가지값 표현이 가능하므로 1바이트는 2의 8승값은 256개의 값 표현이 가능합니다
2바이트는 16개 비트이며 2의 16승 즉 65536개의 값 표현이 가능합니다

C C++ Java 등 정적타입 언어는 메모리낭비의 최소화를 위해 데이터타입별 할당할 메모리 영역을
2바이트, 4바이트 등으로 나누어 정해놓습니다 
예를 들어 2바이트 크기의 정수형 타입 short는 0을 포함한 -32768~32768 (2의 16승 65536 을 반으로 쪼개보면) 숫자만 허용합니다

이 구간 외의 숫자를 입력하면 오류가 되거나 잘못된 값이 저장됩니다
구간 외의 숫자를 입력하고자 할 경우 직접 4바이트 크기의 정수형 타입 int 등으로 형변환해야했었습니다 (과거에만)

자바스크립트 언어는 메모리용량이 월등히 커진 컴퓨터에서 사용가능하고 상대적으로 메모리 관리에 대한 압박에서 자유롭습니다
그래서 메모리 공간을 좀 더 넉넉하게 할당하여 숫자의 경우 정수형, 부동소수형 등을 구분안하고 64비트 (8바이트)를 확보합니다 **

각 비트는 고유한 식별자를 지니고 바이트 역시 시작하는 비트의 식별자로 위치 파악이 가능합니다
모든 데이터는 바이트 단위의 식별자, 메모리 주소값을 통해 서로 구분하고 연결할 수 있습니다

 

 

변수와 식별자 정확한 차이는

변수와 식별자를 혼용하는 경우가 많습니다
이유는 대부분 문맥에 따라 유추 가능하기 때문이지만 차이는 잘 짚어 둬야 혼돈이 덜하겠습니다

변수는 변할 수 있는 수로
수학 용어에서 차용하여 수가 붙게 되었는데 값은 수 외에 다른 것도 가능합니다
영어로는 variable 인데 변할 수 있는 이라는 형용사이지만 컴퓨터 용어에서는 변할 수 있는 어떤 것 인 명사로 확장되었습니다
어떤 것은 데이터입니다. 숫자, 문자열, 객체, 배열 등등입니다

식별자는 어떤 데이터를 식별하는데 사용하는 이름, 즉 변수명입니다.

 

[다른분들 정리를 참고하여 추가]

=> 기본형 데이터는 원본이 항상 있고, 데이터의 위치를 가리키는 변수값(메모리주소)는 변한다


var, const, let의 차이

변수 선언 방식 문법 변수 재선언 여부 변수 재할당 여부 변수의 유효범위
var ES5 재선언 가능 재할당 가능 function scope
const ES6(ECMAScript6) 불가 불가 block scope
let ES6(ECMAScript6) 불가 재할당 가능 block scope

 

// var
var name = "Marcus";
console.log(name);

var name = "Jogeonsang";
console.log(name);

output: Marcus
output: Jogeonsang

// let
let testCase = 'let' // output: let
let testCase = 'let2' // output: Uncaught SyntaxError: Identifier 'testCase' has already been declared
testCase = 'let3' // output: let3

// const
const testCase = 'const' // output: const
const testCase = 'const2' // output: Uncaught SyntaxError: Identifier 'testCase' has already been declared
testCase = 'const3' // output: Uncaught TypeError:Assignment to constant variable.

// 출처 : https://velog.io/@marcus/2019-02-10-1702-%EC%9E%91%EC%84%B1%EB%90%A8
// var
var foo = "This is String.";
if(typeof foo === 'string'){
    var result = true;
} else {
  var result = false;
}

console.log(result);    // var가 hoisting이 되기 때문에 result : true 

// let, const
var foo = "This is String.";
if(typeof foo === 'string'){
    const result = true;
} else {
  const result = false;
}

console.log(result);    // 에러 발생. result : result is not defined

// 출처 : https://velog.io/@marcus/2019-02-10-1702-%EC%9E%91%EC%84%B1%EB%90%A8

 

 

* 자바스크립트 호이스팅 

모든 변수 선언은 호이스트(변수의 정의가 범위에 따라 선언, 초기화, 할당 분리) 된다.
즉 변수가 함수 내에서 정의되었을 경우 선언이 함수의 최상위로, 
함수 밖에서 정의되었을 경우 전역 컨텍스트의 최상위로 변경된다.

 

 

* scope (유효범위)

스코프는 참조 대상 식별자(identifier, 변수, 함수의 이름과 같이 어떤 대상을 다른 대상과 구분하여 식별할 수 있는 유일한 이름)를 찾아내기 위한 규칙이다. (https://poiemaweb.com/js-scope)

변수는 전역 또는 코드 블록(if, for, while, try/catch 등)이나 함수 내에 선언하며 코드 블록이나 함수는 중첩될 수 있다.
식별자는 자신이 어디에서 선언됐는지에 의해 자신이 유효한(다른 코드가 자신을 참조할 수 있는) 범위를 갖는다.
스코프는 같은 식별자 이름의 충돌을 방지한다. 스코프가 없다면 같은 식별자 이름은 충돌을 일으키므로 프로그램 전체에서 하나밖에 사용할 수 없다. 디렉터리가 없는 컴퓨터를 생각해보자. 디렉터리가 없다면 같은 이름을 갖는 파일을 하나밖에 만들 수 없다. 

변수는 선언 위치(전역 또는 지역)에 따라 전역 스코프와 지역 스코프로 나눠 가진다.

 

전역 스코프(Global scope) 

전역에 변수를 선언하면 이 변수는 어디서든지 참조할 수 있는 전역 스코프를 갖는 전역 변수가 된다. var 키워드로 선언한 전역 변수 전역 객체(Global Object) window의 프로퍼티이다.
전역 변수의 사용에서 주의할 점은 변수 이름이 중복될 수 있고, 의도치 않은 재할당에 의한 상태 변화로 코드를 예측하기 어렵게 만드므로 사용할 때 잘 고려해야 한다.

 

var global = 'global';

function foo() {
  var local = 'local';
  console.log(global);
  console.log(local);
}
foo();

console.log(global);
console.log(local); // Uncaught ReferenceError: local is not defined

// https://poiemaweb.com/js-scope

 

 

지역 스코프, 함수레벨 스코프 (Local scope or Function-level scope)

자바스크립트는 함수 레벨 스코프를 사용한다. 즉, 함수 내에서 선언된 매개변수와 변수는 함수 외부에서는 유효하지 않다. 따라서 변수 b는 지역 변수이다.

 

var a = 10;     // 전역변수

(function () {
  var b = 20;   // 지역변수
})();

console.log(a); // 10
console.log(b); // "b" is not defined

// https://poiemaweb.com/js-scope

 

전역 영역에서는 전역변수만이 참조 가능하고 함수 내 지역 영역에서는 전역과 지역 변수 모두 참조 가능하나 변수명이 중복된 경우, 지역변수를 우선하여 참조한다.

 

var x = 'global';

function foo() {
  var x = 'local';
  console.log(x);
}

foo();          // local
console.log(x); // global

 

 

 

비블록 레벨 스코프 (Non block-level scope)

if (true) {
  var x = 5;
}
console.log(x);

// https://poiemaweb.com/js-scope

 

변수 x는 코드 블록 내에서 선언되었다. 하지만 자바스크립트는 블록 레벨 스코프를 사용하지 않으므로 함수 밖에서 선언된 변수는 코드 블록 내에서 선언되었다할지라도 모두 전역 스코프을 갖게된다. 따라서 변수 x는 전역 변수이다.

 

 

다른 언어와 다른 자바스크립트 스코프의 특징

대부분의 타 언어는 코드블록 내에서 유효한 블록 레벨 스코프를 따른다. 
예를 들어 if문이 있다면 if문 코드 블록 내에서 참조, 접근 가능한 스코프를 따른다.
그러나 자스는 함수레벨스코프를 따라, 함수코드블록 내에서 유효하고 함수 외부에서는 그렇지 않다.

ES6 let 을 사용하면 블록레벨스코프를 사용 가능하다.

 

var x = 0;
{
  var x = 1;
  console.log(x); // 1
}
console.log(x);   // 1

let y = 0;
{
  let y = 1;
  console.log(y); // 1
}
console.log(y);   // 0

// https://poiemaweb.com/js-scope

 

 


변수와 리터럴의 차이

리터럴 : 리터럴은 변수의 값이 변하지 않는 데이터(메모리 위치안의 값)를 의미한다. 보통은 기본형의 데이터를 의미하지만, 특정 객체(Immutable class , VO class)에 한에서는 리터럴이 될 수 있다. (https://mommoo.tistory.com/14 [개발자로 홀로 서기])

 

 

 

03 변수 선언과 데이터 할당

 

 

 

04 기본형 데이터와 참조형 데이터

 

 

 

05 불변 객체 (immutable object)

 
참조형 데이터의 가변성은 데이터 자체가 아닌 내부 프로퍼티를 변경할 때만 성립하며
새로운 데이터를 메모리에 할당
하고자 하면 기본형 데이터처럼 불변함

내부 프로퍼티를 변경할 때마다 매번 새로운 객체를 만들어 재할당해주는 대신 자동으로 새로운 객체를 만들어주는 도구를 사용할 수 있음 
==> immutable.js, immer.js, immutability-helper 등의 라이브러리나 ES6의 spread operator, Object.assign 메서드 등

* 불변 객체가 필요한 상황 : 값으로 전달받은 객체에 변경을 가해도 원본 객체는 보존되어야 하는 경우

더보기
  • 여기서부터 볼 것
  • 얕은 복사 : 딱 한 단계 밑의 프로퍼티 값까지만 복사됨
    깊은 복사 : 프로퍼티 값 속의 프로퍼티 값까지 재귀적으로 복사됨.

 

 

06 undefined, null

 

더보기
  • 기본형 데이터 타입에 속하므로, 그 자체로 타입인 동시에 ‘값’에 해당

  • undefined

    • 사용자가 리터럴로 undefined 할당하는 경우 -> ‘값’

      • 참조형 데이터의 요소나 프로퍼티 값으로 할당했을 경우, 배열 메서드가 이를 ‘존재하는 값’으로 보고 순회함

    • 엔진이 런타임에 ‘반환’하는 경우가 있다. -> ‘상태’에 가깝다

      • 값을 할당하지 않은 변수에 접근할 경우

      • 존재하지 않는 객체 프로퍼티에 접근할 경우

      • return문이 없거나 호출되지 않는 함수의 실행 결과

  • null

    • 개발자가 직접 null을 변수에 할당했을 때

    • ‘아무것도 없음’이라는 값을 할당한 것임. 

    • undefined를 직접 할당하는 대신 null을 할당하면 됨.

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

라이브러리와 프레임워크의 차이는 어플리케이션의 Flow(흐름)를 누가 쥐고 있느냐에 달려 있습니다. 라이브러리는 라이브러리를 가져다가 사용하고 호출하는 측에 전적으로 주도성이 있으며 프레임워크는 그 틀안에 이미 제어 흐름에 대한 주도성이 내재(내포)하고 있습니다. 프레임워크는 가져다가 사용한다기보다는 거기에 들어가서 사용한다는 느낌/관점으로 접근할 수 있습니다. 

일반적으로 라이브러리는 프로그래머가 작성하는 클라이언트 코드가 라이브러리의 메소드를 호출해서 사용하는 것을 의미 합니다. 프레임워크를 규정하는 특성은 프레임워크의 메소드가 사용자의 코드를 호출 한다는데 있습니다. 

 

  프레임워크 라이브러리
정의 뼈대, 기반구조 개발자가 만든 클래스에서 호출하여 사용하는 방식
상호 협력하는 클래스와 인터페이스의 집합 도구들의 집합
목적 소프트웨어의 특정 문제를 해결 단순활용
제어 흐름에 대한 주도성 전체적인 흐름을 스스로 가지며 그 안에 사용자가 필요 코드를 짜 넣음 사용자가 전체적인 흐름을 만들며 라이브러리를 가져다 씀
특징 특정 개념들의 추상화를 제공하는 여러 클래스나 컴포넌트로 구성   
컴포넌트들은 재사용이 가능  
높은 수준에서 패턴들을 조작화
 
추상적인 개념들이 문제를 해결하기 위해 같이 작업하는 방법을 정의 
 

 

라이브러리를 사용하는 애플리케이션 코드는 애플리케이션 흐름을 직접 제어합니다.
단지 동작하는 중에 필요한 기능이 있을 때 능동적으로 라이브러리를 사용할 뿐입니다. 

반면에 프레임워크는 거꾸로 애플리케이션 코드가 프레임워크에 의해 사용되는 것입니다. 
보통 프레임워크 위에 개발한 클래스를 등록해두고, 프레임워크가 흐름을 주도하는 중에 개발자가 만든 애플리케이션 코드를 사용하도록 만드는 방식입니다. 프레임워크에는 분명한 제어의 역전 개념이 적용되어 있어야 하며 애플리케이션 코드는 프레임워크가 짜놓은 틀에서 수동적으로 동작해야 합니다.

 

제어의 역전

어떠한 일을 하도록 만들어진 프레임워크에 제어의 권한을 넘김으로써 클라이언트 코드가 신경 써야 할 것을 줄이는 전략입니다. (프레임워크가 나의 코드를 호출하는 것)

사용방법 1 : event, delegate 에 나의 메소드를 등록하여 사용합니다. 전달 인자와 반환 형식만 일치하면 프레임워크 코드는 내가 작성한 객체와 타입을 고려하지 않습니다. 등록된 메소드만 감지하여 실행 invoke (적용) 합니다.

사용방법 2 : 다른 방법은 프레임워크에 정의되어 있는 인터페이스 interface, 추상타입 abstract 을 나의 코드에서 구현, 상속 한후 프레임워크에 넘겨주는 것입니다. 프레임워크는 인터페이스와 추상을 알고 있으므로 내가 하고자 하는 일련의 작업을 처리할 수 있습니다. 이는 객체를 프레임워크에 주입하는 것이고, 이를 의존성 주입 dependency injection 이라고 합니다.

 

라이브러리는 그냥 함수들이나 기능 모음을 가져다가 쓰는 것이고. 프레임워크는 특정 디자인 패턴이나, 전처리 후처리에 필요한 동작과 기능들을 수행하기 위해서 프레임워크가 실행되다가 중간 중간에 특정 비지니스나, 특정 구현 단에서만 사용자의 코드를 lookup(검색)하여 사용하는 형태라고 할 수 있습니다. 쉽게 라이브러리는 연장으로 좀 바뀌어도 목적만 달성하면 되나 프레임워크는 비행기 차 등으로 정해진 곳으로만 다닐 수 있습니다. 일단 연장으로 탈것을 만들고 규칙에 맞게 핸들만 돌리면 되는 것입니다. (XML에 어떤 태그를 쓸지, 함수를 쓸지, 소스파일을 어디에 넣을 지 등 이미 정해진 프로그래밍 규칙)  

 

아래 유명하신 분의 글을 보고 요약했습니다.

출처: https://webclub.tistory.com/458 [Web Club]

 

728x90
728x90

'Frameworks' 카테고리의 다른 글

싱글톤 패턴(Singleton Pattern)을 쓰는 이유  (0) 2019.11.03
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,

v