안녕하세요 js에서 사용하는 Array 에 대한 메서드에 대해 간단 설명 및 예시로 작성 하려고 합니다.


오늘은 [1] 입니다.  빨간 색 부분은 IE 미지원의 경우 입니다.


** 빨간메서드 부분은 Polyfill이 도입되어야 합니다.


각 함수마다 서포팅 되는 호환성 에 특이 한점은 적도록 하겠습니다.


[1] 에서 작성할 배열 메서드 입니다.

concat(IE 5.5) ,fill, filter(IE 9), findfindIndexincludes, indexOf(IE 9)




[2] 에서 작성할 배열 메서드 입니다.

join, keys, lastIndexOf, pop, push, shift, unshift,


[3] 에서 작성할 배열 메서드 입니다.

some, every, slice, splice, sort, toLocaleString, toSource, values


[4] 에서 작성할 배열 메서드 입니다.

reduce, reduceRight, reverse,  copyWithin, Array.of , Array.from



** 모든 설명은 mdn 을 참조하였습니다.


1. concat 


호환성 :  IE 5.5 이상 동작합니다. (전 브라우저 지원이라고 봐도 될거같습니다.)

description : 인자로 주어지는 배열이나 값들을 기존 배열에 합쳐서 새 배열을 반환합니다. 

깍돌이 설명:  배열1.concat(배열2) 와 같이 쓰면   [ 배열1 + 배열 2 ] 가 된 새 배열3 이 나옵니다.


** 메서드를 호출하게 된 배열 뒤에 인수로 넘어온 배열들을 붙여서 새로운! 배열을 생성합니다.

this나 인수로 넘겨진 배열의 내용을 바꾸지 않고 주어진 배열들을 합친뒤 얕은 복사(shallow copy)

를 리턴 합니다.


Example 1  fruits 배열과 animal 배열의 합치기  (2개)



Example 2  fruits 배열과 animal 배열과 language 배열의 합치기 (3개)



Example 3 fruits 배열에 단일 값 "NinJa" 와  ["QA","devOps"] 를 이어 붙이기

(배열에 값 붙이기)

Example Code


// concat

var fruits =["apple","oragne","grapes","strawberry","watermelon"];
var animal = ["dog","rabbit","horse","chicken","lion"];
var language = ["C","C++","Python","JS","GO"];

// Example 1
var newArray = fruits.concat(animal);
console.warn(newArray);

// Example 2
var newArray = fruits.concat(animal,language);
console.warn(newArray);

// Example 3
var newArray = fruits.concat("NinJA",["QA","devOps"]);
console.warn(newArray);



번외편 !

배열을 단순하게 + 로 더하면 어떻게 될까 ?

문자열이 됩니다.! ( 하지만 자세히 보면 watermelondog 로 붙어있는 부분이 있습니다. )

[... 끝]+[처음...]이 붙는 부분에서 "끝처음" 로 붙네요 쓸순 없습니다. ㅎ_ㅎ




2. fill


호환성 : IE,Opera는 아예 지원되지 않습니다.  (Chrome 36이상 FireFox 31이상 Safari 7.1이상)

폴리필을 사용 하여야 합니다.  // 폴리필 주소

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/fill

description : 배열의 시작인덱스부터 끝 인덱스까지 정적 값으로 배열 요소들을 채웁니다.


깍돌이 설명:   배열을 정해진 특정 값으로 채워넣기 위해 사용하는 함수입니다. (react에서 자주 사용합니다.)


** 해당 메서드를 사용한 배열의 원본 값이 변합니다. 주의 !!


Example 1  fruits 배열을 4로 채우기 



Example 2  fruits 배열을 2부터 4로 채우기 2부터에서 2는 index입니다(0부터시작)


Example 3  fruits 배열을 2부터 3까지만 4로 채우기  2에서 3은 index입니다.


** 특이사항 : 시작하는 start는 현재 인덱스를 포함하지만 end는 그 전 인덱스까지 입니다.
Example 4  fruits 배열의 start를 -1로 시작 
** 음수일 경우     start + length (배열 전체 길이 )
이기 때문에 현재 배열의 길이는 5이기 때문에 5 + - 1 이 되어서 fruits[4] 부터 4값이 들어가게 됩니다. 


