1. JavaScript
- 유형 및 연산자, 표준 내장 객체 및 메소드가 있는 다중 패러당미, 동적 언어.
- 구문은 Java 및 C 언어를 기반으로 둠.
- JavaScript는 클래스 대신 객체 프로토 타입을 사용하여 객체 지향 프로그래밍을 지원.
함수는 객체이며, 함수는 실행 가능한 코드를 유지하고 다른 객체와 마찬가지로 전달될 수 있다.
2. JavaScript의 Type
- 수 (Number)
- 문자열 (String)
- 부울 (Boolean)
- 객체 (Object)
- 함수 (Function)
- 배열 (Array)
- 날짜 (Date)
- 정규식 (RegExp)
- 널 (Null)
- 정의되지 않음 (Undefined)
3. 수 (Number)
- parseInt() 함수를 사용하여 문자열을 정수로 변환할 수 있다.
(parseFloat() 함수도 있지만 parseInt() 와는 달리 항상 10진수를 사용한다.)
- 문자열이 수가 아닌 경우 NaN(Not a Number) 로 불리는 값을 Return 한다.
console.log(parseInt('123', 10));
- 덧셈, 뺄셈, 게수 (또는 나머지) 연산을 포함하는 표준 산술 연산자가 지원된다.
또한, Math 내장 객체가 있다.
console.log(Math.sin(3.5));
var r = 10;
var circumference = 2 * Math.PI * r;
console.log(circumference);
- JavaScript는 특별한 값 Infinity와 -Infinity를 가지고 있다.
console.log(1 / 0);
console.log(-1 / 0);
4. 문자열 (String)
- JavaScript에서 문자열은 유니코드 문자들이 연결되어 만들어진 것.
(각각 16 bit 숫자로 표현된 UTF-16 코드 유닛이 길게 이어져있는 것)
- 문자열 역시 객체로 취급된다.
5. undefined / null
- JavaScript는 의도적으로 값이 없음을 가리키는 '객체' 타입의 null과
아직 어떤 값도 할당되지않은 변수임을 나타내는 '정의되지 않음' 객체인 undefined 이 있다.
6. 변수 (Variables)
- 변수 선언시 사용할 수 있는 키워드는 let, const, var 키워드가 있다.
-
let
-
블록 유효 범위 변수를 선언할 수 있다.
-
for(let index = 0; index < 10; index++ )
{
console.log(index);
}
// console.log(index); -> Error
-
const
-
값이 변경되지 않는 변수를 선언할 수 있다.
-
const pi = 3.141592
// pi = 22; -> Error
-
var
-
가장 일반적인 변수 선언 키워드.
-
let, const가 가지는 제한을 갖지 않는다.
-
for(var index = 0; index < 10; index++)
{
console.log(index);
}
console.log(index);
7. 연산자 (Operators)
-
이중 등호(==)
- 서로 다른 타입을 줄 경우 강제로 타입 변환을 수행한다. 따라서 주의해야 한다.
console.log(123 == '123'); // true
console.log(1 == true); // true
-
삼중 등호(===)
- 강제 타입 변환을 하지 않고 비교하기 위해서는 삼중 등호(===)를 사용한다.
console.log(123 === '123'); // false
console.log(1 === true); // false
8. 제어 구조
-
for-of 와 for-in
- for-in : 객체의 모든 열거 가능한 속성에 대해 반복. (key 값에는 접근 가능, value는 접근 불가)- for-of : [Symbol.iterator] 속성을 가지는 컬렉션 전용
Object.prototype.objCustom = function () {};
Array.prototype.arrCustom = function () {};
var iterable = [3, 5, 7];
iterable.foo = "hello";
console.log(iterable.foo);
console.log('-------------');
for (var key in iterable) {
console.log(key); // 0, 1, 2, "foo", "arrCustom", "objCustom"
}
console.log('-------------');
for (var value of iterable) {
console.log(value); // 3, 5, 7
}
-
foreach
- 오직 Array 객체에서만 사용가능한 메서드였지만, ES6 부터 Map, Set 등 여러가지에도 추가 지원됨)
var items = [1,2,3,4];
items.forEach(item => {
console.log(item);
});
9. 객체 (Objects)
- JavaScript 객체는 key-value의 모임이다. 따라서 다음과 비슷하다.
-
Python의 Dictionaries
-
Perl과 Ruby의 Hashes
-
C와 C++의 Hash tables
-
Java의 HashMaps
-
PHP의 Associative arrays
- JavaScript의 대부분은 객체로 취급되기 때문에 기본적으로 해쉬 테이블을 검색하는데 좋은 성능을 보임.
- 값은 객체를 포함하여 모든 것이 될 수 있지만, Key(이름)은 문자열 이다.
// 빈 객체를 생성하는 방법
var object = new Object();
// or
var obj = {};
- 두 번째 방법은 객체 리터럴 구문이라고 부르며 JSON 구문으로 나타내기 좋다.
var object = {
name : "Matagi",
for : "max",
details: {
color : "red",
size : 12
}
}
console.log(object["details"]["size"]);
- 객체 프로토타입(Person)과 프로토타입의 인스턴스(you)를 생성
function Person(name, age) {
this.name = name;
this.age = age;
}
// 객체 정의
var you = new Person("matagi", 28);
console.log(you.name + " age " + you.age);
10. 배열 (Arrays)
- 배열의 생성 및 length
var array = new Array();
array[0] = "dog";
array[1] = "cat";
array[2] = "human";
console.log(array.length);
var overSizeArr = new Array();
overSizeArr[0] = "index_1"
overSizeArr[100] = "index_2"
console.log(overSizeArr.length);
console.log(typeof(overSizeArr[99])); // undefined
- forEach를 사용한 배열 요소 출력.
array.forEach(item => {
console.log(item);
});
11. 함수 (Functions)
- 함수의 가장 기본적인 예
- Return이 없다면 undefined를 반환한다.
function add(x,y) {
var total = x+y;
return total;
}
- arguments 를 통해, 매개 변수로 넘겨진 모든 값을 사용할 수 있다.
function loop()
{
for(let item of arguments)
{
console.log(item);
}
}
loop(2,3,4,5,6);
-
Rest 파라미터 구문
- 정해지지 않은 인수를 배열로 나타낼 수 있게 한다.
function loop(...params)
{
for(let item of params)
{
console.log(item);
}
}
loop(2,3,4,5,6);
-
익명 함수
- 익명 함수 사용의 예
var loop = function()
{
for(let i = 0; i < 10; i++)
{
console.log(i);
}
}
loop();
-
즉시 실행 함수 표현(IIFEs)
var charsInBody = (function counter(elm) {
if (elm.nodeType == 3) { // TEXT_NODE
return elm.nodeValue.length;
}
var count = 0;
for (var i = 0, child; child = elm.childNodes[i]; i++) {
count += counter(child);
}
return count;
})(document.body);
12. 사용자 정의 객체
- JavaScript는 프로토타입 기반언어로 C++이나 Java에서 사용되는 Class 구문이 없다.
따라서 JavaScript는 function을 class로 사용한다.
- Person.prototype은 모든 Person 인스턴스들간에 공유되는 객체.
Person 객체의 설정되지 않은 속성에 접근을 시도할 때마다 그것의 대체 용도로
JavaScript는 Person.prototype에서 그 속성이 존재하는지 살펴본다.
function Person(first, last)
{
this.first = first;
this.last = last;
}
Person.prototype.fullName = function(){
return this.first + ' ' + this.last;
}
Person.prototype.fullNameReversed = function(){
return this.last + ' ' + this.first;
}
var person = new Person('Hong', 'Gil Dong');
console.log(person.fullName());
console.log(person.fullNameReversed());
13. 내장 함수 (Inner functions)
- 좀 더 유지관리가 쉬운 코드를 작성하고자 할 때.
- 한 개 혹은 두 개의 정도의 함수에서만 호출되며 전체 코드 중 다른 부분에서는 사용처가 없는 함수일 경우.
function parentFunc() {
var a = 1;
function nestedFunc() {
var b = 4; // parentFunc은 사용할 수 없는 변수
return a + b;
}
return nestedFunc(); // 5
}
14. 클로져 (Closures)
- JavaScript 함수가 실행될 때는 언제나 '범위' 객체가 생성되어 해당 함수 내에서 생성된 지역 변수를 저장하고 있다.
이것은 모든 전역 변수와 함수가 들어있는 전역 객체와 비슷하지만 두 가지 차이점이 있다.
- 첫 번째로, 함수가 실행될 때마다 새로운 범위 객체가 생성된다.
두 번째로, (브라우저에서 Window로 접근가능한) 전역 객체와 달리 범위 객체는 JavaScript 코드에서
직접적으로 접근할 수 없다.
function makeAdder(a) {
return function(b) {
return a + b;
};
}
var add5 = makeAdder(5);
var add20 = makeAdder(20);
console.log(add5(6)); // 11
console.log(add20(7)); // 20
- 위의 예에서 makeAdder()가 호출되면, 범위 객체는 makeAdder() 함수에 매개변수로 넘겨진 하나의 속성 a를
가진 상태로 생성된다.
일반적으로 JavaScript의 GC가 이 때 makeAdder()에 의해 생성된 범위 객체를 청소해야겠지만,
리턴된 함수가 여전히 범위 객체를 참조하고 있다.
결과적으로 범위 객체는 makeAdder()에 의해 리턴된 함수 객체가 더는 참조되지 않을 때까지 정리되지 않는다.
-
예제
- el을 참조하면 의도와는 달리 익명 내부 함수 때문에 생성된 클로져 내에 붙잡혀 있는다.
function addHandler() {
var el = document.getElementById('el');
el.onclick = function() {
this.style.backgroundColor = 'red';
}
}
-
해결 방법 - 1
- 가장 간단하게 해결할 수 있는 방법은 아래와 같다. (순환 참조 고리를 끊음)
function addHandler() {
var el = document.getElementById('el');
el.onclick = function() {
this.style.backgroundColor = 'red';
}
el = null;
}
-
해결 방법 - 2
- 클로져에 의해 발생된 순환 참조 고리를 끊기 위한 하나의 요령은 또 다른 클로져를 추가하는 것.
- 내부 함수는 실행되고 바로 사라지므로, clickHandler와 함께 생성된 클로져로부터 그 내용을 숨김
function addHandler() {
var clickHandler = function() {
this.style.backgroundColor = 'red';
}
(function() {
var el = document.getElementById('el');
el.onclick = clickHandler;
})();
}
-
해결 방법 - 3
- 또 다른 좋은 요령은 window.onunload 이벤트가 발생하는 동안 순환 참조를 끊는 것.
- 많은 이벤트 라이브러리가 이렇게 동작한다.
- 주의할 것은 Firefox 1.5의 bfcache를 비활성하게 되므로,
별 다른 이유가 없다면 firefox에서 unload listener를 등록해서는 안된다.