자바스크립트

시작하기 전에

웹 브라우저별로 표준을 지원하지 않거나 완벽하게 지원하지 않으므로 (예: IE6이라거나 IE7이라거나 IE8이라거나 IE9라거나...) 이에 주의해주세요.

스크린 리더기, 텍스트 웹 브라우저등을 쓰거나, 플러그인이나 설정 등으로 자바스크립트를 기본적으로 차단하여, 자바스크립트를 쓰지 않는 환경의 사용자들이 있으므로, 자바스크립트 없이도 적절하게 웹사이트를 이용할 수 있도록 신경써 주시기 바랍니다.

기본적인 문법

자바스크립트의 전체적인 문법은 C나 Java와 상당히 비슷합니다.

// 이건 한 줄 주석입니다. /* 이건 여러 줄 주석입니다. */ if(true){} else{} while(true); do{}while(true); for(i=0;i<10;i++){}

변수, 숫자와 문자열

자바스크립트는 동적 타입 언어입니다. 다시 말해, 한 변수에 여러 타입의 객체를 대입할 수 있습니다.

var i=42; var j=1234, k="안녕", 변수; i = true; k = j; 변수 = new Object(); 변수 = i;

변수 이름은 _,$,글자로 시작하여 _,$,글자,숫자로 이루어져 있습니다. (참고)
변수 이름은 대소문자를 구별합니다.

변수 이름에 쓸 수 없는 예약어들이 있으며, 이것은 자바스크립트 키워드와 자바 키워드를 포함합니다.

모든 문자열은 UTF-16 인코딩되어 있으며, 모든 숫자는 64비트 floating point입니다.

문자열은 "" 또는 ''로 둘러싸일 수 있으며, 둘 사이의 차이는 없습니다.
백슬래시(\)를 이용하여 문자열에 탭, 줄바꿈 문자, " 또는 '를 집어넣을 수 있습니다.

var s = '\'\\Hello\tWorld\'\n"Whoo hoo\"\n\u314E\x20\u3147'; /* '\Hello World' "Whoo hoo" ㅎ ㅇ */

Infinity, NaN은 각각 무한대, 숫자가 아닌 것을 뜻합니다.

var i=12, j=Infinity; i/j // 0 j/i // Infinity 0/0 // NaN

사칙연산, 비트 연산은 C와 비슷합니다.

var i=12, j=34; i+j // 46 i/j // 0.35294117... j%i // 10 i^j // 46

문자열과 숫자, 문자열과 문자열을 더할 수도 있습니다. 결과는 항상 문자열입니다.

var i=42, s="안녕"; i+s // "42안녕" s+i // "안녕42" 3+4+s+3+4 // "7안녕34" ""+3+4+s+3+4 // "34안녕34"

나머지 산술 연산에서는 적절한 규칙에 따라 문자열을 숫자로 바꿔 계산합니다.


true와 false는 각각 참과 거짓값을 나타냅니다.

var x=true, y=false; x==true // true y==true // false y = (1+1==2) // true

아직 값이 대입되지 않았을 때에는 undefined 값이 저장됩니다.
null도 빈 값을 뜻하지만, undefined는 정의되지 않은 것, null은 빈 것으로 정의된 것을 뜻합니다.

var x; x // undefined var y=undefined, z=null;

undefined는 표준에는 없는 리터럴입니다만, 많은 브라우저에서 지원합니다.
안전하게 undefined를 얻는 방법은 조금 아래 "함수" 부분을 참고하세요.

약한 타입

등호 두 개(==)는 두 값이 타입은 달라도 같은 값을 가질 경우 참이 되여, 등호 세 개(===)는 두 값이 완전히 같을 경우 참이 됩니다.

var x=10, y='10', z='1e1', w='0XA'; x==y // true x==z // true(!) x==w // true(!!) x===y // false

!=와 !==는 각각 ==와 ===의 반대입니다.

== 연산자의 자세한 규칙은 꽤 복잡하니 왠만하면 ===를 씁시다.


NaN은 자기 자신과 다른 유일한 값입니다.
두 Object는 비록 모든 속성이 같더라도 다른 참조값을 가지고 있으면 다른 값으로 인식됩니다.


(+x)는 x를 숫자로, (''+x)는 x를 문자열로, !!x는 x를 boolean으로 바꿔줍니다.

console

IE 9 이상, Firefox, Chrome, Safari, Opera, Node.js에서 console을 쓸 수 있습니다.

console.log('a','b','c'); console.log("%d+%d=?",2,3); // Opera에서는 안 됨 console.warn("경고! 경고!"); console.error("오류!"); console.info("이 문서의 맨 끝에는 케이크가 있습니다.");

디버깅할 때 유용한 메소드들도 있습니다.

console.debug("Checkpoint"); console.assert("asdf".length == 4, "asdf의 길이는 4"); console.time("loop"); for(var i=0; i<2e6; i++); console.timeEnd("loop");

함수

함수는 다음과 같이 선언할 수 있습니다.

function foo(i,j){ return i*j+i+j; } console.log(foo(3,4));

주어진 인자 수보다 많은 수의 인자가 주어지면, 뒤의 값은 무시됩니다.

