스칼라를 이용한 개발 이후..


폴리글랏 (C++,Java,Python,Swift,Javascript) 언어로 개별 작업하면서 동시에 스칼라를 이용해 (Programming in Scala 와 FPiS 빨강책으로 공부)  EV 충전 인프라 서비스를 위한 마이크로서비스(서버 인프라) 와 웹서비스에 각각 적용하고 난 후 가장 아쉽게 느끼는 점은 akka 나 play2의 문제점 같은게 아니라 내가 짠 것은 함수형 프로그래밍은 아니다. 였습니다. 아시다시피 스칼라는 하이브리드언어입니다. 객체지향식으로 코딩 할 수 도 있고 함수형으로 코딩 할 수 도 있습니다. 따라서 기존 자바나 C++ , 파이썬 개발자들이 순수 함수형 언어인 하스켈이나 거의 순수형인 클로저 보다는 쉽게 접근 할 수 있는데요. 저도 스칼라를 선택한 이유 중 하나에 포함됩니다. (기타 : "Typesafe 사 및 대기업에서의 적극적인 사용, 자바라이브러리사용, Akka 라이브러리, 강력한 정적 타입시스템, Play2, Intellij IDE, 가상머신상에서 돌아감등 ") 

하지만 하이브리드라는 것 은 이것도 해주고 저것도 해주고 장점을 믹스하고 자유도를 높혀 준다 라고 말 할 수 도 있지만 거꾸로 보면 난해하다는것을 말합니다. (다른 사람이 짜놓은 코드가 객체지향인지 함수형인지.. immutable인지 아닌지..버그들을 눈을 부릅뜨고 찾아봐야하며 ..울분에 날 밤을 새야 할지도..) 함수형과 객체지향은 완전 상반된 개념인데 이것을 같이 사용하게 하면 어떤 일이 벌어 질까요? 

예를들어 동시성에 대해서 생각해 봅시다.

무어의 법칙이 한물가고 이제 암달의 법칙이 지배하는 세상입니다. 객체지향이니 함수지향이니 보다는 동시성지향프로그래밍으로 대동단결 할 것으로 보이는데요. lock 이나 뮤텍스,쓰레드등을 직접 요리하는 시대는 갔습니다. 그 우연적복잡성,경쟁상태,메모리가시화,데드락을 해결 하기가 너무 힘듭니다.(나는 저런거만 써서도 잘 할 수 있다는 사람이 주변에 있으면 조심하세요. 요주의 인물입니다 -.-;;)  그래서 어려운 동시성 문제를 해결 하기 위해 여러 방법들이 생겨 났습니다.  크게 보면 3가지 인데요. 참고=> 7가지 동시성 모델

첫째. 변하지 않는 데이터로 공유하라. (immutable 은 함수형파라다임의 대표적 속성 중 하나)
둘째. 공유되지 않게 하라. (
객체지향파라다임에서 메세지 패스를 통해서 해결 하라는 것 이며, 예를들어 Actor 모형입니다.)
셋째. 가변상태에서 아이덴터티를 포착하라. ( STM 을 말함) 

이 얘기는 앞으로 점점 더 동시성 프로그래밍이 대세가 될 텐데  그걸 기본적으로 해결 해주는것이 함수형 파라다임이고 그 이유로 요즘 F#,하스켈,스칼라,클로저,얼랭등이 인기를 얻고 있다는 뜻이기도 합니다. 음 먼가 말이 샌거 같기도 한데...-.-;;

여기서 스칼라는 두둥~~ 네 객체지향이자 함수형이고 가변성질을 느슨하게 포함하고 있는 상태에서 다양한 동시성 모형을 여러가지로 가져 갈 수 있는데.., 그 말은 복잡도가 *100 증가 했습니다와 마찬가지입니다. 한가지만 제공하는 언어를 사용하면 누가 짠 코드이던지 그 본질에 대해 확신이 들지만 이것도 되고 저것도 된다면 확인해 봐야 할것들이 늘어잖겠습니까.. OTL  

뭐 이런 고민 상황에서  허둥지둥 스칼라로 프로젝트를 하였고..스칼라의 반 쪽 밖에 맛을 못본것은 좀 아쉬웠습니다. 특히 그 반쪽보다는 다른 쪽 반쪽에 대한 장점을 가져가고 싶었는데 말이죠. 시간이 없었다는 핑계를 댈 수 도 있겠지만 그것 보다는 우선 순서가 잘못된게 아닌가 느꼈는데요. 결국 "스칼라"라는 하이브리드 언어에서 나머지 한쪽 맛 (함수형) 을 보려면, 순수 함수형을 먼저 공부하는게 순서가 아니겠느냐 하는 점이죠. (이것은  C++ 개발자에게 자바,스몰톡을 공부 해 보라고 권유하는 것과 동일합니다. 자바개발경험이 있으면 C++ 개발에 대한 식견도 꽤 높아질것입니다.) 즉 스칼라를 더 잘 사용하기 위해서 즉 객체지향의 강점과 함수형의 강점을 극대화 하여 사용하기 위해 순수 함수형 언어를 공부해야겠다고 생각 하게 되었습니다.(사실 공부만 해서 별 의미 없을 거 같기도 합니다. 다른 언어를 한 1년 정도 안하고 순수 함수형만 가지고 놀 수 있는 환경에 있다면 좋을텐데.. 여러가지 언어로 개발하면 온전히 함수형 마인드를 갖기는 어렵지 않을까 하는)

