2장 : 기초

장윤희·2022년 4월 19일
0

JsPatterns

목록 보기
2/5
post-thumbnail

전역변수

전역변수의 사용을 최소화
var 선언은 한번만 사용
루프 내에서 length는 개시해두고 사용을 코딩 규칙 준수

전역변수의 사용을 최소화

모든 자바스크립트 실행환경에는 전역객체가 존재, 이때 this를 사용하면 전역객체에 접근
전역변수를 생성하는것은, 이 전역객체의 프로퍼티를 만드는 것과 같다

전역변수의 문제점

모든 전역변수는 동일한 네임스페이스 안에 존재하기 때문에
애플리케이션 내의 다른 영역에서 목적이 다른 전역 변수를 동일한 이름으로 정의할 경우 덮어쓰게 된다. 따라서 전역변수의 사용을 최소화 해야한다
네임스페이스 패턴이나 즉시 실행 함수를 활용

자바스크립트에는 암묵적 전역이라는 개념이 있기 때문에
선언하지 않고 사용한 변수는 자동으로 전역 객체의 프로퍼티가 되어 명시적으로 선언된 전역변수와 별 차이 없이 사용 할 수 있다

function(){
    //암묵적 전역
    result = x + y;
    return result;
}

function(){
    //var로 변수를 선언
    var result = x + y;
    return result;
}

암묵적 전역을 생성하는 또다른 안티패턴은 하나의 var 선언에서 연쇄적으로 할당
a는 지역변수지만, b는 전역변수가 된다

function(){
    //안티패턴 사용하지 말것
    var a = b = 0;
}

: 평가 (evaluation)이 오른쪽에서 왼쪽으로 진행되기 때문이다

b = 0이라는 표현식이 평가되는데 이때 b는 선언되지 않은 상태이다
이 표현식의 반환 값 0은 다시 var a로 선언된 새로운 지역 변수에 할당 된다
즉, 앞의 코드는 var a = (b = 0);이 된다
var a, b;로 미리 선언해두면 전역변수가 생성되는 일이 없다

var 선언을 빼먹었을때의 부작용

암묵적 전역변수와 명시적으로 선언된 변수 사이에 존재하는 차이점은
delete연산자를 사용하여 이 변수의 정의를 취소할 수 있는지 여부이다

  • var을 사용하여 명시적으로 선언된 전역 변수
    (프로그램 내에서 생성되었지만 함수에는 속하지 않는 변수들)는 삭제 할 수 없다
  • var을 사용하지 않고 생성한 암묵적인 전역변수
    (함수 안에서 생성되었든 아니든) 삭제할 수 있다

암묵적인 전역변수가 엄밀히 말하면 변수가 아니라 전역 객체의 프로퍼티라는 사실을 보여준다

var global_var = 1;
global_novar = 2;
(function (){
    global_fromfunc = 3;
}());

//삭제해본다
delete global_var; //false
delete global_novar; //true
delete global_fromfunc; //true

//삭제되었는지 확인
typeof global_var; //"number"
typeof global_novar; //"undefined"
typeof global_fromfunc; //"undefined"

프로퍼티는 delete연산자로 삭제할 수 있지만, 변수는 그렇지 않다

객체에 대한 접근

브라우저에서는 window속성을 통해 전역 객체에 접근 할 수 있다
다른 환경에서는 프로퍼티가 다른 이름으로 불리거나 존재하지 않을 수 있다

window라는 식별자를 직접 사용하지 않고 전역 객체에 접근하고 싶다면
함수 유효범위 안에서 다음과 같이 정의하면 된다. 함수 유효범위가 중첩되어 있어도 상관없다

var global = (function(){
    return this;
}());

이렇게 하면 항상 전역 객체를 얻을 수 있다

함수를 new와 생성자를 사용해 호출하지 않고 그냥 함수로 호출한 경우
함수안에서 this는 항상 전역 객체를 가리키기 때문(ES5에서는 더이상 안됨)

cf) 예를 들어 라이브러리를 개발하고 있다면,
라이브러리 코드를 즉시 실행함수로 감싼 후 즉시실행 함수의 인자로 전역 유효범위를 가리키는 this를 전달하는 방법이 있다

  • 단일 var 패턴(함수 상단에서 var선언을 한번만 쓰는 패턴)
    함수에서 필요로 하는 모든 지역변수를 한군데서 찾을 수 있다
    변수를 선언하기 전에 사용할 때 발생하는 로직상의 오류를 막아준다
    변수를 선언한 후 사용해야 한다는 사실을 상기시키기 때문에 전역 변수를 최소화하는데 도움이 된다

  • 변수를 선언할때는 초기값을 주어 초기화
    객체를 할당할 변수였는지 정수를 할당할 변수였는지 짐작 가능

호이스팅?

여러군데에서 var선언을 사용 할 수 있지만 모두 함수 상단에서 선언된 것과 동일하게 동작 (cf.호이스팅)

