반응형

타입은 자바스크립트에서 제공하는 (숫자, 문자열, 불리언, null, undefined, 심벌, 객체) 타입이 있다. 이 때 크게 원시 타입(primitive type)과 객체 타입(object type)으로 구분되는데, 다른 점이 크게 세가지 있다.

  • 원시 타입의 값은 변경 불가능한 값이다. 이에 비해 객체 타입의 값, 즉 객체는 변경 가능한 값이다.
  • 원시 값을 변수에 할당하면 변수(확보된 메모리 공간)에는 실제 값이 저장된다. 이에 비해 객체를 변수에 할당하면 변수(확보된 메모리 공간)에는 참조 값이 저장된다.
  • 원시 값을 갖는 변수를 다른 변수에 할당하면 원본의 원시 값이 복사되어 전달된다. 이를 값에 의한 전달(call by value) 이라 한다. 이에 비해 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어 전달된다. 이를 참조에 의한 전달(call by reference)이라 한다.

원시 값

변경 불가능한 값

원시 타입의 값은 변경 불가능하기에, 한번 생성된 원시 값은 읽기 전용 값으로써 변경할 수 없다.

변수는 하나의 값을 저장하기 위해 확보한 메모리 공간 자체이고, 값은 변수에 저장된 데이터로서 표현식이 평가되어 생성된 결과를 말한다. 변경 불가능하다는 것은 변수가 아니라 값에 대한 진술이다.

즉 “원시 값은 변경 불가능하다”는 말은 원시 값 자체를 변경할 수 없는 것이지 변수 값을 변경할 수 없다는 것이 아니다. 변수는 언제든지 재할당을 통해 변수 값을 변경할 수 있다.

//상수 o에 값 할당을 다시 못할 뿐, o에 최초할당 된 객체인 o의 프로퍼티는 변경할 수 있다.
const o = {};

o.a = 1;
console.log(o); // {a: 1}

변수에 값 할당이 여러번 이루어질 때 메모리는 말 그대로 재할당이기 때문에 메모리 공간에 특정 값을 등록 후 해당 위치로 변수가 바라보는 주소값을 변경하는 것이다.

let a = 1;
a = 3;

//값이 변경되는 것이 아닌, 값을 재할당

문자열과 불변성

자바스크립트의 문자열은 원시타입으로써 변경 불가능하지만 위와 동일하게 다른 주소를 할당하는 방식으로 변수에 재할당이 가능하다

값에 의한 전달

var score = 80;
var copy = score;

console.log(score); //80
console.log(copy); //80
//score와 copy가 보고있는 80은 서로 다른 메모리주소

score = 100;

console.log(score); //100
console.log(copy); //80

원시값에 대해서는 값을 기존의 값을 복사해서 전달하는 call by value가 일어난다.

객체

객체는 프로퍼티의 개수가 정해져 있지 않으며 동적으로 추가, 삭제가 가능하다.
따라서 객체는 원시 값과 같이 확보해야 할 메모리 공간의 크기를 사전에 정할 수 없다.

프로토타입 객체지향언어 자바스크립트와 클래스 기반 객체지향언어

클래스 기반 객체지향언어는 클래스 내에 이미 생성된 프로퍼티와 메서드가 정해져 있으며, 객체가 생성된 이후에는 프로퍼티를 삭제하거나 추가할 수 없다.

자바스크립트는 클래스 없이 객체 생성이 가능하며, 동적으로 프로퍼티와 메서드를 추가할 수 있다.
하지만, 편한 만큼 클래스 기반 언어보다 객체의 생성과 프로퍼티 접근에 비용이 더 많이든다.

변경 가능한 값

객체 값은 변경이 가능한 값(mutable value)이다.

var person = {
    name: 'Lee'
};

var sang = person;

sang.name = 'ss';

console.log(sang.name);
console.log(person.name);

객체는 원시 값이 값의 주소를 갖고있는 것과 다르게, 참조 값에 접근할 수 있다. 참조 값은 생성된 객체가 저장된 메모리 공간의 주소 그 자체다.

때문에 위의 코드처럼 sang, person이 같은 주소인 0x00000001 을 바라보고 있으며 값이 동시에 변경된다.

이를 얕은복사 라고 하며, 참조에 의한 전달이 된다

반응형
반응형

객체란?

자바스크립트는 원시 값을 제외한 나머지 값(함수, 배열, 정규 표현식 등)은 모두 객체

원시 타입은 단 하나의 값만 나타내고, 객체 타입은 다양한 타입의 값을 하나의 단위로 구성한 복합적인 자료구조다.
또 원시 값은 변경 불가능한 값이지만, 객체는 변경 가능한 값이다.

객체는 0개 이상의 프로퍼티로 구성된 집합이고, 키(key)와 값(value)으로 구성되어 있다.

var person = {
    name: 'Lee', //- 프로퍼티
    age: 20 // age : 키, 20 : 값
}

자바스크립트의 함수는 프로퍼티의 값으로 사용할 수 있다. 프로퍼티 값이 함수일 경우, 일반 함수와 구분하기 위해 메서드라고 부른다.

var counter = {
    num: 0,
    increase: function () {
        this.num++;
    }
};
  • 프로퍼티 : 객체의 상태를 나타내는 값
  • 메서드: 프로퍼티를 참조하고 조작할 수 있는 동작

객체 리터럴에 의한 객체 생성

자바스크립트는 프로토타입 기반 객체지향 언어로서 클래스 기반 객체지향 언어와는 달리 다양한 객체 생성 방법을 지원한다.

  • 객체 리터럴
  • Object 생성자 함수
  • 생성자 함수
  • Object.create메서드
  • 클래스(ES6)

이러한 객체 생성 방법 중에서 가장 일반적이고 간단한 방법은 객체 리터럴을 사용하는 방법이다.

객체 리터럴은 중괄호 내에 0개 이상의 프로퍼티를 정의한다. 변수에 할당되는 시점에 자바스크립트 엔진은 객체 리터럴을 해석해 객체를 생성한다.

