생각을 개발하자, 박진형

[자바스크립트] 필수 개념 - 어렴풋이 알면 모르는 것 본문

Javascript/javascript

[자바스크립트] 필수 개념 - 어렴풋이 알면 모르는 것

imjinbro imjinbro 2017.07.28 16:27
[기본이자 필수개념 - js 프로그래밍 할 때 모르면 코드 못짜, 다른 사람 코드 못봐]
1) 브라우저 환경에서 자바스크립트는 샌드박스 환경에서 실행됨 : 파일 입출력 막기
2) 함수를 통해 생성된 객체는 __proto__ (부모 객체의 프로토타입을 저장하는 프로퍼티가 존재함) 
=> new String, new Object, new 사용자함수 등
     => 사용자 함수를 선언하는 것 : new Function()
=> 리터럴로 string을 생성하는 경우에는 x
=> 부모 객체의 prototype 객체 프로퍼티에 추가를 하면 상속받는 객체들이 추가된 메서드나 변수를 사용할 수 있음
     => 프로토타입 체인 : 해당 객체에 프로퍼티가 존재하지않을 경우 부모 객체로 올라감
     => 즉시 반영  : 부모 역할을 하는 function의 프로토타입 객체에 추가되면 생성자함수로 생성된 객체 프로퍼티에 바로 추가
          => 상속 구현

3) var 키워드로 변수를 선언하면 함수를 기준으로 해서 스코프가 정해짐 : if(var i=0; )의 i가 특정 function에 속해져있지않으면 i는 전역변수
=> 함수 단위로 스코프 정보를 생성
     => function의 경우에만 [[Scope]] 프로퍼티가 존재함
          => [[Scope]]에는 상위 개념의 함수 스코프를 저장하고있음 : 최상위 전역스코프
          => 현재 function level에서 존재하지않거나 중복된 이름으로 선언된 변수의 경우 가장 인접한 지역([[Scope]]) 스코프부터 훑음
     => function 이외에는 [[Scope]] 프로퍼티를 가지고 있지않음
=> 함수 내부에 선언된 변수는 함수 내의 스코프에서만 유효 : 변수 선언 키워드를 생략한채 선언하면 전역변수(window 객체의 변수)가 됨
=> 의도치않은 무한 루프문을 만들 수 있음 : 브라우저 환경에서 여러 스크립트를 하나의 페이지에서 돌릴 경우
     => 전역변수 남발 X : 전역변수를 하나의 객체에 모아서 사용하는 것도 한 방법
     => 즉시실행함수 사용 : 즉시실행함수의 경우 호출되고 바로 없어짐
     => 변수의 이름은 명확하게
     => 변수 키워드 확실하게 쓰자 : 스코프 생각하면서

=> for문을 돌려 i가 찍는 명령문을 함수에 넣고 다음에 돌리면 i는 반복문의 마지막 수가 나옴 : 전역변수 i를 참조하기때문(i 현재값 출력)
     => 관련 코드
          var funcArr = [];

          for(var i=0; i<5; i++){
                funcArr.push( function() { console.log(i) };
           }   

          funcArr[0](); // 5 출력

     => 클로저를 활용하던지 ES6의 let 키워드를 활용하면됨 
          => 스코프 참조 순위 : window를 맨 뒤로 밀어버림
     => let 키워드는 함수레벨 스코프가 아니라 블록레벨 스코프

4) 내부함수는 외부함수의 스코프를 저장함 : [[Scope]] 프로퍼티를 조회해보면 스코프 정보가 2개로 늘어남 
(0) Closure 스코프 : 외부함수의 스코프 정보를 저장
(1) Global 스코프 : window 객체의 스코프 정보를 저장
=> 내부함수는 외부함수의 스코프를 저장한다!
=> [[Scope]] 에 저장된 스코프의 스코프체인 탐색 우선순위는 id값이 낮을수록 높음

5) 자바스크립트는 함수 선언과 할당문을 분리함 : 선언문을 맨 위로 끌어올림
=> var a = function() {}  -> var a = undefined -> 실행! -> a = function() { }
=> function a() {} 의 경우는 따로 분리하지않고 로딩 시점에 초기화하고 VO에 저장 : 함수 호출이 어디에 위치하더라도 실행됨

6) Lexical Scope : 함수가 선언된 시점의 스코프 정보를 그대로 따름
=> 관련 코드
var i = 10;

function foo(){
     var i = 5;
     bar();
}

function bar(){
     console.log(i);
}

foo(); // 10
=> 자바스크립트의 스코프는 함수레벨스코프

7) 함수가 호출될 때 매개변수로 전달되는 인자값 이외에 arguments 객체와 this를 암묵적으로 전달받음

8) 자바스크립트의 this에 바인딩되는 객체는 한가지가 아니다.
(1) 객체의 메서드 : obj2.sayName() -> obj2 전달 -> this에 obj2 바인딩
=> prototype 객체의 메서드 : this -> 생성자함수로 생성된 객체.메서드 -> this에 생성된 객체 바인딩
=> 호출될 때 this를 전달
 