for루프

for루프 안에서는 보통 배열이나 arguments, HTMLCollection 등 배열과 비슷한 객체를 순회

  • 비효율적 방법
for (var i = 0; i < myarray.length; i++){
    //myarray[i]를 다루는 코드
}
  • 효율적 방법
for (var i = 0; max = myarray.length; i < max; i++){
    //myarray[i]를 다루는 코드
}

이렇게 하면 length는 한번만 구하고 루프르 도는 동안 이 값을 사용한다 for루프를 좀더 최적화할 수 있다

for문에 두가지 변형 패턴이 있다

var i, myarray = [];
  for (i = myarray.length; i--;){
      //myarray[i]를 다루는 코드
  }
while 루프 사용
  var myarray = [];
  i = myarray.length;

  while (i--){
    //myarray[i]를 다루는 코드
  }

for-in 루프

배열이 아닌 객체를 순회할 때만 사용
for-in으로 루프를 도는 것을 열거라고 한다
for-in에서는 프로퍼티를 열거하는 순서가 정해져있지 않다
배열 - for
객체 - for-in

js에서 배열은 객체이지만 for-in사용이 권장사항은 아님

객체의 프로퍼티를 순회할 때는 프로토타입 체인을 따라 상속되는 프로퍼티들을 걸러내기 위해 hasOwnPropery()사용해한다 그래야 clone()이 나오지 않음

내장 생성자 프로토타입 확장 하기 / 안하기
내장 생성자 프로토타입을 확장하지 않는 것이 최선
예외가 허용 되려면 아래조건 모두 만족해야한다

  • ECMAScrpt 5에 기술 되었으나 아직 브라우저에 내장되지 않은 메서드라면 추가할 수 있다 이 경우에는 메서드를 미리 정의하는 것
  • 프로터피 또는 메서드가 이미 존재하는지, 이미 코드 어딘가에 구현되어있거나,
    지원 브어우저 중 자바스크립트 엔진에 내장되어 있는지 확인
  • 이 변경사항을 명확히 문서화 하고 팀 내에서 공유

switch 패턴

var inspect_me = 0;
    result - '';

switch (inspect_me){
case 0:
    result = "zero";
    break;
}
case 1:
    result = "one";
    break;
default:
    result = "unknown";
}

각 case문을 swich문에 맞추어 정렬
각 case문 안에서 코드를 들여쓰기
각 case문은 명확하게 break로 종료
breack를 생략하여 통과 시키지 않는다
상응하는 case문이 하나도 없을때도 정상적인 결과가 나올 수 있도록 swich문 마지막에는 default문을 쓴다

암묵적 타입 캐스팅 피하기

js는 변수를 비교할 때 암묵적으로 타입캐스팅을 실행한다
false == 0이나 "" == 0과 같은 비교가 true를 반환한다
암묵적 타입캐스팅으로 인한 혼동을 막기 위해서는 항상 표현식의 값과 타입을 모두 확인하는 ===와 !== 연산자를 사용해야 한다

eval() 피하기

이 함수는 임의의 문자열을 받아 js 코드로 실행한다
동적인 프로퍼티에 접근 할 때는 대괄호 표기법이 더 간단하고 좋은 방법이다

//안티패턴
var property = "name";
alert(eval("obj." + property));

//권장안
var property = "name";
alert(obj[property]);

newFunction() 생성자를 사용하는 것도 eval()과 비슷하기 때문에 신중해야한다
newFunction()안에서 평가되는 코드는 지역 함수의 유효범위 안에서 실행되기 때문에
var로 선언된 변수들이 자동으로 전역 변수가 되지 않는다는 장점이 있다
자동으로 전역 변수가 되지 못하도록 막기 위해 eval() 호출을 즉시실행 함수로 감싸는 방법도 있다

eval과 function생성자 간의 또다른 차이는 eval()은 유효범위 체인에 간섭을 일으킬 수 있지만 Funtion은 좀 더 봉인되어 있다
Function은 어디서 실행 시키든 상관 없이 전역 유효범위를 바라보기 때문에 지역변수를 덜 오염시킨다

(function (){
    var local = 1;
    eval("local - 3; console.log(local)"); //3이 출력 된다
    console.log(local); //3이 출력된다
}());

var local = 1;
(function (){
    var local = 1;
    Function("console.log(typeof local);")();
}());

eval()은 그 자신의 바깥쪽 유효범위에 접근하고 수정을 가할 수 있는 반면,
Function은 그럴 수 없다

parseInt()를 통한 숫자 변환

parseInt()를 사용하면 문자열로부터 숫자 값을 얻을 수 있다
두번째 매개변수로 기수를 받는데 생략하는 경우가 많지만 그래서는 안된다
파싱할 문자열이 0으로 시작할 경우 문제가 생길 수 있다

profile
멋쟁이

0개의 댓글