var person = {
    name: 'Lee';
    sayHello: function() {
        console.log('Hello! My name is $(this.name}.');
    }
};

console.log(typeof person); // object
console.log(person); // {name: "Lee", sayHello: f}

var empty = {};
if(empty){

}
//if문의 코드블록에는 세미콜론 x

객체 리터럴의 중괄호는 코드 블록을 의미하지 않는다는 데 주의.
코드 블록의 닫는 중괄호 뒤에는 세미콜론을 붙이지 않고, 객체 리터럴의 닫는 중괄호 뒤에는 세미콜론을 붙인다.

프로퍼티

객체는 프로퍼티의 집합이며, 프로퍼티는 키와 값으로 구성된다.

var person = {
    name: 'Lee',
    age: 20
};

프로퍼티를 나열할 때는 쉼표(,)로 구분한다. 일반적으로 마지막 프로퍼티 뒤에는 쉼표를 사용하지 않지만, 사용해도 문제되지 않는다.

프로퍼티 키와 프로퍼티 값으로 사용할 수 있는 값은 다음과 같다.

  • 프로퍼티 키: 빈 문자열을 포함하는 모든 문자열 또는 심벌 값
  • 프로퍼티 값: 자바스크립트에서 사용할 수 있는 모든 값

이 때 네이밍 규칙을 따라야 프로퍼티 키값에 따옴표를 생략할 수 있다.

var person = {
    firstName: 'Ung-mo', // 식별자 네이밍 규칙을 준수하는 프로퍼티 키
    'last-name': 'Lee' // 식별자 네이밍 규칙을 준수하지 않는 프로퍼티 키
}

console.log(person); // {firstName: "Ung-mo", last-name: "Lee"}

메서드

자바스크립트에서 사용할 수 있는 모든 값은 프로퍼티 값으로 사용할 수 있다, 그렇기 때문에 자바스크립트의 함수도 프로퍼티 값으로 사용할 수 있다.

프로퍼티 값이 함수일 경우 일반 함수와 구분하기 위해 메서드라 부른다.

var circle = {
    radius: 5, // 프로퍼티

    // 원의 지름
    getDiameter: function () { // 메서드
        return 2 * this.radius; // this는 circle을 가리킨다.
    }
};

console.log(circle.getDiameter()); // 10

프로퍼티 접근

프로퍼티에 접근하는 방법은 다음과 같이 두 가지다.

  • 마침표 프로퍼티 접근 연산자를 사용하는 마침표 표기법
  • 대괄호 프로퍼티 접근 연산자를 사용하는 대괄호 표기법

프로퍼티 키가 식별자 네이밍 규칙을 준수하는 이름, 즉 자바스크립트에서 사용 가능한 유효한 이름이면 마침표 표기법과 대괄호 표기법을 모두 사용할 수 있다.

var person = {
    name: 'Lee'
};

console.log(person.name); // Lee

console.log(person['name']); // Lee

대괄호 프로퍼티 접근 연산자 내부에 지정하는 프로퍼티 키는 반드시 따옴표로 감싼 문자열이 되어야 한다.

문제 예시

var person = {
    name: 'Lee'
};

console.log(person[name]); // ReferenceError: name is not defined

객체에 존재하지 않는 프로퍼티에 접근하면 undefined를 반환한다. 이때 ReferenceError가 발생하지 않는데 주의하자.

프로퍼티 값 갱신

이미 존재하는 프로퍼티에 값을 할당하면 프로퍼티 값이 갱신

var person = {
    name: 'Lee'
}

person.name = 'Kim';

console.log(person); // {name: "Kim"}

프로퍼티 동적 생성

존재하지 않는 프로퍼티에 값을 할당하면 프로퍼티가 동적으로 생성되어 추가되고 프로퍼티 값이 할당된다.

var person = {
    name: 'Lee'
};

person.age = 20;

console.log(person); // {name: "Lee", age: 20}

프로퍼티 삭제

delete 연산자는 객체의 프로퍼티를 삭제한다. 이때 delete 연산자의 피연산자는 프로퍼티 값에 접근할 수 있는 표현식이어야 한다. 만약 존재하지 않는 프로퍼티를 삭제하면 아무런 에러 없이 무시된다.

var person = {
    name: 'Lee'
};

person.age = 20; // 프로퍼티 동적 생성

delete person.age;

delete person.address; // 없는 프로퍼티를 삭제해도 에러반환 x

console.log(person);

ES6에서 추가된 객체 리터럴의 확장 기능

ES6에서는 더욱 간편하고 표현력 있는 객체 리터럴의 확장 기능을 제공한다.

프로퍼티 축약 표현

객체 리터럴의 프로퍼티는 키, 값으로 구성된다.

//ES5
var x = 1, y = 2;

var obj = {
    x: x,
    y: y
}

console.log(obj); // {x: 1, y: 2}

ES6에서는 프로퍼티 값으로 변수를 사용하는 경우 변수 이름과 프로퍼티 키가 동일한 이름일 때 프로퍼티 키를 생략할 수 있다. 이때 프로퍼티 키는 변수 이름으로 자동 생성된다.

//ES6
let x = 1, y = 2;

const obj = { x, y };

console.log(obj); // { x: 1, y: 2 }

계산된 프로퍼티 이름

문자열 또는 문자열로 타입 변환할 수 있는 값으로 평가되는 표현식을 사용해 프로퍼티 키를 동적으로 생성할 수도 있다. 단, 키를 대괄호로 묶어야 한다.

//ES5
var prefix = 'prop';
var i = 0;

var obj = {};

// 계산된 프로퍼티 이름으로 프로퍼티 키 동적 생성
obj[prefix + '-' + ++i] = i;
obj[prefix + '-' + ++i] = i;
obj[prefix + '-' + ++i] = i;