function foo(i,j){ return i*j+i+j; } console.log(foo(3,4,5,6,'안녕'));

주어진 인자 수보다 적은 수의 인자가 주어지면, 남은 인자들에는 undefined 값이 대입됩니다.
값을 명시적으로 반환하지 않을 때에도 undefined를 반환합니다.

이 두 가지는 안전하게 undefined를 얻는 방법입니다. (jQuery에선 전자를 사용)

function foo(i,j){ return j; } console.log(foo(42));

함수 내부에서 선언된 변수는 외부에서 선언된 변수와 다른 변수입니다.

var i=1, j=2, k=3; function asdf(i){ var j=1234; i+=10; k+=10; console.log(i,j,k); } asdf(12); console.log(i,j,k);

문자열, 숫자, boolean, null, undefined가 아닌 경우 인자의 참조값이 전달됩니다.

var i=42; // 배열을 선언합니다. var a=[1,2,3,4]; function modify(x,y){ x++; y.push(5); console.log(x,y); } modify(i,a); console.log(i,a);

기본적으로 제공되는 함수들은 다음과 같습니다.

// parseInt(문자열, 진법) console.log(parseInt("1234")); // 1234 console.log(parseInt("0x42",16)); // 66 // parseFloat(문자열) console.log(parseFloat(".1234")); // 0.1234 // isNaN(숫자) console.log(isNaN(0/0), isNaN(1/0)); // isFinite(숫자) console.log(isFinite(1e10), isFinite(1e1000)); // encodeURI(s), encodeURIComponent(s) var s="//hi%&&"; console.log(encodeURI(s), encodeURIComponent(s)); // decodeURI, decodeURIComponent도 있음

Scope

C 등과는 다르게, 자바스크립트에서는 오직 함수만이 scope를 구분짓습니다. (출처_필요)

만약 어떤 변수가 var로 정의되었었다면, 그 변수는 "로컬" 변수가 됩니다.

var x = 42; function foo(){ x = 1234; } foo(); console.log('foo', x); function bar(x){ x = 5678; } bar(x); console.log('bar', x); function baz(){ var x; x = 9012; } baz(); console.log('baz', x); function bazz(){ x = 3456; var x; } bazz(); console.log('bazz', x);

(Closure 참조) 함수 안에 함수를 넣을수도 있는데, 이 때 안의 함수는 밖 함수의 로컬 변수를 참조할 수 있습니다.

var x = 42; var y = 100; function f(){ var x = 123; var z = 456; function g(){ var x = 444; console.log(x, y, z); } g(); console.log(x, y, z); } f(); console.log(x, y); // ReferenceError! console.log(z);

(웹 브라우저에서) window 변수는 창 전체를 "담당"하는 변수이며, window의 각 변수는 전역 변수처럼 취급됩니다.

window.a = 42; console.log(a);

자바스크립트의 객체들

자바의 클래스처럼, 자바스크립트의 객체들은 자신의 속성과 메소드를 가지고 있습니다.

typeof 연산자로 어떤 변수가 어떤 타입인지를 알 수 있습니다.

var o={}, s="abc", i=123, x, y=null; console.log(typeof o, typeof s, typeof i, typeof x, typeof y);

객체

다음과 같이 특정 속성을 가지는 객체를 만들 수 있습니다.

var obj={'a':42, 'b':true}; console.log(obj.a, obj.b); // 42, true console.log(obj['a'], obj["b"]); obj.b = 'Hello'; console.log(obj.b); // "Hello"

생성자, private 변수, 상속 등은 프로토타입 항목에서 다룰 예정입니다.

Math

수학 관련 함수와 상수들은 Math 객체롤 이용하여 쓸 수 있습니다.

var x = Math.cos(Math.PI/4); console.log(x, Math.SQRT1_2); var y = Math.exp(1/2); console.log(y, Math.sqrt(Math.E));

올림, 반올림, 버림, 삼각함수, 지수함수, 제곱, 제곱근, 최솟값, 최댓값, 난수 등의 함수들이 있습니다.

숫자

Math처럼 Number 객체에도 각종 속성과 함수들이 있습니다.


Number.MAX_VALUE와 Number.MIN_VALUE은 각각 자바스크립트 숫자의 절댓값의 최대, 최소값입니다.
Number.NaN은 NaN이며, Number.POSITIVE_INFINITY와 Number.NEGATIVE_INFINITY는 각각 +Infinity와 -Infinity입니다.

var x = Number.MAX_VALUE; console.log(x*2); var y = Number.MIN_VALUE; console.log(y/2);

숫자에도 메소드가 있습니다. (정확한 표현은 아닙니다.)
toString 메소드는 숫자를 문자열로 변환해줍니다. 이런 기능을 하는 메소드는 다른 종류의 객체에서도 찾아볼 수 있습니다.

var x = 1234; console.log(x.toString()); console.log(x.toString(2));

toFixed 메소드는 소숫점 이하 x자리까지 반올림한 값을 반환합니다.

var x = 1234.0267; console.log(x.toFixed(1)); console.log(x.toFixed(3));