그럼 어떤 함수형언어를 공부 해 볼까 고민하다가 발견한 글 중에 하나가 이것입니다. 뭐 시간 있으면 하스켈,클로저 둘 다 공부해 보면 좋겠지만 시간도 없거니와 이왕하는 거 순수 함수형 언어인 하스켈을 선택하자 하고 몇가지 글을  찾았고 그 중 하나를 정리 해보았습니다. 항상 그러하지만 번역 상태에 대해 만족스럽지 못할 수 있다는 점 송구스럽게 생각하며.. ㅜㅜ  시작해 봅니다. =@@



Clojure 를 넘어 Haskell 로  

http://martintrojer.github.io/beyond-clojure/2016/04/21/beyond-clojure-haskell

타입을 가진 함수형 언어에 관심이 있는 경우 결국 하스켈을 만나게 될 것 입니다. 배우기가 극도로 어렵고 마스터 하기는 더 어렵다는 평판에도 불구하고 훌륭한 자료들이 있으며 귀중한 교훈을 많이 배울 수 있습니다.

하스켈은 매우 순수하며 핵심 아이디어와 라이브러리의 간결함은 환상적입니다. 그것은 명령형 문제 해결 스타일을 뛰어 넘고 높은 수준에서 문제를 매우 깔끔하게 다룹니다. 하스켈에 관해 내가 정말 좋아하는 한 가지는 명백한 학문적 용어를 사용하여 '사물'이 무엇인지 불리는 것입니다. 모나드 (Monads) 등을 가지고 있는 다른 언어들의 경우 수줍어(?)하며 다른 이름을 쓰는 경향이 있습니다.이 점은 혼란만 가중 시킬 것이라고 생각합니다.

핵심 라이브러리 (하스켈 literature 의 대부분인)의 벽으로 둘러싸인 정원에 머물러있는 한 간결하고 아름다운 세계가 제공됩니다. 문제 해결에 영감을 불어 넣고 다양한 각도에서 문제를 바라 보는 환경인데요. 그래도 항상 더 깔끔하게 문제를 해결할 수 있는 방법들이 있으며, 이러한 탐구적인 태도와 성향은 하스켈 커뮤니티에  널리 퍼져 있습니다. Haskell 초급 모임 및 채팅룸에서 경험이 많은 개발자들이 따뜻한 도움을 주고 있으며, 답을 주는 것보다 스스로 문제를 해결할 수 있게끔 유도 합니다. 그것은 언어를 즐겁게 배우게 만드는데 도움을 준다고 생각합니다.

성공하는 대신 결점을 찾아라

Haskell에 대해 이해해야 할 때 중요한 한 가지! 이 언어는 "연구 언어" 란 건데요. 이 사실은 다른 '현장 언어' 들과는 매우 다른 점입니다. 좀 어리둥절 할 수 도 있는 하스켈의 모순 된 모토는  '모든 비용을 들여서라도 성공을 피하십시오'. 입니다. 이 말을 해석해보자면 언어의 안정성에 의존하는 대규모 사용자 기반을 피함으로써 작성자 / 연구자가 마음을 바꾸면 나중에 제거하고 마음 편하게 새로운 아이디어를 탐색 할 수 있다는 것입니다. 대성공의 희생자이며 성공을 했다는 이유로 십 수년 동안 혁신 마비에 빠져있는 Java와 같은 언어와 대조해 보시면 됩니다. (역주: 개인적으로 자바는 혁신 하지말고 그냥 자바 그 자체로 남아 있길 바라는 마음도 있습니다. 혁신하다보면 오히려 정체성만 없어지고 조잡한 언어가 되지 않을까 하는 우려 때문인데요. 오랫동안 혁신하지 않고도 자바가 필요한 분야는 많이 있을 겁니다. 목숨 줄 억지로 늘리지 말고 때가되면 자연스레 은퇴하길...) 가장 유명한 Haskell 컴파일러 인 GHC에서 명백하게 느낄 수 있는데 GHC는 최신 Haskell 표준 Haskell2010을 지원하며 그 위에 다양한 언어 확장 기능을 제공합니다. 