Example 5  fruits 배열의 start를 -2로 시작 
** -2 + 5  = > 3 이기 때문에 index[3] 부터 4가 들어가게 됩니다. strawberry 부터 4값이


Example 6  fruits 배열의 end 를 -1로 시작
** 음수일 경우    end +  length (배열 전체 길이 ) > start와 형태가 같지만
start는 해당 위치부터
end는 해당위치까지입니다.

react 에서 순수 위젯 리스트를 표현할때 사용하기도 합니다.
const btnList = Array(this.props.count).fill(null).map((i,index) =>{
return <button type="button" style={btnStyle} key={"Btn_"+index} >
{this.props.name +"_"+index}</button>;
});





3. filter


앗.. filter부터 안써놓은지 몰랐습니다. ㅜㅜ 새롭게 다시 작성해서 채우도록;; 하겠습니다.'



호환성 :  IE 브라우저 9 이상 지원합니다. 

description : 조건에 맞는 함수를 통과하는 요소를 모아 새로운 배열로 반환 합니다.

깍돌이 설명:  특정 조건에 맞는 배열을 새롭게 반환시켜주는 함수라고 보시면 될 것 같습니다.


var fruits =["apple","oragne","grapes","strawberry","watermelon"];
fruits.filter(function(ele,index,arr){
    return ele.length >= 7; // ['strawberry','watermelon']
});






4. find


호환성 :  IE미지원

description : 

깍돌이 설명:  IE를 미지원하기 때문에 폴리필 코드가 필요합니다.

 


** 

Example 1  


5. findIndex


호환성 : 

description :

깍돌이 설명:  


** 

Example 1  


6. includes


호환성 : 

description :

깍돌이 설명:  


** 

Example 1  


7. indexOf


호환성 : 

description :

깍돌이 설명:  


** 

Example 1  




var temp = {

// do  attribute

}


temp라는  데이터 모델?(객체) 를 통해서 값을 채우고 해당값을 


var resultArr = []; 에


resultArr.push(temp);


식으로 사용하다가 객체 참조 오류가 나는 경우가 생겼습니다.


temp를 수정후 


resultArr.push(temp) 시에는


resultArr [0] = >temp를 가지고있습니다.


다시한번 push 할 경우


resultArr[1] = > temp 0과 1둘다 temp와 같은 곳을 바라보게 됩니다.


수정하면서 push 는 되지만


결국 마지막 수정된 push 값을 resultArr은 전부 가지고있게 되는 것입니다.


예시를 들어 보겠습니다.


해당 예시는 객체 참조 에 대한 예시일뿐입니다.

	

	var temp = {
			"name":"",
			"age":""
	};


	var resultArr = [];

	var response = [
		{"name":"AAA","age":"aa"},
		{"name":"BBB","age":"bb"},
		{"name":"CCC","age":"cc"},
	];



	for(var i=0;i<3;i++)
	{
			temp.name = response[i].name;
			temp.age = response[i].age
			resultArr.push(temp);
	}



해당 결과는?




마지막에 수정되었던 CCC cc값을 전부 가지고있습니다. 모든 배열들이 새로 추가될때마다 같은 temp를 바라보게 되는 상황이 있기 때문입니다.

** push 하는 순간에 (shallow copy (얕은복사) 가 일어나기 때문에 발생하는 현상입니다.)


// 해당 상황에 대한 해결법은

Array.prototype.slice.call 

Array.prototype.slice.apply 

Object.assign 등이 있지만 객체 참조에 대한 이야기로 계속 진행하겠습니다.





gdl blah 가 있습니다. 들어온 숫자만큼 블라 블라를 외치네요


objRef 라는 새로운 객체를 생성 후 속성으로 gdl blah 를 가지게 되면


위의 그림과 같이 같은 함수를 바라보게 됩니다.


아마 해당상태에서는 함수의 동작은 블라를 외치기만 하기 때문에 큰 문제가되어 보이지는 않습니다.





objRef는 그대로 놓은 상태로 gdl의 블라를 제거한다면 위의 그림과 같이


function 은 gdl의 blah 를 바라보고있었지만 해당 연결고리가 끊어지는 바람에  objRef는 바라볼곳이 없어지며 에러를 발생 시킵니다.