toExponential 메소드는 과학적 표기법으로 수를 나타낸 값을 반환합니다.

var x = 420; console.log(x.toExponential(4));

toPrecision 메소드는 toFixed와 toExponential을 적절히 합쳐놓은 것입니다.


10, 16, 8진법(확장), 과학적 표기법으로 수를 나타낼 수 있습니다.

-2147483648~2147483647 사이의 정수로 비트 연산을 할 수 있습니다.
나타낼 수 있는 정수의 최고 절댓값은 2^53입니다.

// 아래 수들은 모두 같은 수입니다. var x=66, y=0x42, z=0102, w=6.6e1; var a = 100000000001; console.log(a,a+1); console.log(a|1); var b = Math.pow(2,53); console.log(b,b+1);

문자열

String.fromCharCode는 주어진 문자 코드를 문자열로 변환합니다.

var s = String.fromCharCode(65,66,67); console.log(s);

length 속성으로 문자열의 길이를 알 수 있습니다.

var s = " Hello, 세상아!"; console.log(s.length);

charAt(i) 메소드는 i번째 문자를 반환합니다.
charCodeAt(i) 메소드는 i번째 문자의 코드를 반환합니다.

var s = "가나다"; console.log(s.charAt(0)); console.log(s[1]); console.log(s.charCodeAt(2));

concat() 메소드는 문자열을 합쳐줍니다.

console.log("123".concat("가나다","ABC","아아아"));

indexOf() 메소드과 lastIndexOf() 메소드로 한 문자열 안에 다른 문자열이 어디에 있는지 알 수 있습니다.

// 01234 5 6 7 8901234567 8 9 0 12345678 var s = "1234가나다라abcd12343라다나가dcb1234a"; console.log(s.indexOf('1234')); console.log(s.indexOf('1234',13)); console.log(s.lastIndexOf('1234')); console.log(s.lastIndexOf('1234',22)); console.log(s.indexOf('가다'));

slice() 메소드로 문자열을 자를 수 있습니다.

var s = "0123456789"; console.log(s.slice(3)); console.log(s.slice(-4)); console.log(s.slice(3,8)); console.log(s.slice(5,-1));

substring() 메소드는 slice() 메소드와 비슷하지만, 몇 가지 다른 점이 있습니다.

var s = "0123456789"; console.log(s.substring(8,3)); console.log(s.slice(8,3)); console.log(s.substring(-1)); console.log(s.slice(-1));

toLowerCase(), toUpperCase()는 문자열을 각각 소문자와 대문자로 변환합니다.

var s = "ABC가나다abc\xE9"; console.log(s.toLowerCase()); console.log(s.toUpperCase());

trim() 메소드는 문자열 앞뒤의 공백을 삭제합니다.

var s = " Hello, world! \t"; console.log('['+s+']'); console.log('['+s.trim()+']');

배열

자바스크립트에서 배열은 다음과 같이 쓸 수 있습니다.

var a = [1,2,3]; var b = Array(1,2,3); var c = new Array(1,2,3); var d = new Array(10); console.log(a, b, c, d); console.log(a[0], c[2], d[0]); console.log(a.length, d.length); console.log(a.toString()); // 참조값이 다르면 내용물이 같더라도 다른 객체로 취급됩니다. console.log(a==b, a===c);

배열은 객체라는 점에 주의하세요.

var a = [1, 2]; var b = [a, a]; console.log(b[0]); a[0] = 42; console.log(b[0]);

join() 메소드로 배열을 원하는 스타일로 문자열로 바꿀 수 있습니다.

// 문자열의 split 메소드로 반대 작업을 할 수 있습니다. var a = "Foo Bar".split(" "); console.log(a.join(',')); console.log(a.join(" Boo "));

concat 메소드로 배열들을 합칠 수 있습니다. 원본은 바뀌지 않습니다.

var a = [1, 2, 3]; console.log(a.concat([4,5,6], [7,8], 9, 10));

push()와 pop() 메소드로 배열 뒤에 뭔가를 집어넣거나 꺼낼 수 있습니다.

var a = [1, 2, 3]; console.log(a.push(42)); console.log(a); a.push([1, 2], 3, 4); console.log(a); console.log(a.pop()); console.log(a);

unshift()와 shift() 메소드로 배열 앞에 뭔가를 집어넣거나 꺼낼 수 있습니다.

var a = [1, 2, 3]; console.log(a.unshift(42, 43)); console.log(a); console.log(a.shift()); console.log(a);

reverse() 메소드로 배열을 뒤집을 수 있으며, 원본도 바뀝니다.

var a = "3141592".split(""); console.log(a); console.log(a.reverse()); console.log(a);

slice() 메소드로 배열을 자를 수 있습니다. 원본은 바뀌지 않습니다.

var a = [1, 2, 3, 4, 5]; console.log(a); console.log(a.slice(2,-1)); console.log(a);

splice() 메소드로 배열에 특정 원소를 집어넣으면서 그 자리의 기존 원소를 뺄 수 있습니다.
반환되는 것은 지워지는 원소들입니다.

