/javascriptStudy

자바스크립트 학습 내용 정리

Primary LanguageJavaScript

자바스크립트(javascript) 정리


(학습 자료 : 인사이트 자바스크립트(2014년))

2018.10.13 시작

소개

자바스크립트는 웹 브라우저에서 동작하는 스크립트 언어다.

웹이 점점 발전하면서, 웹 아키텍처에 변화가 일어났고 서버에서 담당하던 역할들이 상당 부분 웹 브라우저로 이동했다. 이 중심에는 자바스크립트가 있었고, jQuery가 등장하여 쉽게 DOM을 핸들링하게 되면서 폭발적인 성장을 보이게 된다.

현재는 브라우저 기반의 자바스크립트 리이브러리뿐만 아니라, Node.js와 같은 서버 기반의 환경에서 동작할 수 있는 라이브러리도 쏟아져 나오고 있다. 이제 자바스크립트만으로 클라이언트와 서버 개발을 동시에 할 수 있는 수준에 도달한 것이다.

핵심 개념 요약

앞으로 배우게 될 자바스크립트에서 핵심적인 개념들

  1. 객체

    자바스크립트의 거의 모든 것은 '객체'

    null과 undefined를 제외한 모든 것을 객체로 다룰 수 있다.

  2. 함수

    자바스크립트에서는 함수도 객체

    함수는 '일급 객체'로 다뤄진다.

  3. 프로토타입

    모든 객체는 숨겨진 링크인 프로토타입을 가진다.

    ECMAScript에서는 [[Prototype]]이라고 표현

  4. 실행 컨텍스트

    자바스크립트는 실행 컨텍스트를 만들고 이 안에서 실행이 이루어짐

    이 실행 컨텍스트는 자신만의 유효 범위(Scope)를 가진다.

객체지향 프로그래밍

자바스크립트는 클래스를 지원하지 않지만, 객체지향 프로그래밍이 가능하다. 프로토타입 체인과 클로저로 상속, 캡슐화, 정보 은닉 등의 개념을 소화할 수 있다.

함수형 프로그래밍

자바스크립트는 함수형 프로그래밍이 가능하다.

함수형 프로그래밍이란?

높은 수준의 모듈화를 가능케 하는 매우 효율적인 프로그래밍 방법

주요 특성인 일급 객체로서의 함수 특성과 클로저를 활용한다. (But, 가독성이 떨어질 수 있음)

단점?

자바스크립트는 상당히 유연하고 뛰어난 표현력을 가진 언어지만, 오히려 이러한 특성으로 디버깅에 어려움을 겪는다. 느슨한 타입 체크는 개발자들에게 타입 설정에 대한 자유를 주지만, 컴파일 타임에 잡지 못하는 오류는 모두 런타임 오류로 발견이 된다.

또한 전역 객체의 존재에 대한 논란이 존재한다. 최상위 레벨의 객체들은 모두 전역 객체 안에 위치하기 때문에, 이름 충돌 위험성이 있다.


데이터 타입

  1. 기본 타입
    • 숫자(number)

      자바스크립트는 하나의 숫자형만 존재 (int, float 등 모두 number!)

      64비트 부동 소수점 형태로 저장 (double과 유사하다고 생각하면 된다.)

      var num = 5 / 2;
      
      console.log(num); // 2.5
      console.log(Math.floor(num)); // 2 <정수 부분만 구하고 싶을 때>
      
    • 문자열(string)

      ' '나 " "로 문자열 생성 가능

      한 번 정의된 문자열은 변하지 않는다.

      var str = 'test'; // 문자열 생성
      console.log(str[0], str[1], str[2]); // tes <배열로 문자열 접근 가능>
      
      str[0] = 'T'; // 배열로 변경 시도?
      console.log(str); // test
      

      이처럼 배열로 문자열 변경을 시도해도 변하지 않는다.

    • 불린값(boolean)

      true와 false 값을 나타냄 (원래 우리가 알던 거랑 일치)

    • undefined & null

      두 타입 모두 '값이 비어있음'을 의미

      자바스크립트에서 undefined는 타입이면서, 값을 나타냄

      아무런 값이 할당되지 않았으면? -> undefined

      값이 비었다는 것을 개발자가 알려주기 위해 쓰는 것 -> null

  2. 참조 타입

    기본 타입을 제외한 모든 값은 '객체' (ex. 배열, 함수, 정규표현식 등등)

    객체란?

    단순히 '이름(key) : 값(value)' 형태의 프로퍼티들을 저장하는 컨테이너

객체 생성

객체 생성에는 3가지 방법이 있다.

  1. Object() 객체 생성자 함수 이용(기본 제공)

    var foo = new Object(); // Object()를 이용해 빈 객체 생성
    
    foo.name = 'foo'; // 객체 프로퍼티 생성
    foo.age = 25;
    foo.gender = 'male';
    
    console.log(typeof foo); // object (객체니까!)
    console.log(foo); // { name: 'foo', age:25, gender: 'male'}
    
  2. 객체 리터럴 이용

    객체를 생성하는 표기법을 의미

    var foo = {
        name : 'foo',
        age : 25,
        gender: 'male'
    };
    
    console.log(typeof foo); // object (객체니까!)
    console.log(foo); // { name: 'foo', age:25, gender: 'male'}
    
  3. 생성자 함수 이용

    함수를 통해서 객체 생성 (= 생성자 함수)

객체 프로퍼티

읽기

마침표, 대괄호 표기법으로 가능

console.log(foo.name);
console.log(foo['name']);
갱신

읽기와 같이 가능

foo.name = 'zoo';
foo['name'] = 'zoo';
동적 생성