여러분이 핵심 라이브러리의 벽으로 막힌 정원 밖으로 여행을 떠나서 하스켈을 '진짜로'사용하기 시작하면, 거의 모든 모듈에서 이러한 언어 확장을 피할 수 없습니다. 모두는 아니더라도 대부분의 라이브러리는 확장 기능을 사용하고 일부는 코드에서 사용해야합니다. 이것이 얼마나 큰 거래인지는 미래의 변화에 ​​대해  당신이 얼마나 대처 할 수 있을지에 달려 있습니다.

하스켈을 주 언어로 사용하고 5 년 이상 일하는 것에 대해 생각하고 있다면, 이것은 불안의 원인이 될 수 있습니다. 비즈니스 핵심 서비스를 위해 GHC (컴파일러 '모두 사용')를 사용할 계획이라면 언어 / 컴파일러 변경 사항을 지키기 위한 전략과 팀에 부과하는 추가 작업을 고려해야합니다. 개발자가 사용하는 확장 기능에 대한 규율도 중요합니다. (역주 : 역시 공부목적으로만 해야 하는.. -.-a)

게으름

Haskell 의 핵심 설계 원칙 중 하나는 게으른 평가입니다. 이것은 다른 함수형 언어에서 볼 수 있는 게으른 시퀀스 이상입니다. 기본적으로 모든 표현식은 다른 표현식이 결과를 땡겨 올 때만 실현됩니다. 하스켈의 아름다움은 이 기법에서 비롯되었지만 실제적인 문제는 많습니다. 가장 중요한 것은 기능의 시간 / 공간 복잡성을 해결하는 것이 매우 어렵다는 것이며 다른 함수의 표현식은 현재 벤치마킹중인 함수의 문맥상에서 방아쇠가 당겨 질 수 있습니다. 그밖에 따로 방법이 없으며, 적극적 평가(eager evaluation) 가 그 부분에서는 더 쉽지만, 하스켈의 접근법을 무효화하지 않습니다.(??)

또 다른 문제점은 일반적으로 런타임 예외시 스택 트래이스를 얻지 못한다는 것입니다. 그것은 컴파일 타임에 활성화되어야하며 프로덕션 빌드의 경우 일반적으로 실행되지 않습니다. 트레이스를 얻었을 때도, 게으른 것으로 평가되기 때문에, 자바 스택 트레이스와 똑같지는 않습니다.

늘 그렇듯이 몇가지 대안이 있지만,  간단하지 않은 상황 (예 : 생산 중단 시간 시나리오가 그러하듯) 에서는 Java와 유사한 프로파일링 도구가 필요 합니다. 필연적으로 compiler optimization flags, bang patterns 및 기타 어려운 교훈을 배우고 베스트 프랙티스를 수집하는 과정을  거친 후에야 제대로된  응용 프로그램을 만들 수 있을 것 입니다. OTL

타입 언어와 함께 춤을

하스켈과 클로저의 차이는 꽤 있는데요 Clojure에서는 var에서 작업하고자 하는 데이터를 저장하고 변환 작업을 시작합니다. 표현식을 데이터 모양과 일치 시키려 할 때 피드백은 종종 Clojure 런타임 오류입니다. 하스켈에서 추상화 (유형)에 대해 생각하기 시작하고 컴파일러의 주요 오류는 컴파일러가 자신을 모순하는 곳을 가리키는 유형 오류입니다. 또한 런타임 오류가 거의 발생하지 않기 때문에 '컴파일하면 작동합니다'라는 강한 확신감각하에 개발을 합니다. 이것은 결코 테스트의 중요성을 없애지는 않지만 테스트는 Clojure 코드 -베이스에서와 동일한 역할을 하지 않습니다. Haskell에서 나는 코드가 올바르게 붙어 있거나 GADT의 변경으로 인해 case 표현식을 바꾸는 것을 잊지 않았다는 확신을 줄 수있는 테스트가 필요하지 않습니다. 컴파일러는 나를 위해 모든 것을 검사하고 "그것은  여기, 여기, 여기 그리고 여기에 더 많은 수정이 필요합니다"라고 말합니다. 나에게 이것은 엄청난 것이지요.

툴과 함께 춤을 

'Haskell IDE'는 전통적으로 Emacs / Vim과 터미널 입니다. 매우 즐거운 개발자 경험을 주는 여분의 도우미가 많이 있습니다. 전통적인 IDE를 위한 플러그인이 있지만 일반적으로 덜 정교합니다. 나는 대화형 작업 흐름을 제공하는 Emacs, haskell-mode, ghc-mod, hlint 설정에 만족합니다. 좀 더 전통적인 IDE 설정이 필요하다면, IDE-Haskell과 Haskell for Mac이 괜찮아 보입니다.