var a = ["ㄱ", "ㄴ", "ㄷ", "ㄹ"]; // a의 1번째 자리부터 0개의 원소를 빼고 A, B, C를 삽입한다. console.log(a.splice(1,0,"A","B","C")); console.log(a); // a의 3번째 자리부터 2개의 원소를 빼고 ㅎ를 삽입한다. console.log(a.splice(3,2,"ㅎ")); console.log(a);

indexOf() 메소드로 배열에서 특정 원소를 찾을 수 있으며, 엄격한 비교를 해서 같은 원소의 위치를 반환합니다.

var a = [1, "2", 2, 3, [4, 5], 3]; console.log(a.indexOf(2), a.indexOf("2")); console.log(a.indexOf(3)); console.log(a.indexOf(42), a.indexOf([4,5]));

문자열처럼 두번째 인자를 받을 수 있으며, lastIndexOf() 메소드도 있습니다.

날짜

내부적으로 날짜는 하나의 정수입니다. UTC로 1970년 1월 1일 자정부터 앞뒤로 1억일까지 나타낼 수 있습니다.
윤년은 고려하지만 윤초는 고려하지 않으며, 일광 절약 시간을 제외한 자잘한 시차 수정은 고려하지 않습니다.


Date 함수는 현재 날짜를 나타내는 문자열을 반환합니다.

var s = Date(); console.log(s);

Date 생성자는 주어진 인자로 새 Date 객체를 만듭니다.

var a = new Date(); // 2012년 12월 var b = new Date(2012, 11); var c = new Date(2012, 11, 21); // 2012년 12월 21일 오후 12시 34분 56.789초 var d = new Date(2012, 11, 21, 12, 34, 56, 789); // UTC 시각은 Date.UTC(...)로 얻을 수 있으며, 반환값은 숫자입니다. console.log(a); console.log(b); console.log(c); console.log(d);

숫자 인자가 하나 주어지면 그 숫자에 해당하는 날짜로 변환합니다.
문자열 인자가 하나 주어지면 그 문자열을 파싱합니다.

var d = new Date(12345); console.log(d); d = new Date("2012/12/21 12:34:56.7"); console.log(d); // 이 코드는 위 코드와 같습니다. d = new Date(Date.parse("2012/12/21 12:34:56.7")); console.log(d);

다음과 같이 날짜를 문자열로 변환할 수 있습니다.
toISOString()과 toJSON()을 제외한 문자열은 브라우저별로 다를 수 있습니다.

var a = new Date(); console.log(a.toString()); console.log(a.toDateString()); console.log(a.toTimeString()); console.log(a.toUTCString()); console.log(a.toISOString()); console.log(a.toJSON()); console.log(a.toLocaleString()); // localeDateString, localeTimeString 메소드도 있습니다.

valueOf()와 getTime() 메소드로 날짜를 숫자로 변환할 수 있습니다.
Date.now()는 (new Date()).getTime()과 동일합니다.

var a = new Date(); console.log(a.getTime()); console.log(Date.now());

getFullYear(), getMonth(), getDate()로 년월일을 알아낼 수 있습니다.
실제 달과 getMonth()의 반환값이 1씩 차이난다는 걸 기억해두세요!

var d = new Date(); console.log(d.getFullYear(), d.getMonth()+1, d.getDate()); // 이 단락의 모든 메소드로 이렇게 UTC 시각을 알아낼 수 있습니다. console.log(d.getUTCDate());

getDay()로 무슨 요일인지를 알아냈 수 있습니다.

console.log("일월화수목금토"[d.getDay()]);

getHours(), getMinutes(), getSeconds(), getMilliseconds()로 시각을 알 수 있습니다.

console.log(d.getHours(), d.getMinutes(), d.getSeconds()); console.log(d.getMilliseconds());

위 메소드에서 get을 set으로 바꾸면 날짜를 설정할 수도 있습니다. (getDay() 제외)

d.setFullYear(1984); console.log(d.toString()); d.setMinutes(11,10); console.log(d.toString());

정규표현식

자바스크립트에서는 정규표현식으로 다양한 것들을 할 수 있습니다.


정규표현식은 다음과 같이 정의할 수 있습니다.

var r1 = /Hello\, world\./; var r2 = new RegExp('Hello\\, world\\.'); var r3 = /Hi/gim var r4 = new RegExp('Hi', 'gim');

정규 표현식에선 g, i, m 플래그를 쓸 수 있으며, 각각 global, ignoreCase, multiline을 뜻합니다.

이 문서에서는 정규표현식 자체에 대한 설명은 생략하며, 쓸 수 있는 곳만 소개하겠습니다.


source 속성은 정규 표현식을 만든 문자열입니다.
global, ignoreCase, multiline 속성은 정규 표현식의 g, i, m 플래그 유무를 나타냅니다.
lastIndex속성은 정규 표현식 match를 시작할 곳을 나타냅니다. (덮어쓰기 가능)


exec() 메소드로 정규 표현식을 문자열에 적용시킬 수 있습니다.
결과는 첫번째로 일치하는 것에 대한 정보와, (index)인덱스, 그리고 (input)입력한 내용입니다.