해당 객체 참조 이슈가 나타나게 되는데


함수를 작성할 때 함수 Context 를 지정하여 서 해결 할수 있습니다.



각 펑션이 현재 가지고있는 object를 context로 가지기 때문에 앞선 gdl이 사라져도 문제 없이 동작됨을 확인할수 있습니다.


너무 자주 쓰는데 너무 자주 찾아 보는거같아서 포스팅을 해놓고 보면 좀 나을거라 생각되서 포스팅을 합니다.


map,forEach 대해서 포스팅합니다.


함수 전부 Array.prototype 인것으로 보아 배열의 메서드로 보여집니다.


우선 map 부터 보자면



1. map 


Array.prototype.map()

var new_array = arr.map(function callback(currentValue[,index[,array]]) { // new_array 새 요소 반환} [thisArg]) 라고 되어있습니다.  mdn 참조


currentValue : 배열의 요소중 , 현재 처리되고있는 요소 


index  : 현재 처리되는 요소의 배열 내 인덱스


array : 메소드가 적용되는 본래 배열







반환 : 실행한 함수의 결과를 모은 새로운 배열 


** 새로운 배열을 만들어서 반환하기 떄문에 기존의 arr (원본) 배열은 그대로있음을 확인할수 있습니다.

또한 반복 중에 기존의 값에 새로운 값들을 추가해서 반환하여도 원본의 배열은 그대로임을  알수 있습니다.



2. forEach


Array.prototype.forEach();


forEach 의 파라미터 역시 위의 map과 동일합니다.


차이점은




반환 : undefined 반환값이 존재하지 않습니다.



또한 사용상의 주의점 ( js 의 주의) 이라고 할수 있는 점이 하나있습니다. 위에서는 원본 배열을 수정하여도 수정이 되지않는 점이 확인되었는데요


객체의 배열 형태면 이야기가 다릅니다.


forEach 에서 수정된 부분들이 forEachTest로 변경되었습니다.


그리고 그아래에 map으로도 다시 수정하게 되면



기존에 수정하였던 forEach 까지 수정되게 되는 현상이 발생합니다.


이런 현상은 js의 참조 현상 때문인데요 객체를 수정하실때는 매우 유의하여야 합니다.


이부분에 대해서는 따로정리 하였습니다.

// JavaScript 객체 참조 

http://ipex.tistory.com/entry/JavaScript-%EA%B0%9D%EC%B2%B4-%EC%9D%98-%EC%B0%B8%EC%A1%B0





개인적으로 자주 사용하는 메서드들 로는

fill() : 특정값으로 채움

filter() : 특정 조건에 맞는 배열 반환

includes() : 해당 값이 포함된지 확인

push() ,pop(), shift(),unshift(),reduceRight(),reverse(),slice(),sort(),splice(),reudce() 등등이 있습니다.



JavaScript의 Scope는 Block(블록 { } ) 이 아닌 Function(함수)에 의해 정해집니다.


우선 scope에 대한 간단한 예시 입니다. 


scope(유효범위) 란 ?


JavaScript 뿐만 아니라 모든 프로그래밍 언어에서도 통용되는 말이며


block Scope라 함은 

{

  변수 선언 

}

시 block 을 나가면 선언된 변수가 block 안에서만 생존 하는 것을 말합니다.

JavaScript는 기본적으로 block Scope가 아니라 Function Scope 입니다.

function a(){

변수 선언! (A)

    {  

     변수 선언 !(B) 

   }



// 변수 A와 B둘다 살아있음

}



이와 같이 변수를 선언해도 펑션안에서는 어떻게든 살아서 있기 때문에 접근도 가능합니다.

기본적인 block Scope는 C 언어를 보면 알수 있습니다.



블록 안에서 선언된 변수 들은 블록 안에서 끝나지 않고 Function(함수) 단위로 가게 됩니다.


그에 해당 하는 테스트 샘플 코드입니다.





function foo()
{
		console.warn('__Before__');	
		typeof first ==='number' ? console.log('first exist') : console.error('first not exist');
		typeof Internal==='function' ? Internal() : console.error('not exist');
		/*
			first not exist  'number'로 비교하였지만 undefined로 호이스팅(끌어올리다) 
			Internal exist   'function' 으로 비교하여 참조 의 호이스팅이 되는점 확인 -> 실제 함수 사용까지 가능)

		*/
		var first = 1;
		function Internal(){console.log("Internal exist");}

		console.warn('__after__');
		typeof first ==='number' ? console.log('first exist') : console.error('first not exist');
		typeof Internal==='function' ? Internal() : console.error('not exist');

		/*
			first exist 
			Internal exist 
		*/
		if(first===1){var third = 3;};

		typeof third==='number' ? console.log('third exist') : console.error('third not exist');
		
		/*
			third exist  var third 선언은 if(first===1) 분기를 타고 블록(block) 안에 선언되었지만 밖에서도 참조가 가능
		*/

}
foo();






Hoisting ?

코드 실행 전의 변수와 함수 선언을 해당 범위의 맨위로 이동 시키는 JavaScript 의 매커니즘 


고려해야 할 조건이 있습니다.


1. 변수 할당은 함수 선언보다 우선 

2. 함수 선언은 변수 선언보다 우선 

-> 하지만 함수 선언이 변수 할당을 넘어 서진 않습니다.



관련 참고 사이트 // 설명이 잘 되어있습니다. 

https://scotch.io/tutorials/understanding-hoisting-in-javascript






이런느낌으로 알고 지나가는게 좋을 것 같습니다.


펑션은 호이스팅으로 참조까지 가능하지만


변수(var)는 undefined로 호이스팅이 되는점









C언어는 절차 지향 언어라고 할수 있다. 해당 내용은 절차지향에 대한 이야기 일뿐


자바스크립트와는 많은 관련이 있진 않습니다. C를 하다 넘어 왔기 때문에


자바스크립트도 절차지향으로 보여 잘못생각하였던 부분에 대한 설명입니다.






#include 
using namespace std;


int main(void)
{
	printf("CPP Test\n");

	show(); //show 식별자를 찾을수 없습니다. 에러 
	return 0;
}

 void show() 
{
	printf("Show Call");
}

const int OpenResult(int flag) 
{


}



// 해당 호출이 불가능해지기 때문에


// 실제 사용시에는

// 이 처럼 코드 상단에 미리 선언을 하고 원형을 하단에 작성한다.C 의경우


#include 
using namespace std;

// 절차 선언 
void show();
int main(void)
{
	printf("CPP Test\n");

	show();
	return 0;
}

 void show() 
{
	printf("Show Call");
}


의 형태로 지원되어야 한다. 절차지향




자바스크립트 또한 그럴것이라 생각 하였지만 실제 JS에서 유효범위는 생각과는 달랐다.










function external(){

typeof Internal ==='function'  ?  console.log("Internal  exist") : console.log("Internal  not exist");

function Internal (){};

typeof Internal ==='function'  ?  console.log("Internal  exist") : console.log("Internal  not exist");

window.Internal === undefined ? console.log('Internal is not window exist' ) : console.log('Internal window exist');

window.external === undefined ? console.log('external is not window exist') : console.log('external window exist');
}

external();




결과


Internal  exist

Internal  exist

Internal is not window exist

external window exist



1번째에


typeof Internal ==='function 부분에서 exist로 넘어가는것으로 보아


절차적으로 코드가 생성되는것으로 보였지만 


자바스크립트의 유효범위는 블록이 아니라 함수에 의에 정의된다고 할수있다.


여기까지보면 뭔가 큰 차이가 안 느껴져서  자바스크립트의 Scope Chain 은 Function 이라는 예제를 하나 더 들수 있다.

C의 경우




void show() 
{
	printf("Show Call");

	for (int i = 0; i < 5; i++)
	{
		int b = 10;

	}
	printf("B is %d", b);
}

// 와 작성시 이미 printf b 에서 컴파일 하기도전에 validation 에 걸립니다. b가 정의되어있지 않습니다. 
// C,C++에서는 Scope Chain 은 Block Scope를 가진다는 것을 알수 있습니다. 

JavaScript 의 경우


function show()
{
   for (var i=0;i<5;i++)
   {
			var b = 10;
   }
console.log("B is ",b);
}
show();


// 결과
// B is  10



자바 스크립트의 Scope Chain 은 위와 같이 Function 을 가지게됩니다.


이에 대해서 JS 작성시 실수하였던 점이





   for(var i=0;i<10;i++)
  {   
        for(var j=0;j<10;j++)
        {
              for(var i=0;i<5;j++)
              {
               }

         }

        
  }
       









해당 식의 코드를 한번 짤일이 있었는데 디버그 하다가 애를 먹었던적이 있습니다.


처음 i 0 ~을 돌다가 3번째 for문에서 i가 4인 채로 끝나기 때문에  자기 밖으로나가면 i2가 된상태로 돌아야하지만


i4인채로 끝나서


첫번째 포문에서 i 0 1,2,3 부분이 건너 뛰고 바로 4로 넘어가는 현상이 생겼습니다.


js에서는 function Scope Chain 을 가지기 때문에 해당 부분에 유의 하여야 합니다.


최근 ES스펙이 오름에 따라서 let변수가 해당 C,C++의 block scope 를 가지게 도와주지만 해당 내용은 뒤에 작성하도록 하겠습니다.













아직까지 업무도중에 reduce를 쓸일이 없어서 reduce랑 reduceRight 가 몇번 건드리긴 했는데


제대로 해본적이 없다 보니 reduce에 대해 자세하게 알아보기로했다.


매번 return map forEach 만 사용했는데 


https://jsperf.com/native-map-reduce-vs-for/2


reduce가 엄청나게 파워풀하고 map filter forEach 를 전부 해결할수있는 만능 이라는것도  알게되면서


reduce에 대한 포스팅을 하려고합니다.

알아야 하는 JavaScript 


1. JavaScript Event Loop 에 대해 설명


2. JavaScript 에서의 비동기 처리 과정


3. Hoisting 이란


4. Closure 란


5. this 에 대해서 설명


6. Promise 에 대해 설명


알아야하는 front-end


1. 브라우저의 동작 원리 설명


2. Document Object Model (DOM)

Event bubbling and Capturing 설명

Event delegation


3. CORS 에 대한 설명


4. 크로스 브라우징 예시 


5. 웹 성능과 관련된 Issue


6. 서버사이드 렌더링 (SSR) 과 클라이언트 사이드렌더링 (CSR) 


7. CSS Methodology


8. normalize .css    vs reset.css


&& 이외 

1. 페이지 로드를 줄일 수 있는 방법을 나열 


1-1 이미지맵 

여러개의 이미지를 띄우지 않고 한개의 이미지에 사용되는 이미지들을 넣어 놓고 사용합니다.

login.png,logout.png,user.png을 따로 부르는것이 아닌 loginPage.png 라는 곳에 다 넣어 놓고

이미지를 픽셀로 짤라서 불러오는 방식을 사용합니다. 

2. CSS 애니메이션과 자바스크립트 애니메이션의 장단점을 설명하시오


3. 간단한 슬라이드쇼 페이지를 어떻게 개발할지 설명해보시오.





JavaScript 에서 생성자와 프로토타입은 겉으로는 비슷하게 동작하는 것으로 보이지만


실제로 내부적으로는 많은 다른 동작이 있습니다.


해당은 new를 통해서 생성자 함수로 만들어서 사용 하였습니다.


function SuperConstructor(arg){

    this.id = arg;
    
    this.getId = function(){
            return this.id;
    }
    this.setId = function(_id){
        this.id = _id;        
    }
}

var gdl = new SuperConstructor('q1w2e3r4');
console.warn(gdl.getId());    //q1w2e3r4

var gdl2 = new SuperConstructor('qwer1234');
console.warn(gdl2.getId()); // qwer1234




해당 코드를 Prototype으로 변경 해보겠습니다.





function SuperConstructor(arg){

    this.id = arg;
    
}
SuperConstructor.prototype.getId = function(){
			return this.id;
}
SuperConstructor.prototype.setId = function(_id){
			this.id = _id;
}
var gdl = new SuperConstructor('q1w2e3r4');
console.warn(gdl.getId()); // q1w2e3r4

var gdl2 = new SuperConstructor('qwer1234');
console.warn(gdl2.getId()); // qwer1234




두개의 코드 다 결과가 같습니다. 


하지만 내부적으로는 큰 차이가 하나 있습니다.


프로토타입의 경우에는 프로토타입 체이닝이라는 변수가 존재합니다. 


1번째 방식을 사용하게 되면 


메모리 사용되는 폼은 이와 같습니다.



( gdl - getId, setId, id) ( gdl2 - getId, setId, id) ( SupterConstructor - getId, setId, id)


2번째 방식을 사용하게 되면


메모리 사용되는 폼은 이와 같습니다.



(gdl - id)  ↘

                ->   (SuperConstructor -prototype.getId, prototype.setId)

(gdl2 - id) ↗  


와 같이 되며 gdl .setId일시 프로토타입 체이닝을 통해서 -> SupterConstructor 에 있는 값을 찾아가며


해당 함수에서 this.id로 지정이 되었기 때문에 this는 체이닝으로 부터 넘어온 gdl 이 된다.


그러므로 gdl 에 있는 id값을 지정하게 됩니다.


2번의 경우는 확실히 프로토타입 함수가 프로토타입 체이닝으로 인해서 중복 호출에 대한


최소화가 이루어졌기 때문에 


OOP 와 같은 프로그래밍을 하기 위해서는 Prototype 을 사용함을 권장합니다.




자바스크립트에서 this에 대해 공부하다 보면 이해한거 같다가도 클로저 함수가 들어오면 또 이해가 안되는 경우가 많아


this에 대한 이해를 IIFE 패턴에서 어떻게 사용되는지 확인해 보았습니다.


this는 함수 함수 scope 단위로 생성 됩니다. 라는 점을 알고 작성하겠습니다.


해당 객체를 통해서 this의 생성 범위를 확인 해 보면


iife = (function (){

var a = function(){

console.log('iife function a ', this);

                }

       return {

a:a,

       }

})();



결과 :


iife.a();

iife function a  {a: ƒ}


이제 함수 몇개를 추가하여서 iife라는 객체에서 return 되지 않는 함수에 대한 this 확인 

-> 이점이 처음에 this와 iife에 대해서 잘못 이해 하였던 부분이 있습니다.


c계열에서 class라고 생각하다 보면  iife라는 객체로 감싸져있기 때문에 어떤 함수여도 this는 iife라고 생각 했기 때문입니다.



iife = (function (){

		var outerFunction_aa = function(){

		console.log('iife function a ', this);
			
				// this.inner_d(); // error is not a function
				// this.inner_e(); // error is not a function

				inner_d();   // success    -> inner delcaration function  [ window ]
				inner_e();   // success    -> inner expression function  [ window ]
        }


  		// function declaration
		function inner_d(){
				console.log('inner declaration function', this);
        }
		// function expression
		var inner_e = function (){
				console.log('inner expression function',this);
        }

		var outerFunction_b = function(){
				console.log('outer expression function_b ' , this);
        }



       return {
		outer_a : outerFunction_a,
		outer_b : outerFunction_b,
       }

})();

결과 : 실행은 iife.outer_a(); 로 하였을때

this.inner_d();  

this.inner_e();  두 함수다 에러로 표시되며 메시지는 is not a function 

즉 this에 inner_d 가 없다는 뜻입니다. 

(js에서 inner_d가 프로퍼티인데 지정이 안되었을 경우는 undefined 로 되기 때문에 호출하여도 에러는 나지 않습니다.)

하지만 함수의 경우는 실행을 하여야 하기 때문에 정의되거나 함수이지 않은 경우는 is not a function 에러가 나타나게 됩니다.


하지만 this를 제외하고 실행시 

inner_d();  

inner_e();  두개의 함수다 실행되며 내부 함수에서 this는 [window] 가 잡힙니다.


??? IIFE 패턴으로 묶었는데 왜 window가 잡히는지 이해가 잘 안됩니다. 


-> 사실은 이게 class처럼 감싸진게 아닙니다. 


iife객체는 생명주기가 끝난  익명함수의 실행컨텍스트를 가지고 있습니다.


iife객체는 현재 return 되었던 outer_a 와 outer_b 만 을 가지고있습니다.


일반 함수에서 this는 [window]인것 처럼


IIFE패턴과 같이 위에 처럼 작성되어도 

return  { 

// closure space 

}


가 포함되어있지 않은 함수는 expression(함수 표현식) 이나 declaration(선언식) 이나 window를 지칭하게 됩니다. 


하지만 함수 자체(return 되지않은 inner_d)는 


iife.a() 형태로 직접 실행되지 않았기 때문에 this는 [window] 에 바인딩되게 된다.


this의 생성 조건은  해당 메서드를 호출한 객체로 바인딩 이기 때문이다.


그렇기 때문에


iife.outer_a(); 로 호출하였을 경우 outer_a()는 앞에 iife객체가 this가 되지만 해당 함수 내부에서 내부 함수를 호출하기 위해서는


inner_d();   // success    -> inner delcaration function  [ window ]
inner_e();   // success    -> inner expression function  [ window ]

해당형식으로만 선언할수 있기 때문이다.  해당 함수의 선언이 가능한 이유는 iife의 실행컨텍스트 안에 들어있기 때문에 그냥 선언해서


사용하여야 한다.  this로 안나오는 경우는 this가 window이기 때문이다.  


그러면 private하게 변수나 함수를 어떻게 사용하여야 할까


함수 선언식과 표현식은 호이스팅의 차이 유무가 있기 때문에 이후 코드는 표현식으로 사용하겠습니다.


정말 처음에 공부할때 바로 생각도없이 아 그러면 return 함수를 만들고 그안에서 this . value로 쓰면되겠다!


그러면 private로 쓸수 있을줄 알았다면



iife = (function (){
	var innerValue = 1;
		var outerFunction_a = function(){
			console.warn(this);
			console.warn('inner Value ', this.innerValue);	
		}

		var outerFunction_b = function(){
			console.warn('inner Value ', this.innerValue);				
        }

	// function expression
		var inner_e = function (){
			console.warn(innerValue);
        }



       return {
		outer_a : outerFunction_a,
		outer_b : outerFunction_b,
       }

})();

결과 : 실행은 iife.outer_a(); 로 하였을때

▶ : {outer_a:f, outer_b:f}

▶ : inner Value undefined 

undefined로 나온다. 왜 return 을 안했기 때문


innerValue :innerValue, 로 리턴을 해주면 동작은 하지만 그렇게 되면 private 라고 할수 있을까


iife.innerValue = 5 를 입력하게되면 내부값 역시 5로 바뀌기 때문이다. 


일단 내부 변수를 밖으로 빼내는거 자체가 좋은생각은 아니기 때문에 getter, 와 setter를 활용 한다.


또한 내부 함수를 스코핑을 통해서 실행시키기 위해서는


var this_ = this; 를 활용한다.


이에 대한 기본적인 구성은


iiife = (function (){
	var innerValue = 1;
	var arr= [0];
		var outerFunction_a = function(){
			console.warn(this);
			console.warn('inner Value ', innerValue);	
		}

		var thisChange = function(){
				console.warn('thisChange tihs');
				console.log(this);
				var _this = this;
				
				console.warn('forEach this');
					arr.forEach(function(item,index){
								console.log(this);
								console.log(_this);
                    });
				console.warn('map this');
					arr.map(function(item){
							console.log(this);
							console.log(_this);
                    });
			
				console.warn('arrow function this');
			
					arr.map( item => {
							console.log(this);
							console.log(_this);
                    });


					
        }

	// function expression
		var inner_e = function (){
			console.warn(innerValue);
        }

		var getValue = function(){
				this.innerValue;
        };
		
		var setValue = function(value){
				this.innerValue = value;
        };

       return {
		outer_a : outerFunction_a,
		thisUse : thisChange,
		setValue : setValue,
		getValue : getValue,
       }

})();
iife.thisUse();


arrow function 을 쓸 경우는 새로운  this가 바인딩되지 않습니다. 이것은 arrow function 에서 새롭게 포스팅 하도록 하겠습니다.


위의 코드 결과입니다.




getter,setter에 대한 포스팅은 


http://benalman.com/news/2010/11/immediately-invoked-function-expression/#iife 에 자세하게 잘 나와있어 링크 합니다.




+ Recent posts