console.log(obj); // {prop-1: 1, prop-2: 2, prop-3: 3}

ES6에서는 객체 리터럴 내부에서도 계산된 프로퍼티 이름으로 프로퍼티 키를 동적 생성할 수 있다.

//ES6
const prefix = 'prop';
let i = 0;

// 리터럴 내부에서 계산된 프로퍼티 이름으로 프로퍼티 키를 동적 생성
const obj = {
    [`${prefix}-${++i}`]: i,
    [`${prefix}-${++i}`]: i,
    [`${prefix}-${++i}`]: i
};

console.log(obj); // {prop-1: 1, prop-2: 2, prop-3: 3}

메서드 축약 표현

ES5는 프로퍼티 값으로 메서드를 정의, ES6에서는 메서드 정의할 때 function 키워드 생략 가능

//ES5
var obj = {
    name: 'Lee',
    sayHi: function() {
        console.log('Hi! ' + this.name);
    }
};

//ES6
const obj = {
    name: 'Lee',
    // 메서드 축약 표현
    sayHi() {
        console.log('Hi! ' + this.name);
    }
};

obj.sayHi(); // Hi! Lee
반응형
반응형

타입 변환이란?

자바스크립트의 모든 값은 타입이 있다.

개발자가 의도적으로 값의 타입을 변환하는 것을 명시적 타입 변환 또는 타입 캐스팅 이라 한다.

var x = 10;

var str = x.toString();
console.log(typeof x, x); // string 10

개발자의 의도와는 상관없이 암묵적으로 타입이 자동 변환되기도 한다. 이를 암묵적 타입 변환 또는 타입 강제 변환 이라한다.

var x = 10;

var str = x + '';
console.log(typeof str, str); // string 10

타입 변환이 기존 원시 값을 직접 변경하는 것은 아니다. 원시 값은 변경 불가능한 값이므로 변경할 수 없다. 타입 변환이란 기존 원시 값을 사용해 다른 타입의 새로운 원시 값을 생성하는 것이다.

이 타입변환을 모던하게 사용하려면, 개발자가 의도했다는 명확한 표현력이 적은 암묵적 타입 변환보다는, 의도를 명확하게 담은 명시적 타입 변환을 사용하는게 좋다.

암묵적 타입 변환

코드의 문맥을 고려해 암묵적으로 데이터 타입을 강제 변환하는 경우를 살펴보자.

문자열 타입으로 변환

1 + '2' // "12"

+연산은 문자열이 피연산자중 하나라도 있을 경우 문자열로 연결된다.

숫자 타입으로 변환

1 - '1' // 0
1 * '10' // 10
1 / 'one' // NaN

산술 연산자를 활용하면 문자를 숫자로 읽어들인다. ‘one’같은 경우는 숫자로 변환하지 못하기에 NaN을 출력

불리언 타입으로 변환

조건식의 경우도 암묵적 타입변환

if('') console.log('1');
if(true) console.log('2');
if(0) console.log('3');
if('str') console.log('4');
if(null) console.log('5');

// 2 4

false로 형변환 되는 값

  • false
  • undefined
  • null
  • 0, -0
  • NaN
  • ‘’(빈 문자열)

명시적 타입 변환

개발자의 의도에 따라 명시적으로 타입을 변경하는 법

  • 표준 빌트인 생성자 함수
  • 빌트인 메서드
  • 암묵적 타입 변환

문자열 타입으로 변환

  • String 생성자 함수를 new 연산자 없이 호출
  • Object.prototype.toString 메서드
  • 문자열 연결 연산자 이용
String(1);
(1).toString();
1 + '';

숫자 타입으로 변환

  • Number 생성자 함수를 new 연산자 없이 호출
  • parseInt, parseFloat 함수를 사용
    • 단항 산술 연산자를 이용
    • 산술 연산자를 이용
Number('0');
parseInt('0');
'0'*1;

불리언 타입으로 변환

  • Boolean 생성자 함수를 new 연산자 없이 호출
  • ! 부정 논리 연산자를 두번 사용
Boolean('x');
!!'x';

단축 평가

논리합과 논리곱은 논리 연산의 결과를 결정하는 피연산자를 타입 변환하지 않고 그대로 반환한다. 이를 단축 평가라 한다. 단축 평가는 표현식을 평가하는 도중에 평가 결과가 확정된 경우 나머지 평가 과정을 생략하는 것을 말한다.

논리합(||) 논리곱(&&) 연산자 표현식의 평가 결과는 불리언 값이 아닐 수 있다.

'Cat' && 'Dog' // -> "Dog"

논리곱(&&) 연산자는 두 개의 피연산자가 모두 true로 평가될 때 true를 반환한다.

'Cat' || 'Dog' // -> "Cat"

논리합(||) 둘 중 하나만 true여도 true를 반환하기에 Cat부터 True이기 때문에 Cat을 반환

반응형
반응형

자바스크립트 - 데이터 타입

자바스크립트의 모든 값은 데이터 타입을 갖는다.
자바스크립트(ES6)는 7개의 데이터 타입을 제공한다.(ES11에서는 BigInt까지 추가)

7개의 데이터 타입을 제공하는데, 원시 타입과 객체 타입으로 분류된다.

  • 원시 타입
    • 숫자 타입 - number
      • 정수와 실수 구분 없이 하나의 숫자 타입만 존재
    • 문자열 타입 - string
      • 문자열
    • 불리언 타입 - boolean
      • 논리적 참, 거짓
    • undefined 타입
      • var 키워드로 선언된 변수에 암묵적으로 할당되는 값
    • null 타입
      • 값이 없다는 것을 의도적으로 명시할 때 사용하는 값
    • 심벌 타입 - symbol
      • ES6에서 추가된 7번째 타입
  • 객체 타입
    • 객체, 함수, 배열 등

숫자 타입의 값 1과 문자열 타입의 값 ‘1’은 서로 다른 값이다. 사용하는 목적에 따라 다른 타입에 대해서 알아보자.