라이브러리로 작업하고 의존성을 다루는 것은 cabal로 수행됩니다. Cabal은 하스켈 서클 내부와 외부에서 많은 쟁점과 명성을 얻었습니다. Haskell 개발자들은 여러 문제에 대해 다양한 해결책을 찾기 위해 광범위하게 노력해 왔습니다. 그 문제의 일부는 라이브러리의 버전 (및 그 의존성)뿐만 아니라 컴파일러의 버전이 그것을 생성하는 데 사용되었다는 것입니다. 컴파일러는 기계어 코드를 생성하므로 크로스 컴파일 문제도 있습니다. Mac에서 실행 파일을 컴파일하는 작업은 Linux 서버에서 실행되지 않습니다.

최근 Cabal과 관련된 많은 불평은 Stack이라는 도구로 해결되었습니다. 나는 아주 만족하고 있습니다.(그리고 Nix를 필요로 하지 않습니다.). Stack은 하스켈 툴링 스토리에 대한 커다란 개선점입니다.

라이브러리와 함께 춤을 

사용할 수있는 하스켈 라이브러리는  많이 있습니다. 좋은 라이브러리를 찾는 것은 좀 어렵기도 하지만요 웹어플리케이션을 구축하는 경우 대부분의 기반들을  커버 할 수 있습니다. 웹 프레임워크, 데이터베이스 연결, 템플릿 등에 대해 좋은것들이 있습니다. 그러나 자바 생태계와는 여전히 비교 되긴 힘듭니다. Haskell은 닭이 먼저냐 달걀이 먼저냐인 상황에 갇혀 있는데요. Java 는 서드파티제품들에 대해 상호 작용하는 많은 라이브러리가 존재합니다. 하지만 하스켈은 최신 AWS API를 사용하거나 Riak 데이터 저장소에 연결하기 쉬운 경로를 원할 경우 길이 없습니다. 기본 빌딩 블록은 있지만 거기에 앞서 당신은 꽤 많은 일을 해야 할 것입니다. 이러한 상황은 개발자들의  Haskell 채택을 머뭇거리게 하고 있으며, 이는 결국이 라이브러리가 만들어지는것을 또한 머뭇거리게 만들 고 있습니다.

하스켈 라이브러리에 대한 문서는 대개 꽝입니다. 초보자 친화적인 문서를 기대하지는 마십시오. 나는 스택 오버 플로우등에 대한 검색에 의존하고 있습니다. 라이브러리에 관한 여러 문제점은 하스켈을 실제 시나리오에서 '사용할 언어'로 채택 할 때 주로 우려되는 사항입니다. 



어떻게 이렇게 어려운(직관적이지않은) 언어가 세상을 지배하게 됬는지 정말 불가사의하다.


함수 

함수생성법

객체생성법

함수 호이스팅

함수 프로퍼티 

함수 형태  

함수호출과 This 바인딩 

함수 리턴 

프로토타입 체이닝

실행 컨텍스트

스코프 체인 

클로저 

객체지향프로그래밍

함수형 프로그래밍




자바스크립트에서 함수


C/JAVA/C# 등에서 보통 함수는 특정기능을 제공하고 결과값을 얻는 행위 only     

                                                  VS

자바스크립트에서의  함수는 위에것 + 모듈화 처리 + 클로저 + 객체생성등등 JS의 근간이 되는 많은 기능이 추가되어있다. 


“자바스크립트 공부에서 가장 중요한것은  함수의 기능에 대한 기존 프레임에서 알을 깨고 나오는것” 그리고 this 에 대한 감각.


1. 함수안에 함수가 들어가서 c++/java 의  멤버함수 (js에서는 메소드) 역할을 할 뿐 아니라 

2.변수에 할당이 가능하고 매개변수로도 넘길수있고,리턴값 및 배열의 값으로 사용 

3.결정적으로 클래스 역할도 한다. 




함수 정의의 3가지 방법 

 

함수 선언문 

function add(x,y){

return x+y;

}

“반드시 함수명이 정의되어야 한다” 

“function 이라는 키워드를 명시적으로 사용한다”

“ 리턴값과 매개변수로 넘기는값에 변수 타입을 기술하지 않는다”


함수 표현식 (1)

var  add = function(x,y){

return x+y;};


var plus = add;

함수 선언문 방식과 거의 유사하다.

유일한 차이점은 함수이름이 선택사항, 보통 사용하지 않음. 

위의 add와 plus 는 동일한 값(익명함수) 을 참조한다. 

관례적으로 함수뒤에 ; 를 넣는다. 


함수 표현식 (2) 

var  add = function sum(x,y){

return x+y;};


console.log(sum(3,4));  

어떻게 될까? 



console.log(sum(3,4));   // 에러!!!


함수 표현식에서 사용된 함수이름은 외부코드에서 접근 불가능!! 
(내부에서는 가능)



Function() 생성자 함수를 통한 생성  