객체가 생성된 이후에도, 동적으로 프로퍼티를 생성해 추가 가능

foo.major = 'math';
대괄호 표기법만을 사용해야 될 때

프로퍼티가 표현식이나 예약어일 경우

ex. 프로퍼티가 'full-name'이면, '-'로 연산자가 존재하는 표현식이다. 이럴 때는 반드시 대괄호 표기법을 사용

foo['full-name'] = 'foo bar';

마침표를 이용하면, 연산자 - 로 인식해서 NaN이 출력될 위험이 있다.

NaN (Not a Number) : 수치 연산을 해서 정상적인 값을 얻지 못할 때

for in 문

객체를 포함한 모든 프로퍼티에 대해 루프 수행 가능

var foo = {
    name : 'foo',
    age : 25,
    gender: 'male'
};

var prop;
for (prop in foo) {
    console.log(prop, foo[prop]);
}

// 출력
name foo
age 30
gender male
삭제

delete 연산자를 이용해 즉시 삭제 가능

delete foo.name;

delete foo; // 객체 삭제는 불가능

객체는 참조 타입이다

기본 타입을 제외한 배열, 함수 등은 모두 객체로 취급된다고 위에서 말했다. 이는 참조 타입으로 부른다. 객체의 모든 연산이 실제 값이 아닌 참조값으로 처리되기 때문!

var objA = {
    var: 40
};
var objB = objA;

console.log(objA.val); // 40
console.log(objB.val); // 40

objB.val = 50;
console.log(objA.val); // 50
console.log(objB.val); // 50

이 코드의 핵심은, objA 변수는 객체 자체를 저장하고 있는 것이 아니라 생성된 객체를 가리키는 '참조값'을 저장하고 있는 것!!!

objA와 objB는 같은 객체를 참조하고 있기 때문에 둘다 변경되는 모습을 확인할 수 있다.

객체 비교

동등 연산자(==)를 사용해 두 객체 비교 시, 객체의 프로퍼티 값이 아닌 참조값 비교

var objA = { value: 100 };
var objB = { value: 100 };
var objC = objB;

console.log(objA == objB); // false
console.log(objB == objC); // true

값이 모두 100이라 true라고 착각할 수 있다.

objA와 objB는 같은 객체를 참조하고 있지 않기 때문에 false

참조에 의한 함수 호출 방식

  • 기본 타입 : 값에 의한 호출 (Call by value)

    함수 호출 시, 인자로 기본 타입의 값을 넘길 경우 : 호출된 함수의 매개변수로 복사된 값이 전달

    따라서, 함수 내부에서 매개변수를 이용해 값을 변경해도 실제 호출된 변수의 값은 변경 X

  • 참조 타입 : 참조에 의한 호출 (Call by reference)

    함수 호출 시, 인자로 참조 타입의 객체를 전달할 경우 : 인자로 넘긴 객체의 참조값이 그대로 함수 내부로 전달

    따라서 함수 내부에서 참조값을 이용해서 인자로 넘긴 실제 객체의 값을 변경할 수 있는 것

프로토타입

자바스크립트의 모든 객체는 **'자신의 부모 역할을 하는 객체와 연결'**되어 있음

(객체지향의 상속 개념과 같은 것)

이러한 부모 객체를 자바스크립트에서는 '프로토타입'이라고 부른다.

console.dir(foo);

객체 리터럴로 생성한 프로퍼티와 함께 proto 프로퍼티가 존재함

이 프로퍼티가 foo객체의 부모 프로토타입 객체를 가리킴

모든 객체는 자신의 프로토타입을 가리키는 [[Prototype]]이라는 숨겨진 프로퍼티를 가진다.

배열

다른 언어와 달리 배열의 크기를 지정하지 않아도 된다. (굿..)

어떤 위치에 어느 타입의 데이터를 저장하더라도 에러가 발생하지 않는다. (구웃..)

배열 리터럴
var arr = ['a', 'b', 'c'];
console.log(arr[0]); // a

배열 내 인덱스값을 넣어서 접근

배열 요소 생성
var arr = []; // 빈 배열
console.log(arr[0]); // undefined

arr[0] = 1;
arr[2] = 'two';
arr[5] = true;

console.log(arr); // [1, undefined, "two", undefined, undefined, true]
console.log(arr.length); // 6

동적으로 배열 원소 추가 가능

순차적으로 넣을 필요 없이 원하는 인덱스 위치에 동적 추가가 가능하다.

length 프로퍼티
var arr = [0, 1, 2];
console.log(arr.length); // 3

arr.length = 2;
console.log(arr); // [0, 1]

length를 원하는 크기로 늘이거나 줄이면 배열 크기도 이에 맞게 변한다.

push 프로퍼티
var arr = [0, 1, 2];

arr.push(3);
console.log(arr); // [0, 1, 2, 3]

arr.length = 5;
arr.push(10);
console.log(arr); // [0, 1, 2, 3, undefined, 10]

length를 5로 늘리면 arr[4]는 빈 배열이 만들어지고, 그 이후 push를 했기 때문에 arr[5]에 push 값이 들어간다.

배열 프로퍼티 열거

for문을 사용하자

for (var prop in arr) {
    console.log(prop, arr[prop]);
}
// 동적 추가 프로퍼티까지 모두 출력
for ( var i = 0; i < arr.length; i++ ){
    console.log(i, arr[i]);
}
// 배열의 요소만 출력
유사 배열 객체

length를 프로퍼티로 가진 객체

이 객체는 push로 원소 추가 시 에러가 발생한다.

해결법 : apply() 메서드 사용

Array.prototype.push.apply(obj, ['add']);

(/)