숫자 타입

C나 자바의 경우, 정수와 실수를 구분해서 int, long, float, double 등과 같은 다양한 숫자 타입을 제공한다. 하지만 자바스크립트는 독특하게 하나의 숫자 타입만 존재한다.

ECMAScript 사양에 다르면 숫자 타입의 값은 배정밀도 64비트 부동소수점 형식을 따른다. 즉 모든 수를 실수로 처리하며 정수만 표현하기 위한 데이터 타입이 별도로 존재하지 않는다.

var binary = 0b01000001;
var octal = 0o101;
var hex = 0x41;

// 표기법만 다를 뿐 모두 같은 값이다.
console.log(binary); // 65
console.log(octal); // 65
console.log(hex); // 65
console.log(binary === octal); // true
console.log(octal === hex); // true

숫자 타입의 특별한 값 표현

  • Infinity : 양의 무한대
  • -Infinity : 음의 무한대
  • NaN : 산술 연산 불가(not-a-number)

문자열 타입

문자열 타입은 텍스트 데이터를 나타내는 데 사용한다. 문자열은 0개 이상의 16비트 유니코드(UTF-16) 문자의 집합으로 전 세계 대부분의 문자를 표현할 수 있다.

C는 문자열 타입을 제공하지 않고 문자의 배열로 문자열을 표현하고, 자바는 문자열을 객체로 표현한다. 자바스크립트는 문자열을 원시 타입으로 표현하고 이는 변경이 불가능한 값이다.

템플릿 리터럴

ES6부터 템플릿 리터럴이라고 하는 새로운 문자열 표기법이 도입되었다.

  • 멀티라인 문자열
  • 표현식 삽입
  • 태그드 템플릿

등 편리한 문자열 처리 기능을 제공한다.

멀티라인 문자열