new Function(arg1,arg2,...argN, func body);

var add = new Function(‘x’,’y’, ‘return x+y’);
console.log(add(3,4)) // 7



함수선언문,함수표현식 둘다 내부적으로 이것을 이용한다.
일반적으로 자주 사용되지는 않는다.
이런게 있다는것만 알아두자.



함수 호이스팅 


add(2,3); // 5 <------- (1)

function add(x,y){  <-------- (2)
return x+y;}

add(3,4); // 7  <--------(3) 


(1) 시점에는 함수 (2) 가 정의되지도 않았는데 호출이 가능하다 . 
함수 선언문 형태로 정의한 함수의 유효범위는 코드의 맨 처음으로  끌어올려 Hoisting 진다..
따라서 함수 선언문보다는 함수 표현식을 사용하기를 강력히 권고한다.  (코드구조가 엉성해짐) 
 


함수도 객체다.   

function add(x,y){
return x+y;}

add.result = add(3,2);
add.status = ‘OK’; 


보통 객체처럼 result / status 같은 프로퍼티를 가질수있다.
근데 놀라운것은 나중에 필요할때마다 추가할수있다는점이다. 



객체 생성 in Javascript 

// (생성자)  함수를 통함. 
function Person(name,age){
            this.name = name;
            this.age    = age
 
           // 메서드도 추가 가능 
};
 
var foo = new Person('foo',30);  // 이미 선언되있던 함수를 가지구  new 를 사용하여 만든다. 


//객체 리터럴을 통해서 (JSON 처럼) 
var foo = { name : ‘foo’,  
           age : 30
};



함수는 일급객체이다. 


//변수나 프로퍼티의 값으로 할당 

var foo = 100;
var bar = function(){return 100; };
console.log(bar()); // 100 

var obj = {};
obj.baz = function(){return 200;}
console.log(obj.baz()); // 200 


//함수 인자로 전달

    var foo = function(func){
func(); // 인자로 받은 함수 호출 
    };

    foo(function(){
                 console.log(“hello”);
          }
    );



//리턴 값으로 활용  

var foo = function(){
return function(){
console.log(“hello”);
                         };
                };

var bar = foo();
bar();

> hello


함수 객체의 기본 프로퍼티   


function add(x,y){return x+y;}

console.log(add);

argument,
caller,
length,
name,
prototype,
__proto__   

등과 같은 다양한 프로퍼티가 기본적으로 생성되어 있다. 
(ECMA표준도 있고, 브라우저별 프로퍼티도 있음) 


[[Prototype]] 


모든 자바스크립트 객체는 자신의 프로토타입을 가리키는 
[[Prototype]] 내부 프로퍼티를 가진다. 크롬브라우저에서는
__proto__ 라고 표현.


Function.prototype 
Object.prototype 
Array.prototype
Person.prototype
Number.prototype / String.prototype

constructor 프로퍼티
toString() 메서드
apply(thisArg,argArray) 메서드
call(thisArg,[,arg1[,arg2,]]) 메서드 
bind(thisArg,[,arg1[,arg2,]]) 메서드



함수 형태 


콜백 함수

비동기 처리에서 어떤 신호가 왔을때
웹페이지에서 특정 DOM이벤트에 대응하는 함수 


즉시 실행 함수(1) 
(function(name){
console.log(‘hello -> ‘ + name);
})(‘foo’);

다시 호출안됨. 초기화코드에서 사용하면 좋음.


즉시 실행 함수(2)  
(funtion(window,undefined){

..
})(window);

프레임워크에서 사용됨
jquery 에서 전체를 묶음(바운더리만듬)


내부 함수

자신을 둘러싼 부모함수의 변수에 접근 가능

        (클로저) 


함수를 리턴하는 함수

var self = function(){
         console.log(‘a’);
      return function(){
                  console.log(‘b’);
                  }
}

self = self(); // result  >>  a
self();          // result  >>  b





호출패턴 과 This바인딩 

자바스크립트에서 함수를 호출할때 기존 매개변수로 전달되는 인자값에 더해, arguments 객체 및  This인자가 함수 내부로 

암묵적으로 전달됨. 자바스크립트에서 This 는 매우 중요하다. 함수가 호출되는 방식(호출패턴)에 따라 This 가 다른 객체를 

참조(This바인딩) 하기 때문이다.


This바인딩(객체의 메소드호출시) 

객체의 메서드를 호출할때, 메서드 내부에서 사용하는 This 는 해당메서드를 호출한 객체로 바인딩된다. 

var myObject = {
name: ‘foo’,
sayName : function(){
console.log(this.name);
}
};

var otherObject = { name : ‘bar’ };

otherObject.sayName = myObject.sayName;

myObject.sayName(); // ‘foo’
otherObject.sayName(); // ‘bar’



This바인딩(함수 호출시1) 

