최소노출원칙, 블록과 함수스코프로 변수노출을 최소화한다>유지보수 쉽고, 스코프의 이름충돌 문제 등을 피할수 있음
클로저도 POLE기반. 변수를 더 제한된 스코프로 캡슐화한다. 이러면 변수를 더 넓은 범위에서 사용가능
클로저는 함수형프로그래밍, 모듈, 클래스지향설계 및 프로그래밍에서 가장 중요한 언어특성
클로저 관찰하기
클로저는 오직 함수에서만 일어나는 함수의 동작. 클로저를 관찰하려면 반드시 함수를 호출해야함.그리고 호출된 함수가 해당함수를 정의한 스코프체인 아닌 다른분기branch에서 호출해야함. (다른스코프에서 호출해야한다는뜻?)
내부함수가 외부스코프에 있는 변수를 참조하는것=클로저
학문적으로는 함수를 호출할때 생기는 greetStudnet()인스턴스 각각이 외부변수 students, studentID를 감싸고있다(close over)
클로저는 외부스코프가 종료된 이후에도(lookupStudnet()각 호출이 완료된후) 리턴되는함수greetStudnet()가 외부변수에 계속 접근할수있게 해준다.
화살표함수의 스코프
화살표함수도 스코프가 있다! (**함수 이름, this, arguments 총 3가지가 없다)
화살표함숮도 클로저를 형성한다
추가되는 클로저
클로저는 단순 함수코드에 의해 정의되는게 아닌, 함수인스턴스에 따라 다르게 생성됨
클로저는 렉시컬스코프 기반,컴파일시 처리되나 실제 동작은 실행시점에 함수인스턴스에따라 달라지는 특성
스냅숏 아닌 라이브링크
클로저는 실시간으로 변수자체에 접근하도록 관계맺어주는 라이브링크. 그래서 클로저를 통해 값을 읽고, 수정(재할당)가능하다. 언제든 해당 변수를 읽고쓸수있다. 클로저의 외부스코프는 반드시 함수스코프가 아니여도 된다. 내부함수 감싸는 외부스코프가 존재하기만 하면 클로저가 된다. (FiB=블록내 함수선언function declaration in blocks)
흔한오해) 클로저는 변수가 아닌 값과 연관되어있어, 특정시점의 값을 보존할수있다? ㄴㄴ틀림
keepI함수에서 i가 보존되지않는이유는 var로 선언되어 i가 하나만 존재하기때문에 i=3으로 갱신됭어버림. 모두 동일한 i를 참조하기때문. 여러값을 보존하려면 각각 다른변수가 필요함.
쉽게 관찰할수있는 클로저:Ajax와 이벤트
비동기실행환경에서도 콜백함수가 변수에 접근할수있는 이유도 클로저때문.
보이지 않으면 어떡하죠
클로저의 관찰가능성.
관찰할수없는경우-렉시컬스코프를 탐색해서 찾는경우, 전역변수에 접근하는경우, 변수가 존재만 하고 해당변수에 한번도 접근하지않는경우, 함수호출 안할경우
관찰가능성 관점에서의 클로저의 정의
반드시 함수와 관련되고, 외부스코프 변수를 최소1개 참조, 참조하는 변수가 있는 스코프체인의 다른분기에서 함수호출해야함.
클로저 생명주기와 가비지컬렉션
함수를 참조하는 함수가 있는한 변수에 대한 클로저는 지속된다. 마지막 함수참조 삭제되면 변수에대한 클로저가 사라지고, 변수가 GC처리됨. 이벤트핸들러가 더이상 필요하지않을때 취소하는것이 첫번째(최초) 구독보다 중요?
변수 혹은 스코프
클로저를 참조된 외부변수에만 적용되나? 아니면 전체스코프체인과 그안의 모든변수에 적용되나?
onClick은 cb을 클로저로 유지할까, clickHandler, clickHandlers, btn도 유지할까?
개념만 따지면 클로저는 변수기준(스코프기준 아님)
grades=함수인자인 Rec돌면서 점수만 저장한 배열.
엔진으로 디버깅해보기 studentRecords변수가 표시되지않음. 엔진이 클로저를 통해 studentRecords를 메모리에 유지하지않는다는 증거!
eval()렉시컬 스코프꼼수 (1.5절 참조)사용하면 변수접근가능.
내부함수에서 명시적으로 변수참조는 아니지만 클로저를 통해 모든변수가 확실히 보존됨. 이건 스코프기준일까? 상황에따라 다르다. 왜?? eval은 최적화가 안됨. 현대 자스엔진은 클로저를 최적화해 실제함수내에서 참조되는 변수만 클로저에 포함시킨다. 최적화로 클로저가 포함한느 스코프를 줄이고, 필요없는 변수제거해 메모리 정리. 그래서 최적화결과가 변수별로 이뤄진것 처럼 보인다.. (아냐??)
최적화는 엔진의 선택사항. 그러니 클로저최적화나 GC에 의존하지말자. 큰값을 가진 변수가 클로저 스코프에 있는경우, 더이상 필요없다면 메모리사용량면에서 수동으로 버리는게 안전함.
필요이상으로 메모리 점유하지않도록 주의하자. 명시적으로 값해제하는 습관을 들여라? 직접 null설정해주기.
그렇지만 null을 설정한다고 해서 클로저스코프에서 변수가 제거되지않음. 클로저스코프는 우리가 통제할수없다? 그러나 클로저스코프에 있더라도 더이상 대용량데이터를 참조하지않고 GC대상이 될수있따
애플리케이션 프로파일링(?)을 통해 메모리과잉 사용 판단되면 해당참조 해제해 메모리 추가확보가능.
클로저가 어디에 있고, 어떤변수 포함하는지 파악하는게 중요하다. 메모리낭비하지않도록 관리하기
다른관점
함수는 일급값, 클로저는 함수가 어디로 이동하든 해당 함수를 외부스코프의 변수와 연결해주는 링크역할
대신 함수는 참조,복사를 통해 할당,전달 된다! 관점에서 보자.(1부 부록A참고)
클로저란 프로그램의 다른부분에서 해당함수 인스턴스에 대한 참조가 존재하는한 함수인스턴스와 그전체스코프환경 및 스코프체인을 살아있게 유지해줌 (동기콜백은 여전히 클로저일까? 부록A참고)
무엇을 콜백하는가? 동기콜백 이름이 최선인가? iif함수는 왜 클로저가 필요한가? 핵심은 시간에 따른 연기
콜백이란?? 제어권을 넘겨주는것, 그리고 나중에 다시호출되는것
프로그램의 다른부분이 호출을 대신하도록 함수를 전달하는것=DI(의존성주입),IoC(제어의 역전) 이 더 낫다 동기콜백보다
Inversion of Control제어권 역전
IIF inter-invoked function상호 호출함수 :다른엔티티(?)의해 호출됨
동기적콜백은 IIF라고 부르자.
비동기콜백과 IIF? 비동기콜백은 비동기적으로 호출되는 IIF
IIF는 클로저일까?
외부참조가 있는 IIF는 클로저인가?
그럼 동기콜백IIF는 클로저가 아니다. 비동기여야 클로저다.
클로저를 사용하는 이유
클로저로 코드구조 향상하는법
함수형 프로그래밍 패러다임의 대표적기법2가지-부분적용,커링
여러 입력이 필요한 함수의 모양을 바꿔서 미리 입력하거나 나중에 입력하는 기법. 초기입력은 클로저를 통해 기억됨. 입력이 모두제공되면 기본작업 수행.
정리
클로저를 보는 관점
관찰관점: 함수가 다른 스코프로 전달되거나 호출될때도 외부변수를 기억하는 함수인스턴스
구현관점: 다른스코프에서 참조가 전달되고 호출되는동안 함수인스턴스와 해당 스코프환경을 제자리에 보존
부분적용과 커링
여러 개의 인자를 받아야 하는 함수에 대해 인자 일부만을 먼저 적용하여 새로운 함수를 만드는 기법입니다
**부분적용
- 여러 인자를 받는 함수에 대해 일부 인자만 미리 고정하여 새로운 함수를 만듭니다.
- 이 새로운 함수는 미리 채운 인자를 기억하고, 나머지 인자만 받으면 됩니다.
- bind, apply 등을 사용하여 특정 인자를 고정해 부분적으로 적용할 수 있습니다.
**커링(Currying)**은 여러 개의 인자를 받는 함수를 한 번에 하나의 인자만 받도록 연속적인 함수로 변환하는 과정입니다. 단계별로 인자를 하나씩 받아서 최종 결과를 반환하는 방식입니다.
- 부분적용은 인자의 일부만 미리 적용하고, 나머지 인자는 나중에 받습니다. 주로 bind, apply, call 등의 함수로 구현할 수 있습니다. 이 과정에서 반환되는 함수는 아직 남은 인자를 모두 받지 못했으므로, 나머지 인자를 받기 위해 계속 대기합니다.
- 커링은 여러 개의 인자를 한 번에 받는 대신, 각 인자를 하나씩 받아 새로운 함수를 반환하며, 마지막 인자를 받으면 최종 계산이 수행됩니다. 모든 인자를 받을 때까지 함수 호출이 연쇄적으로 이어지며, 마지막 인자를 받았을 때 계산이 완료됩니다
**func.bind(context)는 함수처럼 호출 가능한 '특수 객체(exotic object)'를 반환합니다. 이 객체를 호출하면 this가 context로 고정된 함수 func가 반환됩니다. bind는 컨텍스트를 this로 고정하는 것 뿐만 아니라 함수의 인수도 고정해줍니다.
부분적용으로 기존 함수의 매개변수를 고정하여 새로운 함수를 만들 수 있습니다.
부분 함수는 왜 만드는 걸까요?
가독성이 좋은 이름(double, triple)을 가진 독립 함수를 만들 수 있다는 이점 때문입니다. 게다가 bind를 사용해 첫 번째 인수를 고정할 수 있기 때문에 매번 인수를 전달할 필요도 없어지죠. 매우 포괄적인 함수를 기반으로 덜 포괄적인 변형 함수를 만들수 있다는 점에서 유용합니다.
부분 적용은 같은 인수를 여러 번 반복하고 싶지 않을 때 유용합니다. send(from, to)라는 함수가 있는데 from을 고정하고 싶다면 send(from, to)의 부분 함수를 구현해 사용하면 됩니다.
**HTML dataset은 HTML 요소에 데이터를 저장하고 접근할 수 있게 해주는 기능입니다. data-* 속성을 사용하여 사용자 정의 데이터를 HTML 요소에 저장할 수 있으며, JavaScript에서 해당 데이터를 dataset을 통해 쉽게 접근할 수 있습니다.
dataset을 통해 HTML에서 정의된 데이터에 접근하고, 값을 읽거나 쓸 수 있습니다.
HTML에서 data-* 속성은 임의의 데이터를 HTML 요소에 추가할 수 있는 방법입니다. 예를 들어, data-user-id, data-product-name 등과 같은 사용자 정의 속성을 추가할 수 있습니다.
** Endpoint는 클라이언트와 서버가 서로 통신할 때 데이터를 주고받는 접속 지점을 의미합니다. 특히 API(애플리케이션 프로그래밍 인터페이스)에서 자주 사용되며, 클라이언트가 요청을 보내고 서버가 응답을 처리하는 구체적인 URL 또는 URI를 나타냅니다.
Endpoint는 API에서 클라이언트가 요청을 보내는 지정된 URL로, 서버와 데이터를 주고받는 진입점입니다
웹 애플리케이션에서 사용되는 RESTful API의 구조를 통해 살펴보면: 이 URL에서 https://example.com/api/users가 하나의 endpoint입니다.
'Javascript > YDKJS' 카테고리의 다른 글
부록 A,B (0) | 2024.11.22 |
---|---|
YDKJS (유돈노JS) 6,8 - 스코프 노출제한, 모듈 (0) | 2024.10.17 |
1008 유돈노 (0) | 2024.10.08 |
유돈노 (0) | 2024.10.08 |
YDKJS (유돈노JS) 부록A - 암시적스코프 (0) | 2024.10.06 |
댓글