var r = /f(oo)(z)?/; var g = /f(oo)(z)?/g; var s = "I do fooz bar foo bar foo!"; console.log(r.exec(s)); console.log(g.exec(s)); console.log(g.exec(s)); console.log(r.lastIndex); console.log(g.lastIndex); g.lastIndex = 999; console.log(g.exec(s));

test() 메소드는 exec()의 결과가 null이 아닌지 여부를 반환합니다.

var r = /[0-9]{3}/; console.log(r.test('01')); console.log(r.test('3210'));

String 객체의 match() 메소드는, 정규 표현식이 global이 아닐 경우에는 exec()와 동일합니다.
정규 표현식이 global일 경우에는, 정규 표현식에 맞는 모든 것을 배열로 만든 것입니다.

var r = /f(oo)(z)?/; var g = /f(oo)(z)?/g; var s = "I do fooz bar foo bar foo!"; g.lastIndex = 999; console.log(s.match(r)); console.log(s.match(g)); console.log(g.lastIndex);

String 객체의 search() 메소드는 indexOf()의 정규 표현식 버전이라 봐도 무방합니다.

var r = /f(oo)(z)?/; var x = /ba(o|z)/; var g = /f(oo)(z)?/g; var s = "I do fooz bar foo bar foo!"; g.lastIndex = 999; console.log(s.search(r)); console.log(s.search(x)); console.log(s.search(g)); console.log(s.search("fo*!")); console.log(g.lastIndex);

String 객체의 replace() 메소드로 문자열의 일정 부분을 바꿀 수 있습니다.

var g = /f(oo)(z)?/g; var s = "I do fooz bar foo bar foo!"; console.log(s.replace(g, "($&)$$[$1][$02]")); console.log(s);

String 객체의 split() 메소드의 첫번째 인자에 정규 표현식을 넣을 수도 있습니다.

var r = /<(\/)?([^<>]+)>/; var html = "The <i>quick</i> brown fox " + "<pre>jumps over</pre> the lazy dog."; console.log(html.split(r));

두번째 인자로 얼마나 많이 쪼갤지를 결정할 수 있습니다.

console.log(html.split(r,3));

함수

자바스크립트에서 함수는 단순한 Function 객체입니다.

// 어라? console.log(typeof asdf); function asdf(i, j){ return i*j+i+j; } var foo = asdf; console.log(foo(1,2));

위와 같이 함수 선언은 한 scope 안에서는 순서와 상관없이 코드가 실행되기 전에 먼저 정의됩니다.


함수 내부에선 this를 쓸 수 있는데, 어떤 객체의 메소드라면 그 객체가 this가 됩니다.
더 정확하고 자세한 표현은 아래 프로토타입 부분을 참고해주세요.

function f(){ return this; } // 일반적인 함수의 this는 브라우저에서는 window입니다. console.log(f()); var o = {'x':f}; console.log(o.x);

call()과 apply() 메소드로 this와 인자를 지정할 수 있습니다.

function f(a,b){ console.log(a,b); console.log(this); } var o = {}; f(1,2); f.call(o,42,43); f.apply(o,[10,11]);

arguments로 함수의 인자를 알 수 있습니다.
비록 배열처럼 쓸 수 있어도 정말로 배열은 아니라는 점에 주의해주세요.

function sum(){ for(var sum=0, i=0; i<arguments.length; i++){ sum += arguments[i]; } return sum; } console.log(sum(1,2,3));

(자바스크립트에서) setInterval과 setTimeout은 지정된 간격마다 주어진 함수를 한 번, 또는 계속 실행시킬 수 있습니다.

function f(a, b, c){ console.log(a, b, c); } // 함수 f를 2초마다 실행한다. var x = setInterval(f, 2000); setTimeout(f, 1000, 42); setTimeout(f, 3000, 1, 2, 3);

첫번째 인자로 문자열을 줄 수도 있지만, IE가 아니라면 신경 쓸 필요가 없습니다.

clearInterval과 clearTimeout으로 "삭제"할 수 있습니다.

clearInterval(x);

함수식

함수식으로 이름이 없는 함수를 만들 수 있습니다.

var x = function(i, j){ return i*j+i+j; }; console.log(x(12,34));

이름이 없는 함수도 다른 변수에 할당할 수 있습니다.

var o = {}; var x = function(i, j){ return i*j+i+j; }; o.a = x; console.log(o.a(4, 5));

함수식에 이름을 부여할수도 있습니다.

var x = function factorial(i){ if(i==0) return 1; return factorial(i-1)*i; }; console.log(x(10)); console.log(factorial); // ReferenceError!

함수식의 상당히 자주 보이는 응용 예 중 하나는, 다음과 같이 global scope를 신경 쓰지 않는 코드를 만드는 것입니다.

var x = 100; var y = 200; var z = 42; (function(){ var x = 12; var y = 34; console.log(x+y+z); }()); console.log(x+y+z);

Array 객체의 sort() 메소드에 함수 인자를 지정하여 정렬을 할 수 있습니다.
sort에 넣을 함수 f는 두 인자 x,y를 받으며, f(x,y)의 부호에 따라 어느 인자가 더 큰지 결정됩니다.