This는 전역 객체에 바인딩된다. 

-브라우저라면 window 객체
- Node 라면 globlal 객체 

“자바스크립트의 전역변수는 실제로는 전역객체의 프로퍼티들이다.”
var foo = “hello world”;
console.log(foo);   // hello world
console.log(window.foo); // hello world

var test = ‘This is test’;
console.log(window.test);

var sayFoo = function(){
console.log(this.test);
}

sayFoo();   // 'This is test' 



This바인딩(함수 호출시2) 

이런 특성은 내부 함수를 호출할때도 마찬가지이다.  즉 외부에서 객체를 호출한게 아니라면 this 는 전역임(아 어렵다 ..OTL) 
var value = 100;
var myObject={
value : 1,
func1 : function(){
this.value +=1;
console.log(‘ func1 this.value : ‘ + this.value);
func2 = function(){
this.value += 1;
console.log(‘ func2 this.value : ‘ + this.value);
}
func2();
}
}; 

myObject.func1();

  • " func1 this.value : 2"
  • " func2 this.value : 101"


This바인딩(함수 호출시3) 

다음과 같이  해결한다. 
var value = 100;
var myObject={
value : 1,
func1 : function(){
var that = this; 
this.value +=1;
console.log(‘ func1 this.value : ‘ + this.value);
func2 = function(){
this.value += 1;
console.log(‘ func2 this.value : ‘ + that.value);
}
func2();
}
}; 

myObject.func1();

  • " func1 this.value : 2"
  • " func2 this.value : 2"



This바인딩(생성자 함수 호출) 

그냥 기존함수에 new연산자를 붙여서 호출하면 해당 함수는 생성자 함수. 

new연산자로 함수를 생성자로 호출했을때 일어나는 일  (굉장히 중요함!!!) 

1.  빈 객체 생성 및 this 바인딩 
2.   this  를 통한 프로퍼티 생성 
3.  생성된 객체 리턴 

var Person = function(name){
this.name = name;
};

var foo = new Person("foo");
console.log(foo.name);  

  • "foo"
1. Person() 함수가 생성자로 호출되면, 일단 빈객체가 생성된다. this 를 빈객체와 바인딩 
2.빈객체는 Person() 의 prototype 프로퍼티가 가르키는 객체를 연결해서 자신의 프로토타입으로 설정
3. this 가 가르키는 빈 객체에  name 이라는 동적 프로퍼티 생성 
4. 리턴값이 없으므로  this  로 바인딩한  객체가 리턴값으로 반환되어 foo변수에 저장 





객체 생성 


객체 리터럴 vs 생성자 함수


리터럴은 한번만 가능 /   생성자함수를 사용하면 같은 형태를 재 생성 가능   




생성자 함수 호출시 

new없이   vs  new 를 붙여서 

this바인딩이 다르기때문에 오류발생가능 큼 
개발할때 큰 주의 요망. 

많은 라이브러리에서 내부코드에 저것을 방지하기위한 코드패턴이들어가있다. 

function A(arg){
                            if(!(this instanceof A))
                                         return new A(arg);





This바인딩(call, apply ) 

둘다 기능은 같으니 apply로 설명.
지금까지는 this 가  강제로 바인딩되었지만 apply를 사용하면 명시적으로 바인딩 

apply는 Function.property 객체의 메서드이다.
다음과 같이 호출가능.
function.apply(thisArg, argArray) 

function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}

var foo = {};

Person.apply(foo, [‘foo’, 30, ‘man’]);      // foo 객체가 Person 객체의 this 로 바인딩됨. 
console.dir(foo);

  • [object Object] {
      age
    : 30,
      gender
    : "man",
      name
    : "foo"
    }



함수 리턴  (1)

일반 함수나 메서드는 리턴값을 지정하지 않을 경우, undefined값이 리턴 

var noReturnFunc = function(){
console.log(‘This function has no return statement.’);

};


var result = noReturnFunc();
console.log(result);    // undefined




함수 리턴  (2)

생성자 함수에서 리턴값을 객체로 지정할경우 그 객체가 리턴된다. 

function Person(name,age,gender){
this.name = name;
this.age    = age;
        this.gender = gender;

return {name: "bar", age:20, gender : "woman"};
};

var foo = new Person("foo",30,"man");
console.log(foo);

  • [object Object] {
      age
    : 20,
      gender
    : "woman",
      name
    : "bar"
    }

   

생성자 함수의 리턴값으로 넘긴 값이 객체가 아니라 불린,숫자,문자열일경우는 무시. 



prototype 프로퍼티 vs [[Prototype]] 







function Person(name){
this.name = name;
}

var jane = new Person(‘Jane’);    // Person 객체는 상위에 프로토타입을 가지고있고, jane 이라는 새 객체가 생성되면 
                                                // jane 에 [[Prototype]] 이 생기고 그것은 Person 의 프로토타입을 가르키게 된다. 
                                                // 공통 상위단이 생긴다고 생각하면 된다.