백틱(`)을 사용한 문자열 리터럴이다.

일반 문자열 내에서는 줄바꿈(개행)이 허용되지 않는다. 따라서 일반 문자열 내에서 줄바꿈 등의 공백을 표현하려면 ()이스케이프 시퀀스를 사용해야 한다.
하지만 템플릿 리터럴 내에서는 이스케이프 시퀀스를 사용하지 않고도 줄바꿈이 허용되며, 모든 공백도 있는 그대로 적용된다.

var template = `<ul>
    <li><a href="#">Home</a></li>
<ul>`;

표현식 삽입

문자열은 피연산자 중 하나 이상이 문자열인 경우 문자열 연산자 +를 사용하면 연결된다.

불리언 타입

논리적 참, 거짓을 나타내는 true, false 뿐이다.

undefined 타입

undefined 타입의 값은 undefined가 유일하다.

변수 선언에 의해 확보된 메모리 공간을 자바스크립트 엔진에서 최초에 undefined로 초기화해둔다. 이후 값을 할당하지 않은 변수를 참조하면 undefined가 반환된다.

var foo;
console.log(foo); // undefined

undefined가 발견된다면 초기화되지 않은 변수인 것을 인지할 수 있다.

null 타입

프로그래밍 언어에서 null은 변수에 값이 없다는 것을 의도적으로 명시할 때 사용하며 두 가지 의미가 있다.

  • 변수에 null 할당 시 변수가 이전에 참조하던 값을 더 이상 참조하지 않겠다는 의미

    • 이전에 할당되어 있던 값에 대한 참조를 명시적으로 제거하며 제거된 주소에 있는데이터는 가비지 콜렉션이 수행됨
  • 유효한 값을 반환할 수 없는 경우 명시적으로 null을 반환

    • ex)

      var element = document.querySelector('.myClass');
      => myClass가 없다면 null값을 반환
      
      console.log(element); // null

심벌 타입

심벌 타입은 변경 불가능한 원시 타입의 값으로 다른 값과 중복되지 않는 유일무이한 값이다.

var key = Symbol('key')
console.log(typeof key); //symbol

객체 타입

자바스크립트는 객체 기반의 언어이며, 자바스크립트를 이루고 있는 거의 모든 것이 객체라는 것이다.

즉 위에서 언급한 원시타입 6가지를 제외하고는 모두 객체 타입이다.

데이터 타입의 필요성

데이터 타입에 의한 메모리 공간의 확보와 참조

값을 메모리에 저장할 때 메모리 공간을 미리 확보해야 하는데, 몇 바이트의 메모리 공간을 사용해야 낭비와 손실 없이 값을 저장할 수 있는지 알아야 한다. 이 때 데이터 타입이 주요하게 활용된다.

var score = 100;

위의 코드가 실행되었을 때의 자바스크립트 엔진 메모리 동작

  • 리터럴 100을 숫자 타입의 값으로 해석 → 숫자 타입의 값 100을 저장하기 위해 8바이트의 메모리 공간을 확보 → 100을 2진수로 저장한다.
  • 자바스크립트는 64비트 부동소수점 형식을 사용해 숫자 타입을 메모리에 저장

데이터 타입에 의한 값의 해석

메모리에 01000001 의 이진수는 해석하기에 따라 65가 되거나 ‘A’가 될 수 있다. 이렇게 메모리에 저장된 값만으로는 해당 값이 문자인지 숫자인지 판단을 할 수가 없기에 데이터 타입을 활용해서 값의 종류를 말한다.

  • 값을 저장할 때 확보해야 하는 메모리 공간의 크기를 결정하기 위해
  • 값을 참조할 때 한 번에 읽어 들여야 할 메모리 공간의 크기를 결정하기 위해
  • 메모리에서 읽어 들인 2진수를 어떻게 해석할지 결정하기 위해

동적 타이핑

동적 타입 언어와 정적 타입 언어

C나 자바같은 정적 타입 언어는 변수를 선언할 때 변수에 할당할 수 있는 값의 종류, 즉 데이터 타입을 사전에 선언해야 한다. 이를 명시적 타입 선언 이라 한다. ex) int num, Map map

정적 타입 언어는 컴파일 시점에 타입 체크를 수행한다. 타입 체크를 통과하지 못했다면 에러를 발생시키고 프로그램의 실행 자체를 막는다. 이러한 컴파일 시점 체크로 런타임에 발생하는 에러를 줄인다.

자바스크립트는 정적 타입 언어와 다르게 변수를 선언할 때 타입을 선언하지 않고 var, let, const 키워드를 사용해 변수를 선언할 뿐이다. 자바스크립트의 변수는 자바 스크립트에서는 값을 할당하는 시점에 변수의 타입이 동적으로 결정되고 변수의 타입을 변경할 수 있다.

자바스크립트의 변수는 선언이 아닌 할당에 의해 타입이 결정(타입 추론)된다. 그리고 재할당에 의해 변수의 타입은 언제든지 동적으로 변할 수 있다. 이러한 특징을 동적 타이핑 이라 하며 이러한 특징을 가진 자바스크립트를 동적 타입 언어라고 한다.

동적 타입 언어와 변수

동적 타입 언어는 변수에 어떤 데이터 타입의 값이라도 자유롭게 할당이 가능하기에 편리하지만, 위험하기도 하다.

모든 소프트웨어 아키텍처에는 트레이드오프가 존재하며 동적 타입 언어도 예외가 아니다.

  • 동적 타입 언어의 구조적 문제
    • 변수 값은 언제든지 변경될 수 있기 때문에 복잡한 프로그램에서는 변화하는 변수 값을 추적하기 어려울 수 있다.
    • 변수의 타입의 값의 변경에 의해 타입도 변경될 수 있다.
      • 자바스크립트는 개발자의 의도와는 상관없이 엔진에 의해 암묵적으로 타입이 자동변환되기도 한다.

즉 동적 타입 언어는 유연성은 높지만 신뢰성은 떨어진다.

  • 변수를 사용할 때 주의할 사항
    • 변수는 꼭 필요한 경우에 한해 제한적으로 사용한다.
    • 변수의 유효 범위(스코프)는 최대한 좁게 만들어 변수의 부작용을 억제해야 한다.
    • 어디서든 참조/변경이 가능한 전역 변수는 최대한 사용하지 않도록 한다.
    • 변수보다는 상수를 사용해 값의 변경을 억제한다.
    • 변수 이름은 변수의 목적이나 의미를 파악할 수 있도록 네이밍한다.

코드는 오해하지 않도록 작성해야 한다. 코드는 개발자를 위한 문서이기도 하다.

사람이 이해할 수 있는 코드, 즉 가독성이 좋은 코드가 좋은 코드다.

반응형
반응형

컴퓨터 공학 전반에서 사용하는 값, 표현식, 문에 대해서 알아보자


은 식(표현식expression)이 평가(evaluate)되어 생성된 결과를 말한다.

평가란 식을 해석해서 값을 생성하거나 참조하는 것을 의미한다.

10과 20을 더해 평가 -> 30 : 값
10 + 20; // 식

모든 값은 데이터 타입을 가지며 메모리에 2진수로 저장된다. 메모리에 저장된 값은 데이터 타입에 따라 다르게 해석될 수 있다. 예를 들어 0100 0001을 숫자로 해석하면 65지만 문자로 해석하면 ‘A’다

변수는 하나의 값을 저장하기 위해 확보한 메모리 공간을 식별하기 위해 붙인 이름이기에 변수에 할당되는 것은 이다


리터럴

리터럴은 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용해 값을 생성하는 표기법을 말한다.
리터럴은 사람이 이해할 수 있는 아라비아 숫자를 사용해 숫자 리터럴 3을 코드에 입력하면 이를 평가해 숫자 값 3을 생성해 메모리에 적재된다
리터럴은 사람이 이해할 수 있는 문자 또는 미리 약속된 기호(’’, “”, [], // 등)로 표기한 코드이다.
자바스크립트 엔진에서는 이러한 리터럴을 런타임 시점에 평가해 값을 생성한다.

리터럴 예시

리터럴 예시
정수 리터럴 100
2진수 리터럴 0b010000001
8진수 리터럴 0o101
16진수 리터럴 0x41
문자열 리터럴 ‘Hello’, “World”

표현식

표현식(expression)은 값으로 평가될 수 있는 문(statement)이다. 즉, 표현식이 평가되면 새로운 값을 생성하거나 기존 값을 참조한다.

앞서 살펴본 리터럴은 값으로 평가된다. 따라서 리터럴도 표현식이다.

즉 값으로 평가될 수 있는 문은 모두 표현식이다.


문과 표현식을 구별하고 해석할 수 있다면 자바스크립트 엔진의 입장에서 코드를 읽고 실행 결과를 예측하는 데 도움이 된다.

문(statement)은 프로그램을 구성하는 기본 단위이자 최소 실행 단위다. 문의 집합으로 이뤄진 것이 바로 프로그램이며, 문을 작성하고 순서에 맞게 나열하는 것이 프로그래밍이다.

또 문은 여러 토큰이 모여서 구성되는데 토큰이란 문법적인 의미를 가지며, 문법적으로 더 이상 나눌 수 없는 코드의 기본 요소를 의미한다.

var sum = 1 + 2;
 t   t  t t t tt

t : 토큰
위와 같이 모든 요소의 단위

세미콜론과 세미콜론 자동 삽입 기능

세미콜론(;)은 문의 종료를 나타낸다. 즉 자바스크립트 엔진은 세미콜론으로 문이 종료한 위치를 파악하고 순차적으로 하나씩 문을 실행한다.

세미콜론이 필요없는 문법이 있는데, if문, for문 등은 {} 와 같은 코드블록을 사용한다. 문의 종료를 의미하는 자체 종결성을 갖기 때문에 사용하지 세미콜론을 사용하지 않는다.

반응형

'공부 > 자바스크립트' 카테고리의 다른 글

자바스크립트 - 타입 변환과 단축 평가  (0) 2024.10.07
자바스크립트 - 데이터 타입  (0) 2024.09.04
자바스크립트 - 변수  (0) 2024.08.11
자바스크립트 실행 환경  (0) 2024.07.22
자바스크립트란?  (0) 2024.07.12
반응형

변수

변수하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름을 말한다.

식별자

변수를 식별자라고도 부른다, 식별자는 어떤 값을 구별해서 식별할 수 있는 고유한 이름을 말한다.

식별자는 값이 아니라 메모리 주소를 기억하고 있다.

var result = 10 + 20;

위의 코드 동작을 실행했을 때 result는 10 + 20이 저장되어있는 메모리의 주소(0x0000ffff 예시)를 알고있다.

즉 메모리 주소에 붙인 이름을 식별자라고 할 수 있다.

식별자라는 용어는 변수 이름에만 국한해서 사용하지 않고, 변수, 함수, 클래스 등은 모두 식별자라고 부를 수 있다.

메모리 상에 존재하는 어떤 값을 식별할 수 있는 이름은 모두 식별자라고 부른다.

자바스크립트에서 10 + 20을 어떻게 계산하는가?

자바스크립트 엔진이 10+20의 값을 계산하기 위한 동작과정

    • 연산을 수행하기 위해 먼저 + 연산자의 좌변과 우변의 숫자 값, 즉 피연산자를 기억
  • CPU를 활용해 연산하고 메모리를 통해 데이터를 기억
    • 메모리는 데이터를 저장할 수 있는 메모리 셀의 집합체다.
    • 메모리 셀 하나의 크기는 1바이트 즉 1바이트 단위로 데이터를 저장하거나 읽어들인다
  • 각 셀은 0xFFFFFFFF 등과 같은 메모리 주소를 가지며, 메모리 공간의 위치를 나타낸다.
    • 0x00000000 ~ 0xFFFFFFFF
  • 위 예제의 숫자 값 10과 20은 메모리 상의 임의의 위치(메모리 주소)에 기억되고 CPU는 이 값을 읽어들여 연산을 수행한다. 연산 결과로 생성된 숫자 값 30도 메모리 상의 임의의 위치에 저장한다.

ex ) a = 10, b = 20, a + b = 30

각각 임의로 a = 0x0000ffff, b = 0x0000fffc 의 주소가 있다고 했을 때
a + b 의 코드가 실행되면 cpu에서 a의 주소, b의 주소를 참조하여 계산 후 임의의 주소 어딘가에
10 + 20의 결과값 30을 넣어둔다. 이 때 30을 변수에 저장한다면 메모리에서 저장해둔 채로 둘 수 있고,
변수에 저장하지 않는다면 1회성으로 사용 후 찾기 어렵다.

 


변수 선언

변수 선언을 하면, 하드웨어 에서는 값을 저장하기 위한 메모리 공간을 확보하고, 변수 이름과 확보된 메모리 공간의 주소를 연결시켜둔다.

변수를 선언할 때는 var, let, const 키워드를 사용한다 ES6에서 let, const 키워드가 도입되기 이전까지 var 키워드는 자바 스크립트에서 사용할 수 있는 유일한 키워드였다.

Var 키워드의 단점

  • 변수의 스코프 문제
  • 호이스팅(hoisting)
  • 중복 선언 허용

변수 단원이기에 세가지 큰 문제중 하나를 다루자면, 변수의 스코프 문제가 있다.

ES6에서 let과 const 키워드가 도입된 이유

var 키워드는 블록 레벨 스코프를 지원하지 않고 함수 레벨 스코프를 지원하는 것으로 의도치 않게 전역 변수가 선언되어 자주 부작용이 발생했다.

ES6에서 let과 const가 나왔지만 var가 사라지지는 않았는데, 이 이유는 이미 구현된 ES6 이전의 js코드들은 모두 var로 선언되었기 때문에 호환성 등을 위해 남겨두고 폐기시키지 않았다. 하지만 위의 설명과 같은 이유로 권장하지 않기에 사용을 지양

변수 선언과 메모리 관계

변수를 최초 선언 시에는 메모리주소를 정하고 공간을 확보했을 때 따로 넣는 값이 없다면 자바스크립트 에서는 undefined의 값이 해당 메모리 공간에 들어가 있다.

때문에 자바스크립트 엔진에서는 변수 선언을 2단계에 거쳐 수행한다.

  • 선언 단계 : 변수 이름을 등록해서 자바스크립트 엔진에 변수의 존재를 알린다.
  • 초기화 단계 : 값을 저장하기 위한 메모리 공간을 확보하고 암묵적으로 undefined를 할당해 초기화한다.

초기화 단계의 중요성

초기화 단계를 통해 undefined를 할당해 초기화 하는 이유는 초기화 단계를 거치지 않았을 때 확보된 메모리 공간에 이전에 사용했던 값이 남아있을 수 있기 때문.

할당 된 변수 이름들은 자바스크립트 실행 컨텍스트에 등록된다.

실행 컨텍스트

실행 컨텍스트는 자바스크립트 엔진이 소스코드를 평가하고 실행하기 위해 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역으로 실행 컨텍스트를 통해 식별자와 스코프를 관리한다.


변수 선언의 실행 시점과 변수 호이스팅

console.log(score);

var score; // 변수 선언

위의 코드를 실행하면 선언 시점이 score를 사용하는 console.log보다 늦었기에 참조 에러ReferenceError가 발생할 것처럼 보이는데, 자바스크립트에서는 undefined가 출력된다.

  • 변수 선언이 소스코드가 한 줄씩 순차적으로 실행되는 시점, 런타임 시점이 아니라 그 이전 단계에서 먼저 실행되기 때문이다.

자바스크립트 엔진은 소스코드 실행을 위한 준비 단계인 소스코드의 평가 과정에서 모든 선언문(변수 선언문, 함수 선언문 등)을 소스코드에서 찾아내 먼저 실행한다. 평가 과정 이후 변수 선언을 포함한 모든 선언문을 제외하고 소스코드를 한 줄씩 순차적으로 실행한다.

즉 자바스크립트 엔진은 변수 선언이 소스코드의 어디에 있던지 다른 코드보다 먼저 실행된다. 따라서 변수 선언이 소스코드의 어디에 위치하는지와 상관없이 어디서든지 변수를 참조할 수 있다.

이처럼 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징을 호이스팅(variable hoisting)이라 한다.


값의 할당

변수에 값을 할당(대입, 저장)할 때는 할당 연산자(=)를 사용한다.

var score = 80;

이 때 호이스팅 관련해서 주의할 점이 변수 선언 까지만 호이스팅 되고, 값의 할당은 실제 스크립트를 한줄씩 읽는 런타임 때 할당된다.

console.log(score); // undefined

var score; // 변수 선언
score = 80; // 변수 할당

var score = 80; // 변수 선언 및 할당

console.log(score); // 80

위의 예제에서 두 소스코드 모두 동일하게 undefined, 80으로 결과값이 같다.

  • 메모리 관점
    • 변수 선언과, 값의 할당은 서로 다른 메모리에 저장
    • 즉 score 식별자는 메모리 공간에 할당된 주소만 볼 뿐

console.log(score); // undefined

score = 80;
var score;

console.log(score); // 80

상수

값을 재할당 하지 못하게 하는 것

var score = 80; //변수 선언과 값의 할당
score = 90; //값의 재할당

엄밀하게 말하면 score = 80;의 시점부터 재할당이 된 것이다.
때문에 자바스크립트에서의 상수는 명확하게 말하면 한번 정해지면 변하지 않게 하는 값

ES6에서는 const 키워드를 사용해 상수 선언을 할 수 있다.

출처 : 모던 자바 스크립트 Deep Dive

반응형
반응형

자바스크립트 실행 환경

모든 브라우저와 Node.js에서 ECMAScript를 실행할 수 있다.
하지만 ECMAScript 외의 기능들은 호환되지 않는다.

예) 브라우저에서 활용하는 자바스크립트 DOM API

// ECMAScript 코드
const button = document.getElementById('myButton'); // DOM API 사용

// ECMAScript 함수 정의
button.addEventListener('click', () => { // DOM API 사용
  alert('Button clicked!'); // ECMAScript 내장 함수 사용
});

Node.js가 DOM API를 활용하지 않는 이유는 Node.js역할과 관련있다.
Node.js는 브라우저 외부 환경에서 동작하는 백단의 구현을 위한 실행 환경 이기에 Core 언어로 제공하지 않으며, 필요한 경우 라이브러리를 사용해서 HTML문서를 가공할 수 있다.

백단에서 사용하는 우리가 아는 언어들은 모두 파일 시스템을 기본적으로 제공하는 것처럼 Node.js환경에서는 이를 동일하게 제공한다(Javascript범주). 하지만, 브라우저에서는 이런 파일 시스템을 기본 제공하지 않는다.(FileReader로 읽기동작은 가능)

제공하지 않는 이유 : 브라우저에서 동작하는 자바스크립트가 사용자의 파일을 임의로 다룰 수 있다면 사용자의 파일을 보안 공격으로 쉽게 공격할 수 있음

위에서 이야기한 내용을 정리하면

  • 브라우저
    • ECMAScript
    • DOM
    • BOM
    • Canvas
    • XMLHttpRequest
    • fetch
    • ….
  • Node.js
    • ECMAScript
    • 클라이언트 사이드 API(DOM …)를 미지원


Node.js와 NPM

  • Node.js : 크롬 V8 자바스크립트 엔진으로 빌드된 자바스크립트 런타임 환경
    ⇒ 서버 사이드 개발이 가능
  • NPM(Node Package Manager) : 자바스크립트 패키지 매니저로 Node.js에서 사용할 수 있는 모듈을 패키지화해서 모아둔 저장소 역할, 패키지 설치 및 관리를 위한 CLI를 제공
반응형
반응형

자바스크립트의 표준화

자바스크립트가 나온 초창기에는 자사 브라우저의 시장 점유율을 높이기 위해 자사 브라우저에만 동작하는 기능들을 추가했는데, 이로 인해 브라우저에 따라 웹페이지가 정상적으로 동작하지 않는 크로스 브라우징 이슈가 발생

이로 인해 비영리 표준화 기구인 ECMA 인터네셔널에서 자바스크립트 표준화 진행되어, 표준화된 자바스크립트 버전인 ECMAScript의 최초버전인 ES1이 등장

이후 ES2 버전에서는 ISO/IEC 16262 국제 표준과 동일한 규격을 적용하며 계속 버전업 되어왔음

자바스크립트 버전별 변천사

  • ES3(1999) → 정규 표현식, try catch
  • ES5(2009) → HTML5와 함께 등장 JSON, 배열조작(forEach, map 등), map, set
  • ES6(2015) → let/const, 클래스, 화살표 함수, 프로미스
  • ES7(2016) → prototype, **연산자
  • ES8(2017) → async/await, Object 정적 메서드
  • ES9(2018) → for await …of, async generator
  • ES10(2019) → Object.fromEntries, Array.prototype.flatMap
  • ES11(2020) → String. prototype. matchAll, BigInt, 옵셔널 체이닝 연산자 등

자바스크립트 성장의 역사

첫 자바스크립트는 웹 페이지의 보조기능을 수행하는 용도였고, 대부분의 로직이 웹 서버에서 실행되며 서버측에서 렌더링(Server Side Rendering)이 진행됨

Ajax

비동기(Asynchronous )방식으로 데이터를 교환할 수 있는 Ajax가 등장하며 렌더링을 Client측에서 직접 렌더링하기 시작했다

서버 측에서의 렌더링은 매번 데이터를 변경할 때마다 새로 페이지를 불러와 렌더링 해야하기에 성능상 문제가 있었고 사용자 입장에서도 좋지않은 경험이였다.

Ajax의 등장으로 변경되는 데이터만 특정하여 값을 변경해 부드러운 화면 전환 효과를 보게 되었다.

jQuery

jQuery는 자바스크립트의 까다롭고 복잡한 문제를 해결해주었고, 직관적인 jQuery로 인해 자바스크립트 환경이 더욱 개선되었다.

V8 자바스크립트 엔진

구글에서 개발한 V8엔진은 빠른 성능을 보여주었고, 데스크톱 애플리케이션과 유사한 사용자 경험을 제공할 수 있게 되었다.

이 이후 클라이언트 사이드 렌더링이 본격적으로 활성화되었고, 프론트엔드 영역이 주목받기 시작했다.

Node.js

브라우저에서만 동작하는 자바스크립트 엔진을 브라우저 이외의 환경에서도 동작할 수 있도록 브라우저에서 독립시킨 자바스크립트 실행 환경

Node.js가 생기며 프론트, 백 모두 자바스크립트를 사용해 개발할 수 있다는 동형성(동일한환경)이라는 *_장점이 있으며, *_비동기I/O, 단일스레드 이벤트 루프 기반으로 동작하기에 요청 처리성능이 좋으며 실시간으로 데이터를 처리하기 위해 I/O가 빈번하게 발생하는 SPA(Single Page Application)에 적합하다.

SPA 프레임워크

복잡해진 개발환경에서는 이전의 자바스크립트 환경에서는 수행하긴 하지만 변경에 유연해지며 CBD 방법론을 기반으로 하는 SPA(Single Page Application)가 대중화되었다.

SPA를 돕는 프레임워크/라이브러리로는 Angular, Reach, Vue.js, Svelte 등이 있다

자바스크립트와 ECMAScript

각 브라우저 제조사는 ECMAScript 사양을 준수해서 브라우저에 내장되는 자바스크립트 엔진을 구현한다.

자바스크립트는 큰 범주로 JavaScript내에 ECMAScript가 들어있다.

ECMAScript는 자바스크립트에서 구현할 때의 뼈대라고 생각해야 한다. 이 뼈대는 문법과 기본 기능을 정의하며 ECMAScript를 기반으로 브라우저에서 자바스크립트가 동작하는 엔진을 구현하여 자바스크립트 실행 환경을 제공한다.

자바스크립트는 브라우저 엔진을 통해 만들어져 실제 웹 페이지와 상호작용하기 위해 사용되는 프로그래밍 언어이다.

자바스크립트의 특징

  • 웹 브라우저에서 동작하는 유일한 프로그래밍 언어이다.
  • 개발자가 별도의 컴파일 작업을 수행하지 않는 인터프리터 언어이다.
  • 인터프리터 언어의 단점인 실행시간을 최적화하기 위해
    JIT(Just-In-Time) 컴파일 기술이 도입되어 자주 실행되는 코드를 컴파일해둔다
  • 명령형, 함수형, 프로토타입 기반 객체지향 프로그래밍을 지원하는 멀티 패러다임 프로그래밍 언어이다.

스터디 회고

자바스크립트가 ECMAScript를 아우른다는 것 추가설명

이 부분이 다음 주 주제와도 연결이 되다보니 이해가 중요한 부분이였는데, 제가 설명을 자세히 못 적었다고 생각이 드네요..!

다음번엔 이해하기 쉽도록 더 잘 정리해보겠습니다 ㅜㅜ

제가 이해할 때 도움됐던 부분을 조금 더 정보를 꺼내 부연 설명 드리자면, 크롬의 경우 우리가 자주 사용하는 확장프로그램을 예시로 들 수 있습니다.

확장프로그램은 ECMAScript 표준을 기반으로 작성되며, 브라우저 자체에서 제공하는 고유API와 모듈을 사용해 다른 기능과 상호작용합니다.

크롬 자체에서만 지원하는 API를 활용하기에 이는 JavaScript 라고 이해했었습니다!

  if (request.message === 'Tab updated') {
    console.log('Tab was updated');
  }
});

🤔 질문

자바스크립트에 대해 알게 된 좋은 글이었습니다! 감사합니다

올려주신 글 부분에서 Node.js 설명 중 궁금한 부분이 있습니다.
Node.js에서 단일 스레드 이벤트 루프 기반이라는데, 단일 스레드인 경우에는 여러 요청들이 몰리면 성능에 이슈가 생기는 것은 아닌가요?
단일 스레드라 요청 처리 성능이 좋다고 되어 있어서 궁금해져 여쭤봅니다!..

🖥️ 답변

저도 처음에 보고 당황해서 따로 검색을 했었는데, 명확히 이해하지 못했다 생각해 올리지는 않았었습니다..

제가 이해가 가능했던 부분까지 설명을 해보자면, 이벤트 루프에 대한 이해가 필요한데요.

간단하게 한 문장으로 표현하자면, 싱글스레드로 이벤트 루프 기능이 동작하고 있고, 상세 기능은 내부적으로 비동기요청들을 멀티스레드 처리생성해 로직 처리 후 콜백하는 형태입니다.

노드에서는 멀티스레드 처리하는 라이브러리를 libuv라고 부르며, 이 라이브러리가 스레드풀에 멀티스레드를 담은 후 요청들에 대한 처리를 진행 한다고 합니다.

때문에 싱글 스레드로 동작을 모니터링 후 동작 처리는 멀티스레드 라이브러리(libuv)에 비동기 요청으로 맡기는 식으로 동작한다고 합니다.

저도 완전한 이해를 기반으로 답변드리지 못하여 아쉽지만 생각보다 단번에 이해하기 어려워 큰 틀에서만 이해해둔 상태입니다..!

이는 이후 책 진도가 나가면 한번 더 깊게 다루도록 하겠습니다!!

반응형

+ Recent posts