var a = [3, 1, 4, 1, 5, 9, 2]; a.sort(function(x,y){ return x-y; }); console.log(a);

오름차순으로 정렬되며, f(x,y)>0은 x>y를 의미하고, f(x,y)<0은 x<y를 의미합니다.


Array 객체의 every() 메소드와 some() 메소드를 사용하여 모든/일부 원소를 f에 대입했을 때 참값이 반환되는지 알 수 있습니다.
두번째 인자로 this를 지정할 수 있습니다.

var f = function(x){return x>5;} var a = [3, 1, 4, 1, 5, 9, 2]; console.log(a.every(f)); console.log(a.some(f));

Array 객체의 forEach() 메소드과 map() 메소드를 사용하여 배열의 원소를 f에 대입할 수 있습니다.
forEach() 메소드는 각 원소를 f에 대입하기만 하며, map() 메소드는 f의 반환값들로 새 배열을 생성한 것을 반환합니다.
원본은 바뀌지 않습니다.

var f = function(x){return x*42;} var a = [3, 1, 4, 1, 5, 9, 2]; a.forEach(console.log, console); console.log(a.map(f)); console.log(a);

Array 객체의 filter() 메소드로 배열을 거를 수 있습니다. 원본은 바뀌지 않습니다.

var f = function(x){return x>=5;} var a = [3, 1, 4, 1, 5, 9, 2]; console.log(a.filter(f)); console.log(a);

Array 객체의 reduce()와 reduceRight() 메소드로 값을 "누적"시키며 계산할 수 있습니다.
함수의 첫번째 인자는 전 연산의 결과값, 두번째 인자는 현재 원소, 세번째 인자는 현재 원소의 인덱스, 그리고 네번째 인자는 전체 배열입니다.
메소드의 두번째 인자로 초기값을 지정할 수 있으며, 기본적으로 배열의 첫 원소입니다.
reduce는 왼쪽에서 오른쪽으로, reduceRight는 오른쪽에서 왼쪽으로 진행합니다.

var a = [1, 2, 3, 4, 5, 6, 7]; console.log(a.reduce(function(x,y){ return x+y; }));

String 객체의 replace() 메소드의 두번째 인자에 함수를 넣을 수도 있습니다.
첫번째 인자는 매치된 문자열, 마지막에서 두번째 인자는 인덱스, 마지막 인자는 전체 문자열이며, 나머지는 정규 표현식의 그룹들입니다.

var a = ["철수", "영희"]; var r = /\$(\d)/g; var s = "$0는 $1를 사랑해.\n$1는 $0를 싫어해."; console.log(s.replace(r, function(x, y){ return a[y]; }));

Closure

다음과 같이 내부 변수를 내부 함수에서 계속 참조할 수 있습니다.

function f(){ var x = 42; function g(){ x++; return x; } return g; } var g = f(); console.log(g()); console.log(g()); // x에는 접근할 수 없습니다. console.log(x);

프로토타입

클래스 기반 OOP 언어인 자바와는 다르게, 자바스크립트는 프로토타입을 기반으로 합니다.

new Object

그냥 함수를 호출할 때와 달리, new 키워드를 붙이면 새 객체를 생성합니다. (this를 반환하는 것 같이)

function Foo(x){ this.bar = x; this.baz = "42"; return 123; } var x = Foo(1); var y = new Foo(2); console.log(x); console.log(y.bar); console.log(y.baz);

constructor로 생성자를 알 수 있습니다.

function Foo(){} var x = new Foo(); console.log(x.constructor); console.log(x.constructor.constructor);

prototype으로 프로토타입을 지정할 수 있습니다. (코드 참고)

function Foo(x){ this.bar = x; } Foo.prototype.baz = 12; var crow = new Foo(42); console.log(crow.bar); console.log(crow.baz);

물론 메소드도 지정할 수 있습니다.
이렇게 하면 각 개체마다 함수를 가지는 것보다 더 효율적으로 공간을 쓸 수 있게 됩니다.

function Hello(s){ this.target = s; } Hello.prototype.say = function(){ console.log("Hello, "+this.target+"!"); } var h = new Hello("world"); h.say();

this에 주의해 주세요!

function Foo(){} Foo.prototype.bar = function(){ console.log(this); } var foo = new Foo(); var bar = foo.bar; foo.bar(); bar();

기본 객체에 prototype으로 새 메소드를 추가할 수 있지만, 당연히 권장되는 것은 아닙니다.

var a = [1, 2, 3]; Array.prototype.foo = function(){ for(var s=0,i=0; i<this.length; i++) s += this[i]; return s; }; Object.prototype.bar = function(){ return "AAAAAAAAAAA"; }; var b = [4, 5, 6]; console.log(a.foo(), b.foo()); console.log(a.bar());

Scope를 잘 이용하면 "private" 메소드와 변수도 만들 수 있습니다.

function Foo(){ var bar = 42; var secret = function(){ bar = 999; } this.doSecret = function(i){ if(i===42) secret(); } this.say = function(){ console.log("Foo "+bar); } } var foo = new Foo(); console.log(foo.bar, foo.secret); // undefined foo.doSecret(12); foo.say(); foo.doSecret(42); foo.say();