프로토타입 체이닝

자바스크립트에서 객체는 자기 자신의 프로퍼티뿐만 아니라 ,
자신의 부모역할을 하는 프로토타입객체의 프로퍼티 또한 마치 자신의 것 처럼 접근하는게 가능하다. 이걸 가능케하는게 바로 프로토타입 체이닝!!




프로토타입 체이닝(1)

객체 리터럴 방식으로 생성된 객체의 프로토타입 체이닝 
Object.prototype 객체 

name = "john";
var myObject = {
name : ‘foo’,
sayName: function(){
console.log(‘My name is ‘ + this.name);    // 여기서  this 는  myObject  이다.
}
};

myObject.sayName();   
myObject.hasOwnProperty(‘name’);

  • "My name is foo"
  • true


name = "john";
var myObject = {
name : "foo",
  func1 : function(){
  sayName =  function() {
console.log("My name is " + this.name);     
};
        sayName();  // 이거 호출시  this 는 전역이다.  이런거 너무 헥깔린다;;
}
};

myObject.func1();   
myObject.hasOwnProperty("name");

  • "My name is john"
  • true



프로토타입 체이닝(2)

생성자 함수로 생성된 객체의 프로토타입 체이닝  
Person.prototype (함수에 연결된 프로토타입 객체는 디폴트로 constructor프로퍼티만 가진 객체이다) 

Person() -> Person.prototype->Object.prototype 

function Person(name,age,hobby){
this.name = name;
this.age    = age;
        this.hobby = hobby;
}

var foo = new Person(‘foo’,30,’tennis’);

foo.hasOwnProperty(‘name’); // true




프로토타입 체이닝(3)

프로토 타입 체이닝의 종점 Object.prototype 

객체 리터럴 방식이나 생성자 함수 방식에 상관없이 모든 자바스크립트 객체는 프로토타입체이닝으로 
Object.prototype 객체가 가진 프로퍼티와 메서드에 접근하고,서로 공유가 가능하다. 


그리고 표준 빌트인 프로토타입 객체에도 사용자가 직접 정의한 메서드를 넣을수 있다. 

String.prototype.testMethod = function(){
console.log(‘hello’);
};

var str = ‘this is test’;
str.testMethod();



프로토타입 체이닝(4)

프로토타입 메서드와 this 바인딩 

메서드 호출 패턴에서의 this 는 그 메서드를 호출한 객체에 바인딩!!

function Person(name){
this.name = name;}

Person.prototype.getName= function(){
return this.name;};

var foo = new Person(‘foo’);
foo.getName();  //  foo 

Person.prototype.name = ‘person’; // 동적 추가 
Person.prototype.getName(); // person 



프로토타입 체이닝(5)

디폴트 프로토타입(Person.prototype같은) 은 다른 객체로 변경이 가능 하다.

디폴트 프로토타입 객체는 함수가 생성될때 같이 생성되며, 함수의 prototype 프로퍼티에 연결 된다. 

자바스크립트에서는 이렇게 함수를 생성할때 해당 함수와 연결되는 디폴트 프로토타입 객체를 다른 일반 객체로 변경하는것이 

가능하다. 이러한 특징을 이용해서 객체지향의 상속을 구현한다.   


프로토타입 체이닝

객체의 프로퍼티 읽기나 메서드를 실행할때만 프로토타입 체이닝이 동작한다.




실행 컨텍스트

실행 가능한 코드를 형상화하고 구분하는 추상적인 개념 

실행컨텍스트가 형성되는 경우는 전역코드, 함수로 실행되는 코드, eval() 함수로 실행되는 코드 3가지 

현재 실행되는 컨텍스트에서 이 컨텍스트와관련 없는 실행 코드가 실행되면, 새로운 컨텍스트가 생성되어 스택에 들어가고 

제어권이 그 컨텍스트로 이동한다. 



실행 컨텍스트 생성과정 

1. 활성 객체 생성 

(해당 컨텍스트에서 실행에 필요한 여러가지 정보를 담을 객체)

- 매개변수
- 사용자가 정의한 변수 및 객체
- 스코프 정보

등이 앞으로 담겨짐..  

변수객체로 사용됨. 
 

2.  arguments 객체 생성
  - 매개변수를 담는다. 


3. 스코프 정보 생성  
 -리스트형식으로 만들어짐 이것은 상위 실행컨텍스트의 변수도 접근가능
 -이 리스트를 스코프 체인이라고 함

4. 변수 생성 
   - 지역변수의 생성이 이루어진다.
          (생성은 변수객체에 이루어짐,활성객체가 변수객체로 사용됨) 
   - 생성이 이루어지는것이지 초기화가 이루어지지는 않는다.
   - 초기화는 표현식이 실행될때 이루어진다. 
           (변수객체 생성이 다 이루어진후 표현식 실행됨)