(2) (전역)함수 : 전역객체 window 바인딩
=> (1)번과 같음 : 전역객체의 메서드
=> 함수의 내부함수도 this는 window 바인딩
=> 객체 메서드의 내부 함수는 window를 바인딩 : 메서드의 내부함수를 사용할 때 this를 사용하면 위험
     => 프로토타입(prototype) 객체 메서드 내부함수 사용 : 객체지향을 구현, 내부함수를 사용할 경우 알고있어야지
     => 해결방법 : 외부함수(객체의 메서드)의 this를 변수에 저장(클로저)
     var obj = {
          x : 10,
          foo: function(){
               var that = this;

               function inner(){
                    console.log(this); // window
                    console.log(that); // obj
               }
          }
     }
     => 해결방법 : 명시적 바인딩(call, apply) 메서드 사용

(3) 생성자함수 : 일반함수처럼 인자값을 this에 추가하면 window에 추가되고, new 키워드를 사용해서 호출하면 생성되는 객체에 바인딩
var Person = function(name){
     this.name = name; 
}

Person.prototype.sayName = function(){
     console.log(this.name);
}

Person('hi'); // window.name == 'hi'
var jinbro = new Person('jinbro'); // jinbro.name == 'jinbro'
jinbro.sayName(); // 'jinbro', 객체의 메서드 -> 호출 시 this 전달

=> jinbro라는 빈 객체 생성(생성자함수가 새로 생성하는 객체) -> this에 빈 객체 바인딩  -> jinbro의 __proto__를 Person의 prototype으로
=> 생성자 함수 객체 생성 과정을 간추리면? 빈 객체 생성 -> this 바인딩 -> 프로토타입 설정
     => {}, [] 는 new 를 생략하고 객체를 생성하도록 한 것 : new Object, new Array
=> this는 새롭게 생성된 객체를 가리키는 키워드가 됨
=> 객체 리터럴로 객체를 생성할 경우 : new Object() -> 생성하는 객체에 바인딩 -> 생성 객체의 __proto__ 를 Object의 prototype으로


(4) 명시적 바인딩 : 자바스크립트 엔진 내부에서 자동으로 바인딩되는 결과가 아닌 사용자가 직접 바인딩시킴
=> apply, call, bind 함수가 있음 : 인자값으로 this에 바인딩할 객체를 넘겨주면서 함수를 호출
=> 함수명.apply 혹은 bind, call : Function의 prototype 객체.call / apply / bind
=> 객체의 메서드에 자신의 객체를 this 바인딩시켜서 호출할 수 있음

9) 실행가능한 코드 영역 : 전역, 함수, eval / 실행에 필요한 여러 정보 : 변수, 매개변수, 함수 선언, 스코프, this
=> 자바스크립트 엔진은 실행에 필요한 정보를 실행컨텍스트(각각 생성)라는 객체에서 관리
     => Variable Object(변수, 매개변수, 함수 선언) / [[Scope]] / thisValue
     => VO의 경우 전역과 함수 영역으로 나뉨 : 전역은 함수 선언만 / 함수 영역은 함수의 매개변수를 배열 형태로 담고 있는 arguments 객체 
     => 실행 가능 영역에서 여러정보를 담고 있는 객체 생성함
     => 순서 : [[Scope]] 생성 초기화 -> VO -> thisValue 결정

=> 컨트롤이 실행가능한 코드로 이동하면 실행컨텍스트 스택에 쌓임 : 실행이 종료되면 스택에서 제거
=> undefined로 VO의 멤버값들을 SET 해두고, 실행되면 대입
     => 전역은 프로그램 실행되자마자 실행(전역 변수 초기화)
     => 함수는 호출되자마자 VO의 멤버값들을 초기화

10) 자바스크립트 함수는 일급객체 : 클로저 구현, 실행컨텍스트 순서에 대한 이해가 되어있어야함
function outer(){
     var x = 0;

     return (function(){
          return x+=1;
     });
}

var timer = outer();
timer(); // 지속적으로 호출할 경우 1, 2, 3, 4, 5 ---- 1씩 증가
=> 즉시실행함수를 내부함수로 사용 : 외부함수 종료 시에 즉시실행함수를 리턴, 즉시실행함수는 outer의 Scope를 Scope에 추가
     =>  outer()의 x에 +1을 더하는 것임 : 복사하는 것이 아니라 참조하는 것
     => 실행컨텍스트 : 함수 1개당 1개X 실행시킬 때마다 생성 -> 콜스택 : 전역 컨텍스트의 VO 함수 -> 함수 실행 -> 실행컨텍스트 생성

11) 자바스크립트는 비동기 처리 : 완료될 때까지 기다리는 것이 아니라 다음 실행될 코드를 처리함
=> 동기처리를 할 경우 현재 실행되고있는 코드가 완료될 때까지 다음코드가 실행되지않음
=> 대부분의 함수처리를 비동기로 처리
=> 단일 쓰레드 단일 콜스택 비동기처리 : ????? 여러갈래로 처리하는 것이 아니라 실제로는 한 갈래 여러개 처리?
     => Run to Completion : 함수가 실행되고 종료되기 전까지 다른 함수는 끼어들 수 없음
     => 이벤트 루프 기반 비동기처리 : Call Stack -> WebAPIs(비동기호출을 위한 함수 영역, 엔진 외부) 처리 -> task queue -> Call Stack -> 끝

     => 눈으로 확인하기 : https://goo.gl/7u9etL