getter와 setter도 지정할 수 있지만, 여기서는 이게 있다는 것만 언급하고 넘어가겠습니다.

function Foo(){} var foo = new Foo(); Object.defineProperty(foo, "bar", { 'get': function(){ return "bar "+this._bar; }, 'set': function(bar){ this._bar = bar+" bar"; } }); foo.bar = "baz"; console.log(foo.bar);

상속

제일 기본적인 상속은 다음과 같이 할 수 있을 겁니다.

function Foo(x){ this.value = x; } Foo.prototype.foo = function(){ console.log("FOO "+this.value+"!"); } Foo.prototype.print = function(){ console.log("Foo "+this.value); } var foo = new Foo(42); var bar = new Foo(42); bar.print = function(){ console.log("Bar "+this.value); } foo.foo(); bar.foo(); foo.print(); bar.print(); // 생성자의 prorotype에 있으면 false, // 객체의 속성으로 직접 있는것이면 true. console.log(foo.hasOwnProperty('print')); console.log(bar.hasOwnProperty('print'));

Object.create를 사용할 수도 있습니다.

function Foo(x){ this.value = x; } Foo.prototype.print = function(){ console.log("Foo "+this.value); } var foo = new Foo(42); var bar = Object.create(foo); bar.value = 43; foo.print(); bar.print();

Object.create를 좀 더 건드려 봅시다.

var o = {}; var n = Object.create(null); console.log(o, n); console.log(o.hasOwnProperty); console.log(n.hasOwnProperty);

살짝 고급스러워 보이는 방법을 써 봅시다.

function Foo(x){ this.value = x; } Foo.prototype.foo = function(){ console.log("FOO "+this.value+"!"); } Foo.prototype.print = function(){ console.log("Foo "+this.value); } function Bar(y){ Foo.call(this, y); this.value2 = y*2; } Bar.prototype = new Foo(); Bar.prototype.constructor = Foo; Bar.prototype.print = function(){ console.log("Bar "+this.value); } Bar.prototype.bar = function(){ console.log("BAR "+this.value2+"!"); } var foo = new Foo(42); var bar = new Bar(43); foo.foo(); bar.foo(); foo.print() bar.print(); bar.bar();

node.js에서는 util.inherits로 비슷한 것을 할 수 있습니다.
이것을 참고하셔도 좋습니다.

DOM

DOM(Document Object Model)은 (X)HTML과 XML을 다루기 위한 컨벤션입니다. DOM API를 이용하여 HTML 문서의 내용에 쉽게 접근하고 동적으로 바꿀 수 있습니다.
하지만, 브라우저별로 (특히 IE) 지원하는 것이 조금씩 다루기 때문에 jQuery등의 라이브러리등을 많이 씁니다.

DOM은 document를 루트로 하는 트리처럼 구성되어 있으며, <body>는 document.body같이 접근할 수 있습니다.

기본적인 메소드

HTMLXxxElement는 HTML Xxx 태그를 나타냅니다. 이것을 직접 호출할 수는 없습니다.
document.createElement() 메소드로 생성할 수 있습니다.

document.getElementById(), document.getElementsByTagName(), document.getElementsByClassName() 등으로 해당 id, name, class를 가지는 element를 찾을 수 있으며, insertBefore()나 appendChild() 등으로 element를 삽입할 수 있습니다.

childNodes 속성은 자식 노드들을 보여주며, firstChild, lastChild로 첫, 마지막 자식을, nextSibling과 previousSibling으로 형제 노드를 얻을 수 있습니다.

jQuery

jQuery는 웹 브라우저마다 DOM API나 자바스크립트의 각종 표준 함수들이 존재하지 않거나, 존재해도 쓰기가 불편한 것을 쓰기 간편하게 만드는 자바스크립트 라이브러리입니다.

2006년부터 만들어진 jQuery의 현재 최신 버전은 2.0.2이며, 최신 브라우저만을 지원합니다
IE 8 이하를 위한 버전도 같이 개발되고 있으며, 현재 최신 버전은 1.10.1입니다.

API 문서

jQuery의 자세한 문서는 api.jquery.com에서 자세히 볼 수 있습니다. 이 글에서 다루지 않는 많은 유용한 메소드들이 많고, 또한 다른 자세한 설명들도 있으니, 즐겨찾기에 추가해두고 시간이 날 때마다 읽거나, 찾을 메소드가 있을 때 저 곳에서 찾아보는 것이 좋습니다.

기초적인 사용법

jQuery나 $ 변수로 jQuery 라이브러리에 접근할 수 있습니다.

var s = " Hello, world! "; // IE 8 이하에선 String.prototype.trim이 없음 console.log(s.trim()); console.log($.trim(s)); // JSON.parse를 쓰는게 정상이여야 하지만.. s = "{\"test\":123456}"; console.log($.parseJSON(s));

다른 라이브러리가 $를 쓸 경우, jQuery.noConflict() 메소드로 $를 다시 복구할 수 있습니다.
이 때 $를 jQuery로 쓰고 싶은 경우에는 함수식을 쓰세요.