5. this 바인딩 



스코프 체인 

void A()
{
for(.....)
{
int a = 10;
}

printf(“ a: %d”, a);   // 컴파일 에러  c 언어는 for, if문도 하나의 스코프
}  

자바스크립트는 오직 함수만이 유효범위의 한 단위가 된다.
유효범위는 스코프체인을 따라서 위로 계속 올라가면서 넓어짐.. 

- 각 함수객체는 [[scope]] 프로퍼틸 현재 컨텍스트의 스코프체인을 참조한다. 
- 한 함수가 실행되면 새로운 실행 컨텍스트가 만들어지는데, 이 새로운 실행 컨텍스트는 현재 실행되는 함수객체의 
  스코프 프로퍼티를 복사하고 새롭게 생성된 변수객체를 해당 체인의 제일 앞에 추가한다. 



스코프 체인 예제(1)

var value = “value1”

function printFunc(){
var value = “value2”;
function printValue(){
return value;
}

console.log(printValue());
}

printFunc();

  • "value2"


스코프 체인 예제(2)

var value = “value1”

function printValue(){
return value;
}

function printFunc(func){
var value = “value2”;

console.log(func());
}

printFunc(printValue);

  • "value1"
각 함수객체가 처음 생성될 당시 실행 컨텍스트가 무엇인지를 생각해야한다. 




클로저

function outerFunc(arg1, arg2){
var local = 8;
function innerFunc(innerArg){
console.log((arg1 + arg2) / (innerArg + local));
}
return innerFunc;
}

var exam1 = outerFunc(2,4);
exam1(2);   
  • 0.6



클로저(1)

function outerFunc(){
var x = 10;
var innerFunc=function(){ console.log(x)};
return innerFunc;
}

var inner = outerFunc();
inner(); 
  • 10

outerFunc 실행컨텍스트는 사라졌지만 outerFunc 변수객체는 여전히 남아있다.



클로저(2)
함수의 캡슐화
( I am brad. I live in seoul. I’am 28 years old 문장 출력하기)

var buffAr = [
‘I am’,
‘’,
‘.I live in ‘,
‘’,
‘. I \’ am’,
‘’,
‘years old.’,
]; 

function getCompletedStr (name, city, age) 
{
buffAr[1] = name;
buffAr[2] = city;
buffAr[5] = age;

return buffAr.join(‘’);
};

var str = getCompletedStr(‘brad’, ‘seoul’, 28);
console.log(str);



객체지향 프로그래밍 

var person = { 
name = “brad lee”,
getName : function(){
return this.name;
},
setName : function(arg){
this.name = arg;
}
};

function create_object(o){
function F(){};
F.prototype = o;
return new F();
}

var student = create_object(person);

student.setName(“ john “);
console.log(student.getName());  // john 


student 객체는 person 객체를  상속받은후에 다른 기능을  추가도  할수있게 된다. 

student.setAge = function (arg) { .....}  



하지만 이렇게 되면 코드가 지져분해지는데 , 그래서  라이브러리들은  extend() 함수를 제공

jQuery 1.0 의 extend() 를 살펴보자

jQuery.extend = jQuery.fn.extend = function(obj, prop) {
if( ! prop ){ prop = obj ;  obj = this; }
for(var i in prop ) {
obj[i] = prop[i];   // 얕은 복사 
}
return obj;
}; 


jQuery 1.7 에서는 깊은복사/얕은복사 선택을 해준다. 

jQuery 에서 이런것은 extend 는 

내가 만든 기능을 jQuery 에 플러그인으로 집어넣기 위해 사용할수 있겠다.


(function ($) {
$.extend( $.fn , {
my_func : function() {
...
}
} );
}) (  jQuery );






함수형  프로그래밍 

function sum( arr ){
var len = arr.length;
var i = 0 , sum = 0;

for ( ; i < len ; i++) {
sum += arr[i];
}

return sum;
}

var  arr = [ 1, 2, 3, 4, 5];
console.log(sum (arr));
  • 15

//////////////////////////////////////////////////////////////////////////////////

// 함수를 인자로 매개변수로 넘겨서 계산하게함. 
var sumFunc = function (x,y){
return x + y;
};

function reduce ( func, arr ){
var len = arr.length;
var i = 0 , sum = 0;
for( ; i < len ; i++){
sum  = func(sum, arr[i]);
}
return sum;
}

var  arr = [ 1, 2, 3, 4, 5];
console.log(reduce(sumFunc, arr));

  • 15






참고 

http://www.yes24.com/24/goods/11781589?scode=032&OzSrank=1
http://www.yes24.com/24/goods/3071412?scode=032&OzSrank=10



+ Recent posts