jQuery.noConflict(); // $는 다른 라이브러리 (function($){ // $는 jQuery }(jQuery));

$(document).ready(f)나 $(f)처럼 문서를 "편집"할 수 있을 때 jQuery를 실행시킬 수 있습니다.
이 때, 함수의 첫번째 인자로 jQuery 객체가 주어집니다.

console.log($('#test')); $(function(){ console.log($('#test')); });

body의 onload 속성과 함께 쓸 수 없으니 주의해주세요!


바로 윗 예제에서도 보셨겠지만, $('CSS Selector')처럼 DOM 객체에 접근할 수 있습니다.
IE6부터 Opera까지 모든 웹 브라우저에서 작동합니다!

// 아이디가 test1인 객체 console.log($('#test1')); // 클래스 이름이 test인 모든 객체 console.log($('.test')); // type attribute의 값이 hidden인 모든 input 필드 console.log($('input[type=hidden]')); // #test1 객체의 모든 자식 p 노드들 console.log($('#test1>p')); // #test1 객체 안에 있는 모든 p 노드들 console.log($('#test1 p'));

자세한 사용 방법은 jQuery API 사이트를 참고해 주세요.


jQuery 객체는, 비록 배열은 아니지만, 배열처럼 접근할 수 있으며 length 속성도 있습니다.

var tests = $('.test'); console.log(tests.length, tests.size()); console.log(tests[2]); console.log(tests.get(-1));

hide(), show() 메소드로 객체를 숨기거나 보이게 할 수 있습니다.

$('.test').hide(); $('.test').show();

시간을 지정해주면...

$('.test').hide(500); $('.test').show(500);

함수를 지정해 줄 수도 있습니다. 이 단락의 모든 메소드에 적용됩니다.
실행되는 횟수에 주목해 주세요.

$('.test').hide(1000, function(){ console.log('어, 어디로 갔지?'); });

toggle() 메소드로 둘을 번갈아 가면서 할 수 있습니다.

$('.test:first').hide(); $('.test').toggle(); $('.test').toggle(500);

fadeIn(), fadeOut() 메소드로 서서히 사라지는 효과를 보이게 할 수 있습니다.
fadeToggle() 메소드도 있습니다.

$('.test').fadeOut(); $('.test').fadeIn(500);

slideDown(), slideUp(), slideToggle()도 있습니다.

$('.test').slideUp(); $('.test').slideDown(1000);

jQuery의 많은 메소드는, 다른 값을 반환하지 않는다면, 자기 자신을 반환합니다.
이것은 jQuery를 쓰기 매우 편하게 만들어줍니다.

$('.test').slideUp().slideDown().hide(1000).show(1500);

css() 메소드는 CSS 속성을 얻거나 설정할 수 있게 합니다.

$('.test').css('background-color','#DDD'); console.log($('#test1').css('font-size')); $('.test').css({'color':'#666','font-size':'1.5em'});

each() 메소드로 각 개체에 접근할 수 있습니다.

$('.test').each(function(x){ console.log(x,this); });

값 읽어오기 / 쓰기

text() 메소드와 html() 메소드로 현재 개체의 문자열과 내부 HTML을 수정할 수 있습니다.

$('.test').text("Hai"); $('#test13').html('<b>FOO</b>'); console.log($('#testp2').text());

data() 메소드로 현재 개체에 데이터를 지정할 수 있습니다.
기본값은 data-*로 지정된 값입니다.

console.log($('#testp2').data('foo')); $('p').data('test',42); console.log($('p').data('test'));

val() 메소드로 현재 개체의 값을 얻어오거나 수정할 수 있습니다.

console.log($('#testarea').val()); $('#testtext').val("Hello, world!"); console.log($('#testselect').val()); $('#testselect').val(42);

DOM

우선, attr() 메소드로 속성을 읽고 쓸 수 있습니다.

$('div').each(function(){ console.log($(this).attr('id')); $(this).attr('foo','bar'); });

addClass(), removeClass()로 클래스를 추가할 수 있습니다.

$('div').addClass('foo'); $('div').removeClass('foo');

hasClass()로 해당 클래스 속성을 가지고 있는지 알 수 있습니다.

console.log($('.test').hasClass('test'));

이벤트

jQuery에서는 짜증나고 복잡한 DOM 이벤트 처리까지 자동으로 잘 해줍니다.

click() 함수는 주어진 오브젝트를 클릭했을 때 함수를 호출하게 합니다.

$('.test').click(function(){ console.log('Click!'); });

mousedown()과 mouseup()도 써봅니다.

$('.test').mousedown(function(e){ console.log('Mousedown',e.which); }).mouseup(function(e){ console.log('Mouseup',e.which); });

이벤트 객체의 속성 중 target, relatedTarget, pageX, pageY, which, metaKey 정도가 모든 브라우저에서 똑같이 작동합니다.

이벤트를 코드에서 "생성"할 수도 있습니다.

$('#test12').click();

이벤트를 해제시키고 싶을 땐 unbind() 메소드를 씁니다.

// 두번째 인자로 함수를 줄 수도 있음. $('.test').unbind('mouseup'); $('.test').unbind();

Ajax

애니메이션