이 섹션에서는 자바스크립트에 대한 약간의 배경 정보를 제공하여 그것이 왜 그런지 이해하도록 도와줍니다.
ECMAScript은 자바스크립트의 공식 이름이다. 자바스크립트에 상표가 있기 때문에 새로운 이름이 필요해졌다. 현재 모질라는 자바스크립트 이름을 오랫동안 라이선스를 받았기 때문에 공식적으로 사용할 수 있는 몇 안 되는 회사 중 하나입니다. 일반적인 사용에 대해서는 다음과 같은 규칙이 적용됩니다.
자바스크립트의 창시자 브렌던 아이히는 언어를 매우 빠르게 만들 수밖에 없었다. 그는 여러 프로그래밍 언어에서 자바 (합법, 원시 값 대 객체), 스키마 및 AWK (첫 번째 클래스 함수), 셀프 (원형 상속), 그리고 펄과 파이썬 ( 문자열, 배열 및 정규 표현식) 을 빌렸다.
자바스크립트는 ECMAScript 3까지 예외 처리가 없었고, 이것이 왜 언어가 자주 자동으로 값을 변환하고 종종 침묵으로 실패하는지 설명합니다. 처음에는 예외를 던질 수 없었습니다.
한편으로는 자바스크립트에는 특이한 점이 있으며 기능이 상당히 부족합니다. (블록 범위 변수, 모듈, 하위 클래스 지원 등). 다른 한편으로는 이러한 문제를 해결 할 수있는 몇 가지 강력한 기능이 있습니다. 다른 언어에서는 언어 기능을 배우게됩니다. 자바스크립트에서는 패턴을 자주 배우게됩니다.
그 영향력을 감안할 때 자바스크립트가 함수형 프로그래밍 (높은 계층의 함수, 내장된 맵, 리듀스 등) 과 객체 지향 프로그래밍 (물질, 상속) 을 혼합한 프로그래밍 스타일을 가능하게 하는 것은 놀라운 일이 아닙니다.
이 섹션에서는 자바스크립트의 기본 문법 원리를 설명합니다.
문법의 몇 가지 예:
// Two slashes start single-line comments
var x; // declaring a variable
x = 3 + y; // assigning a value to the variable `x`
foo(x, y); // calling function `foo` with parameters `x` and `y`
obj.bar(3); // calling method `bar` of object `obj`
// A conditional statement
if (x === 0) { // Is `x` equal to zero?
x = 123;
}
// Defining function `baz` with parameters `a` and `b`
function baz(a, b) {
return a + b;
}
동일 표시의 두 가지 다른 용도에 주목하십시오.
자바스크립트의 문법을 이해하기 위해서는 두 가지 주요 문법 범주를 알고 있어야 합니다.
var foo;
3 * 7
명령어와 표현식의 차이점은 자바스크립트가 if-then-else
var x;
if (y >= 0) {
x = y;
} else {
x = -y;
}
또는 표현으로:
var x = y >= 0 ? y : -y;
후자를 함수 인수로 사용할 수 있습니다 (하지만 전자를 사용하지 않습니다):
myFunction(y >= 0 ? y : -y)
마지막으로, 자바스크립트가 문장을 기대하는 곳이라면, 당신은 또한 표현식을 사용할 수 있습니다. 예를 들어:
foo(7, 1);
전체 선은 명령어 (표현 명령어라고 불리는) 이지만 함수 호출 foo ((7, 1) 는 표현식입니다.
세미콜론은 자바스크립트에서 선택 사항입니다. 그러나, 나는 항상 그들을 포함하는 것이 좋습니다, 그렇지 않으면 자바스크립트는 명령어 끝에 대해 잘못 추측 할 수 있습니다. 세부 사항은 자동 세미콜론 삽입에 설명됩니다.
세미콜론은 명령어를 끝내는 것이지만 블록은 아닙니다. 블록 뒤에 세미콜론을 볼 수있는 한 가지 경우가 있습니다: 함수 표현식은 블록으로 끝나는 표현식입니다. 그러한 표현식이 명령어에서 마지막으로 나오면 세미콜론이 따릅니다.
// Pattern: var _ = ___;
var x = 3 * 7;
var f = function () { }; // function expr. inside var decl.
자바스크립트는 두 가지 유형의 댓글을 가지고 있습니다. 단선 댓글과 다선 댓글. 단선 댓글은 //로 시작되고 라인의 끝으로 종료됩니다.
x++; // single-line comment
여러 줄의 댓글은 /*와 */로 구분됩니다.
/* This is
a multiline
comment.
*/
자바스크립트의 변수는 사용 전에 선언됩니다.
var foo; // declare variable `foo`
변수를 선언하고 값을 동시에 할당할 수 있습니다.
var foo = 6;
또한 기존 변수에 값을 할당할 수 있습니다:
foo = 4; // change variable `foo`
+=과 같은 복합 할당 연산자가 있습니다. 다음 두 가지 할당은 동등합니다:
x += 1;
x = x + 1;
식별자는 자바스크립트에서 다양한 문법적 역할을 수행하는 이름이다. 예를 들어 변수의 이름은 식별자이다. 식별자는 대소문자로 민감하다.
대략적으로, 식별자의 첫 문자는 유니코드 문자, 달러 기호 ($), 또는 하부점 (_) 이 될 수 있다. 다음 문자는 추가로 유니코드 숫자가 될 수 있다. 따라서 다음과 같은 모든 법적 식별자:
arg0
_tmp
$elem
π
다음 식별자는 예약 된 단어입니다. 그들은 문법의 일부이며 변수 이름 (함수 이름 및 매개 변수 이름) 으로 사용할 수 없습니다.
다음 세 개의 식별자는 예약 된 단어는 아니지만, 당신은 그들이있는 것처럼 그들을 취급해야합니다:
마지막으로, 표준 글로벌 변수의 이름에서 멀리 떨어져 있어야 합니다. 당신은 아무것도 깨지 않고 로컬 변수에 사용할 수 있습니다. 하지만 당신의 코드는 여전히 혼란 스럽습니다.
자바스크립트는 프로그래밍 언어에서 기대하는 많은 값을 가지고 있습니다. 부엘, 숫자, 문자열, 배열 등이 있습니다. 자바스크립트의 모든 값에는 속성이 있습니다. 각 속성은 키 (또는 이름) 와 값을 가지고 있습니다. 당신은 레코드의 필드와 같은 속성을 생각할 수 있습니다. 당신은 지점 (.) 연산자를 사용하여 속성을 읽을 수 있습니다:
value.propKey
예를 들어, 문자열
> var str = 'abc';
> str.length
3
앞부분은 다음과 같이 쓸 수 있습니다.
> 'abc'.length
3
The dot operator is also used to assign a value to a property:
> var obj = {}; // empty object
> obj.foo = 123; // create property `foo`, set it to 123
123
> obj.foo
123
메소드를 호출할 수 있습니다.
> 'hello'.toUpperCase()
'HELLO'
이전 예제에서, 우리는 값
자바스크립트는 값들을 다소 임의로 구분합니다.
> var obj1 = {}; // an empty object
> var obj2 = {}; // another empty object
> obj1 === obj2
false
> obj1 === obj1
true
반대로, 동일한 값을 암호화하는 모든 원시 값은 동일하다고 간주됩니다:
> var prim1 = 123;
> var prim2 = 123;
> prim1 === prim2
true
다음 두 섹션에서는 원시적 값과 객체를 더 자세히 설명합니다.
다음은 모든 원시적 값 (또는 짧은 원시적 값) 이다:
원시적인 것은 다음과 같은 특징을 가지고 있습니다.
> 3 === 3
true
> 'abc' === 'abc'
true
♪ 항상 변함없는 ♪ 속성은 변경, 추가 또는 제거 할 수 없습니다:
> var str = 'abc';
> str.length = 1; // try to change property `length`
> str.length // ⇒ no effect
3
> str.foo = 3; // try to create property `foo`
> str.foo // ⇒ no effect, unknown property
undefined
(알리지 않는 속성을 읽는 것은 항상 정의되지 않은 것을 반환합니다.)
모든 비원형 값은 객체입니다. 가장 일반적인 유형의 객체는 다음과 같습니다.
{
firstName: 'Jane',
lastName: 'Doe'
}
앞의 객체는 두 가지 속성을 가지고 있습니다: firstName 속성의 값은
[ 'apple', 'banana', 'cherry' ]
이전 배열은 숫자 인덱스를 통해 액세스 할 수있는 세 가지 요소가 있습니다. 예를 들어,
/^a+b+$/
물체는 다음과 같은 특징을 가지고 있습니다.
정체성은 비교됩니다. 모든 값은 자신의 정체성을 가지고 있습니다.
> ({} === {}) // two different empty objects
false
> var obj1 = {};
> var obj2 = obj1;
> obj1 === obj2
true
일반적으로 속성을 자유롭게 변경, 추가 및 제거할 수 있습니다.
> var obj = {};
> obj.foo = 123; // add property `foo`
> obj.foo
123
대부분의 프로그래밍 언어는 누락된 정보를 표시하는 값을 가지고 있습니다. 자바스크립트는 두 가지와 같은
> var foo;
> foo
undefined
빠진 매개 변수는 정의되지 않았습니다.
> function f(x) { return x }
> f()
undefined
존재하지 않는 속성을 읽으면 정의되지 않습니다.
> var obj = {}; // empty object
> obj.foo
undefined
undefined와 null는 속성이 없고 toString 같은 표준 메소드도 없습니다.
함수들은 일반적으로 미흡한 값을 undefined 또는 null로 표시할 수 있습니다.
if (x === undefined || x === null) {
...
}
또한 undefined와 null을 모두 거짓으로 간주한다는 사실을 활용할 수 있습니다.
if (!x) {
...
}
false, 0, NaN, 그리고
값을 분류하는 데는 두 가지 연산자가 있습니다. typeof는 주로 원시 값에 사용되며 instanceof는 객체에 사용됩니다. 이런 모양이네요.
typeof value
값의
> typeof true
'boolean'
> typeof 'abc'
'string'
> typeof {} // empty object literal
'object'
> typeof [] // empty array literal
'object'
다음 표에서는 모든 결과의 유형을 나열합니다.
typeof null 반환
예를 들어 이렇게 보입니다.
value instanceof Constr
값이 컨스트럭터 Constr (Constructors: Factories for Objects 참조) 에 의해 생성된 객체라면 true를 반환합니다. 몇 가지 예는 다음과 같습니다:
> var b = new Bar(); // object created by constructor Bar
> b instanceof Bar
true
> {} instanceof Object
true
> [] instanceof Array
true
> [] instanceof Object // Array is a subconstructor of Object
true
> undefined instanceof Object
false
> null instanceof Object
false
원시적인 부울형은 true 및 false 값을 포함합니다. 다음 연산자는 부울형을 생성합니다:
자바스크립트에서 부울값을 기대할 때 (예: if 문장의 조건에 대해), 어떤 값도 사용할 수 있습니다. true 또는 false로 해석됩니다. 다음 값은 false로 해석됩니다:
다른 모든 값 (모든 객체 포함!) 은 사실로 간주됩니다. 거짓으로 해석 된 값은 거짓이라고, 진실으로 해석 된 값은 진실이라고합니다. 함수로 호출되는 룰리언 (() 은 매개 변수를 룰리언으로 변환합니다. 값을 해석하는 방법을 테스트하는 데 사용할 수 있습니다:
> Boolean(undefined)
false
> Boolean(0)
false
> Boolean(3)
true
> Boolean({}) // empty object
true
> Boolean([]) // empty array
true
자바스크립트의 이진 논리 연산자는 단회로입니다. 즉, 첫 번째 연산자가 결과를 결정하기에 충분하다면 두 번째 연산자가 평가되지 않습니다. 예를 들어 다음 표현식에서 함수 foo() 는 결코 호출되지 않습니다.
false && foo()
true || foo()
또한, 이진 논리 연산자는 그 연산자 중 하나를 반환한다. 이는 부울 연산자일 수도 있고 아닐 수도 있다. 어느 연산자인지 결정하기 위해 진실성 검사가 사용됩니다.
첫 번째 연산자가 거짓이라면, 반환합니다. 그렇지 않으면, 두 번째 연산자를 반환합니다:
> NaN && 'abc'
NaN
> 123 && 'abc'
'abc'
첫 번째 연산자가 사실이라면 반환합니다. 그렇지 않으면 두 번째 연산자를 반환합니다.
> 'abc' || 123
'abc'
> '' || 123
123
자바스크립트는 두 가지 종류의 평등을 가지고 있습니다.
정상평등은 (너무) 많은 값을 동등하게 간주합니다. (정상적인 (완성) 평등 (==,!=) 에서 세부 사항을 설명합니다.) 이는 버그를 숨길 수 있습니다. 따라서 항상 엄격한 평등을 사용하는 것이 좋습니다.
자바스크립트의 모든 숫자는 부동 소수점입니다.
> 1 === 1.0
true
특별 번호는 다음을 포함합니다:
NaN (
> Number('xyz') // 'xyz' can’t be converted to a number
NaN
무한 또한 대부분 오류 값:
> 3 / 0
Infinity
> Math.pow(2, 1024) // number too large
Infinity
인피니티는 다른 어떤 숫자보다 크다 (NaN을 제외하면). 마찬가지로, -인피니티는 다른 어떤 숫자보다 작다 (NaN을 제외하면). 이것은 이 숫자를 기본 값으로 유용하게 만듭니다 (예를 들어, 최소 또는 최대값을 찾고 있을 때).
자바스크립트는 다음과 같은 수학적 연산자를 가지고 있습니다 (수학적 연산자를 참조하십시오):
글로벌 객체 수학 (수학을 참조) 은 함수를 통해 더 많은 수학적 연산을 제공합니다.
자바스크립트에는 또한 비트와이즈 연산에 대한 연산자가 있습니다 (예를 들어, 비트와이즈 앤; 비트와이즈 연산자를 참조하십시오).
문자열은 문자열 리터얼을 통해 직접 생성할 수 있습니다. 그 리터얼은 단일 또는 이중 인용구로 구분됩니다. 역 슬래시 () 는 문자를 탈출하고 몇 개의 제어 문자를 생성합니다. 다음은 몇 가지 예입니다:
'abc'
"abc"
'Did she say "Hello"?'
"Did she say \"Hello\"?"
'That\'s nice!'
"That's nice!"
'Line 1\nLine 2' // newline
'Backlash: \\'
단 한 문자는 괄호를 통해 액세스 합니다:
> var str = 'abc';
> str[1]
'b'
속성 길이는 문자열의 문자수를 계산합니다.
> 'abc'.length
3
모든 원시자처럼 문자열은 변하지 않습니다. 기존 문자열을 바꾸려면 새로운 문자열을 만들어야 합니다.
문자열은 플러스 (+) 연산자를 통해 연계되며, 다른 연산자 중 하나가 문자열이라면 다른 연산자를 문자열로 변환합니다.
> var messageCount = 3;
> 'You have ' + messageCount + ' messages'
'You have 3 messages'
여러 단계로 문자열을 연결하려면 += 연산자를 사용하세요:
> var str = '';
> str += 'Multiple ';
> str += 'pieces ';
> str += 'are concatenated.';
> str
'Multiple pieces are concatenated.'
문자열에는 많은 유용한 메소드가 있습니다 (String Prototype Methods 참조). 다음은 몇 가지 예입니다:
> 'abc'.slice(1) // copy a substring
'bc'
> 'abc'.slice(1, 2)
'b'
> '\t xyz '.trim() // trim whitespace
'xyz'
> 'mjölnir'.toUpperCase()
'MJÖLNIR'
> 'abc'.indexOf('b') // find a string
1
> 'abc'.indexOf('x')
-1
자바스크립트의 조건 및 루프는 다음 섹션에서 소개됩니다.
if 명령어는 then 문장과 선택적인 else 문장을 가지고 있으며 이는 부울 조건에 따라 실행됩니다.
if (myvar === 0) {
// then
}
if (myvar === 0) {
// then
} else {
// else
}
if (myvar === 0) {
// then
} else if (myvar === 1) {
// else-if
} else if (myvar === 2) {
// else-if
} else {
// else
}
나는 항상 브래시스를 사용하는 것을 추천합니다. (그들은 0 또는 더 많은 명령어 블록을 나타냅니다.) 그러나 단어가 하나의 명령어일 경우 그렇게 할 필요가 없습니다.
if (x < 0) return -x;
다음은 스위치 명령어입니다. 과일의 값은 어떤 케이스가 실행되는지를 결정합니다.
switch (fruit) {
case 'banana':
// ...
break;
case 'apple':
// ...
break;
default: // all other cases
// ...
}
for 루프는 다음과 같은 형식을 가지고 있습니다.
for (⟦«init»⟧; ⟦«condition»⟧; ⟦«post_iteration»⟧)
«statement»
init는 루프의 시작에서 실행됩니다. condition은 각 루프 반복 전에 확인됩니다. false가 되면 루프가 종료됩니다. post_iteration은 각 루프 반복 후에 실행됩니다.
이 예제에서 콘솔에 배열 arr의 모든 요소를 인쇄합니다:
for (var i=0; i < arr.length; i++) {
console.log(arr[i]);
}
while 루프는 그 상태가 유지되는 동안 그 몸 위에 계속 루프를 계속합니다.
// Same as for loop above:
var i = 0;
while (i < arr.length) {
console.log(arr[i]);
i++;
}
듀-웨일링 루프는 상태가 유지되는 동안 몸 위에 계속 루프를 계속합니다. 상태가 몸을 따라가기 때문에 몸은 항상 적어도 한 번 실행됩니다.
do {
// ...
} while (condition);
모든 루프에서:
함수를 정의하는 한 가지 방법은 함수 선언을 통해:
function add(param1, param2) {
return param1 + param2;
}
앞의 코드는 두 개의 매개 변수인 param1과 param2를 가진 함수를 정의합니다. 그리고 두 매개 변수의 합을 반환합니다.
> add(6, 1)
7
> add('a', 'b')
'ab'
더하기 (add) 를 정의하는 또 다른 방법은 변수 add에 함수 표현식을 부여하는 것입니다:
var add = function (param1, param2) {
return param1 + param2;
};
함수 표현식은 값을 생성하고 따라서 함수를 다른 함수로 인수로 직접 전달하는 데 사용할 수 있습니다.
someOtherFunction(function (p1, p2) { ... });
함수 선언은 전체적으로 현재 범위의 시작으로 이동됩니다. 이것은 나중에 선언 된 함수를 참조 할 수 있습니다.
function foo() {
bar(); // OK, bar is hoisted
function bar() {
...
}
}
또한 var 선언이 들어간다는 점에 유의하십시오 (변수들이 들어간다는 것을 참조하십시오).
function foo() {
bar(); // Not OK, bar is still undefined
var bar = function () {
// ...
};
}
자바스크립트에서 임의의 수의 논리로 어떤 함수를 호출할 수 있습니다. 언어는 결코 불평하지 않을 것입니다. 그러나 모든 매개 변수를 특수 변수 논증으로 사용할 수 있습니다.
> function f() { return arguments }
> var args = f('a', 'b', 'c');
> args.length
3
> args[0] // read element at index 0
'a'
자바스크립트에서 너무 많은 또는 너무 적은 매개 변수가 처리되는 방법을 탐구하기 위해 다음 함수를 사용해보자 (toArray( 함수는 Array로 인수를 변환하는 데 표시됩니다):
function f(x, y) {
console.log(x, y);
return toArray(arguments);
}
추가 매개 변수들은 무시됩니다 (항변을 제외하면):
> f('a', 'b', 'c')
a b
[ 'a', 'b', 'c' ]
빠진 매개 변수는 값을 정의하지 않습니다:
> f('a')
a undefined
[ 'a' ]
> f()
undefined undefined
[]
다음은 매개 변수에 기본값을 부여하는 일반적인 패턴입니다.
function pair(x, y) {
x = x || 0; // (1)
y = y || 0;
return [ x, y ];
}
줄 (1) 에서, "선" 연산자는 true (무 null, undefined, 등) 이면 x를 반환한다. 그렇지 않으면 두 번째 연산자를 반환한다.
> pair()
[ 0, 0 ]
> pair(3)
[ 3, 0 ]
> pair(3, 5)
[ 3, 5 ]
arity (특정 수의 매개 변수) 를 강제하려면 arguments.length를 확인할 수 있습니다.
function pair(x, y) {
if (arguments.length !== 2) {
throw new Error('Need exactly 2 arguments');
}
...
}
arguments는 배열이 아니라 배열과 비슷합니다 (Array-Like Objects and Generic Methods를 참조하십시오). 그것은 속성 길이가 있으며, 당신은 사각형 괄호에 있는 인덱스를 통해 그것의 요소에 액세스할 수 있습니다. 그러나 당신은 요소를 제거하거나 그 위에 배열 방법 중 하나를 호출할 수 없습니다. 따라서 때때로 당신은 배열으로 배열을 변환해야 합니다. 이것은 다음 함수가 하는 것입니다 (Array-Like Objects and Generic Methods에서 설명됩니다):
function toArray(arrayLikeObject) {
return Array.prototype.slice.call(arrayLikeObject);
}
예외를 처리하는 가장 일반적인 방법 (목적 14) 은 다음과 같습니다.
function getPerson(id) {
if (id < 0) {
throw new Error('ID must not be negative: '+id);
}
return { id: id }; // normally: retrieved from database
}
function getPersons(ids) {
var result = [];
ids.forEach(function (id) {
try {
var person = getPerson(id);
result.push(person);
} catch (exception) {
console.log(exception);
}
});
return result;
}
try 조항은 중요한 코드를 둘러싸고, catch 조항은 try 조항 안에 예외가 던져지면 실행됩니다. 이전 코드를 사용하여:
> getPersons([2, -5, 137])
[Error: ID must not be negative: -5]
[ { id: 2 }, { id: 137 } ]
엄격 모드 (Strict Mode) 는 더 많은 경고를 가능하게 하고 자바스크립트를 더 깨끗한 언어로 만듭니다.
'use strict';
또한 함수별로 엄격한 모드를 활성화할 수 있습니다:
function functionInStrictMode() {
'use strict';
}
자바스크립트에서는 변수를 사용하기 전에 var를 통해 변수를 선언합니다.
> var x;
> x
undefined
> y
ReferenceError: y is not defined
하나의 var 명령어로 여러 변수를 선언하고 초기화할 수 있습니다.
var x = 1, y = 2, z = 3;
하지만 변수당 하나의 문장을 사용하는 것이 좋습니다. 그래서 이전 문장을 다시 써서
var x = 1;
var y = 2;
var z = 3;
호스팅 때문에 (변수들이 호스팅되는 것을 참조), 일반적으로 함수의 시작에서 변수를 선언하는 것이 가장 좋습니다.
변수의 범위는 항상 완전한 함수 (현재 블록과 달리) 이다. 예를 들어:
function foo() {
var x = -512;
if (x < 0) { // (1)
var tmp = -x;
...
}
console.log(tmp); // 512
}
우리는 변수 tmp가 줄 (1) 에서 시작하는 블록에 국한되지 않는다는 것을 볼 수 있습니다. 그것은 함수의 끝까지 존재합니다.
각 변수 선언은 들어갑니다: 선언은 함수의 시작으로 이동하지만, 할당하는 작업은 계속됩니다. 예를 들어 다음 함수에서 줄 (1) 의 변수 선언을 고려하십시오.
function foo() {
console.log(tmp); // undefined
if (false) {
var tmp = 3; // (1)
}
}
내부적으로, 이전 함수는 다음과 같이 실행됩니다.
function foo() {
var tmp; // hoisted declaration
console.log(tmp);
if (false) {
tmp = 3; // assignment stays put
}
}
각각의 함수는 그것을 둘러싸고 있는 함수의 변수와 연결되어 있다. 예를 들어:
function createIncrementor(start) {
return function () { // (1)
start++;
return start;
}
}
(1) 줄에서 시작하는 함수는 생성된 맥락을 떠나지만 시작의 라이브 버전과 연결되어 있습니다.
> var inc = createIncrementor(5);
> inc()
6
> inc()
7
> inc()
8
클로저는 함수와 그 주변 범위의 변수와의 연결을 더하는 함수입니다. 따라서 createIncrementor() 는 클로저를 반환합니다.
때로는 새로운 변수 범위를 도입하고 싶을 수도 있습니다. 예를 들어, 변수가 글로벌화되는 것을 막기 위해. 자바스크립트에서는 블록을 사용할 수 없습니다. 함수를 사용해야합니다. 그러나 블록과 같은 방식으로 함수를 사용하는 패턴이 있습니다. 그것은 IIFE (제시적으로 호출 된 함수 표현, 발음
(function () { // open IIFE
var tmp = ...; // not a global variable
}()); // close IIFE
앞의 예제를 정확히 표시된 대로 입력하는 것을 확인하십시오. IIFE는 당신이 정의 한 직후에 호출되는 함수 표현식입니다. 함수 내부에는 새로운 범위가 존재하여 tmp가 글로벌화되는 것을 방지합니다. IIFE를 통해 새로운 범위를 소개하는 것을 참조하십시오.
폐쇄는 외부 변수와 연결을 유지합니다.
var result = [];
for (var i=0; i < 5; i++) {
result.push(function () { return i }); // (1)
}
console.log(result[1]()); // 5 (not 1)
console.log(result[3]()); // 5 (not 3)
행 (1) 에서 반환되는 값은 항상 함수의 생성 당시의 값이 아니라 i의 현재 값입니다. 루프가 끝나면 i는 값 5을 가지게 됩니다. 그래서 배열의 모든 함수가 그 값을 반환합니다. 행 (1) 에서 함수가 i의 현재 값의 스냅샷을 받기를 원한다면 IIFE를 사용할 수 있습니다:
for (var i=0; i < 5; i++) {
(function () {
var i2 = i; // copy current i
result.push(function () { return i2 });
}());
}
이 섹션에서는 자바스크립트의 두 가지 기본 객체 지향 메커니즘을 다루고 있습니다. 단일 객체와 구성 요소 (다른 언어의 클래스와 유사한 객체 공장) 입니다.
모든 값과 마찬가지로 객체에도 속성이 있습니다. 사실, 객체를 속성 집합으로 간주할 수 있습니다. 각각의 속성은 (키, 값) 쌍입니다. 키는 문자열이고 값은 자바스크립트 값입니다.
자바스크립트에서는 객체 리터얼을 통해 일반 객체를 직접 만들 수 있습니다.
'use strict';
var jane = {
name: 'Jane',
describe: function () {
return 'Person named '+this.name;
}
};
이전 객체는 속성 이름과 설명이 있습니다. 당신은 (
> jane.name // get
'Jane'
> jane.name = 'John'; // set
> jane.newProperty = 'abc'; // property created automatically
describe와 같은 함수 값의 속성은 메소드라고 불립니다. 그들은 이것을 호출하는 데 사용되는 객체를 참조하기 위해 사용합니다.
> jane.describe() // call method
'Person named John'
> jane.name = 'Jane';
> jane.describe()
'Person named Jane'
in 연산자는 속성이 존재하는지 확인합니다:
> 'newProperty' in jane
true
> 'foo' in jane
false
만약 당신이 존재하지 않는 속성을 읽으면, 당신은 정의되지 않은 값을 얻습니다. 따라서 이전 두 가지 검사는 다음과 같이 수행될 수 있습니다.
> jane.newProperty !== undefined
true
> jane.foo !== undefined
false
삭제 연산자는 속성을 제거합니다:
> delete jane.newProperty
true
> 'newProperty' in jane
false
속성 키는 어떤 문자열도 될 수 있습니다. 지금까지 우리는 객체 리터럴과 점 연산자 뒤에 속성 키를 보았습니다. 그러나 식별자가 될 경우에만 그렇게 사용할 수 있습니다. 다른 문자열을 키로 사용하려면 객체 리터럴에 인용하고 사각형 괄호를 사용하여 속성을 얻어서 설정해야합니다.
> var obj = { 'not an identifier': 123 };
> obj['not an identifier']
123
> obj['not an identifier'] = 456;
제곱괄호는 또한 속성의 키를 계산할 수 있습니다.
> var obj = { hello: 'world' };
> var x = 'hello';
> obj[x]
'world'
> obj['hel'+'lo']
'world'
메소드를 추출하면 객체와의 연결을 잃습니다. 그 자체로 함수는 더 이상 메소드가 아니며 정의되지 않은 값이 있습니다.
예를 들어, 이전 객체 jane로 돌아가 봅시다:
'use strict';
var jane = {
name: 'Jane',
describe: function () {
return 'Person named '+this.name;
}
};
우리는 jane에서 describe 메소드를 추출하고, 변수 func에 넣고, 호출하고 싶습니다. 하지만, 그것은 작동하지 않습니다:
> var func = jane.describe;
> func()
TypeError: Cannot read property 'name' of undefined
모든 함수들이 가지고 있는 bind() 메소드를 사용하는 것이 해결책이다. 이것은 항상 주어진 값을 가진 새로운 함수를 만듭니다:
> var func2 = jane.describe.bind(jane);
> func2()
'Person named Jane'
모든 함수에는 고유의 특수 변수 this가 있습니다. 이 함수가 메소드 안에 네스트되면 불편합니다. 왜냐하면 함수에서 메소드 this에 액세스 할 수 없기 때문입니다. 다음 예는 함수와 함께 forEach를 호출하여 배열을 반복하는 것입니다.
var jane = {
name: 'Jane',
friends: [ 'Tarzan', 'Cheeta' ],
logHiToFriends: function () {
'use strict';
this.friends.forEach(function (friend) {
// `this` is undefined here
console.log(this.name+' says hi to '+friend);
});
}
}
로그HiToFriends를 호출하면 오류가 발생합니다.
> jane.logHiToFriends()
TypeError: Cannot read property 'name' of undefined
이 문제를 해결하는 두 가지 방법을 살펴보겠습니다. 첫째, 다른 변수에 저장할 수 있습니다.
logHiToFriends: function () {
'use strict';
var that = this;
this.friends.forEach(function (friend) {
console.log(that.name+' says hi to '+friend);
});
}
또는, forEach는 두 번째 매개 변수를 가지고 있습니다.
logHiToFriends: function () {
'use strict';
this.friends.forEach(function (friend) {
console.log(this.name+' says hi to '+friend);
}, this);
}
함수 표현식은 종종 자바스크립트에서 함수 호출에서 인수로 사용됩니다. 항상 이러한 함수 표현식 중 하나를 참조 할 때 조심하십시오.
지금까지, 당신은 자바스크립트 객체가 문자열에서 값에 대한 지도에 불과하다고 생각할 수 있습니다. 다른 언어의 지도/사전을 닮은 자바스크립트 객체 리터럴에 의해 제안된 개념입니다. 그러나 자바스크립트 객체는 또한 진정으로 객체 지향적인 기능인 상속을 지원합니다. 이 섹션에서는 자바스크립트 상속이 어떻게 작동하는지 완전히 설명하지는 않지만 시작하기 위해 간단한 패턴을 보여줍니다. 더 알고 싶다면 17 장을 참조하십시오.
함수들은
// Set up instance data
function Point(x, y) {
this.x = x;
this.y = y;
}
// Methods
Point.prototype.dist = function () {
return Math.sqrt(this.x*this.x + this.y*this.y);
};
우리는 구성 요소가 두 가지 부분을 가지고 있음을 볼 수 있습니다. 첫째, 함수 포인트가 인스턴스 데이터를 설정합니다. 둘째, 속성 Point.prototype는 메소드를 가진 객체를 포함합니다. 전자는 각 인스턴스에 특이하며 후자는 모든 인스턴스 사이에서 공유됩니다.
포인트를 사용하려면 새로운 연산자를 통해 호출합니다.
> var p = new Point(3, 5);
> p.x
3
> p.dist()
5.830951894845301
p는 포인트의 인스턴스입니다:
> p instanceof Point
true
배열은 0에서 시작하는 정수 인덱스를 통해 액세스 할 수있는 요소의 연속입니다.
배열 리터럴은 배열을 만드는 데 유용합니다.
> var arr = [ 'a', 'b', 'c' ];
전 배열에는 세 가지 요소가 있습니다: 문자열
> arr[0]
'a'
> arr[0] = 'x';
> arr
[ 'x', 'b', 'c' ]
length 속성은 배열이 얼마나 많은 요소를 가지고 있는지 나타냅니다. 요소를 추가하고 제거하는 데 사용할 수 있습니다:
> var arr = ['a', 'b'];
> arr.length
2
> arr[arr.length] = 'c';
> arr
[ 'a', 'b', 'c' ]
> arr.length
3
> arr.length = 1;
> arr
[ 'a' ]
in 연산자는 배열에서도 작동합니다.
> var arr = [ 'a', 'b', 'c' ];
> 1 in arr // is there an element at index 1?
true
> 5 in arr // is there an element at index 5?
false
배열은 객체이고 따라서 객체 속성을 가질 수 있다는 점에 유의하십시오.
> var arr = [];
> arr.foo = 123;
> arr.foo
123
배열에는 여러 가지 방법이 있습니다. 몇 가지 예는 다음과 같습니다.
> var arr = [ 'a', 'b', 'c' ];
> arr.slice(1, 2) // copy elements
[ 'b' ]
> arr.slice(1)
[ 'b', 'c' ]
> arr.push('x') // append an element
4
> arr
[ 'a', 'b', 'c', 'x' ]
> arr.pop() // remove last element
'x'
> arr
[ 'a', 'b', 'c' ]
> arr.shift() // remove first element
'a'
> arr
[ 'b', 'c' ]
> arr.unshift('x') // prepend an element
3
> arr
[ 'x', 'b', 'c' ]
> arr.indexOf('b') // find the index of an element
1
> arr.indexOf('y')
-1
> arr.join('-') // all elements in a single string
'x-b-c'
> arr.join('')
'xbc'
> arr.join()
'x,b,c'
요소를 반복하는 데 몇 가지 배열 방법이 있습니다. 두 가지 가장 중요한 것은 forEach 및 map입니다.
forEach는 배열을 반복하여 현재 요소와 그 인덱스를 함수로 전달합니다.
[ 'a', 'b', 'c' ].forEach(
function (elem, index) { // (1)
console.log(index + '. ' + elem);
});
앞의 코드는 다음과 같은 출력을 생성합니다.
0. a
1. b
2. c
라인 (1) 의 함수는 인수를 무시할 수 있습니다. 예를 들어, 매개 변수 elem만 가질 수 있습니다.
map는 기존 배열의 각 요소에 함수를 적용하여 새로운 배열을 만듭니다.
> [1,2,3].map(function (x) { return x*x })
[ 1, 4, 9 ]
자바스크립트는 정규 표현식을 지원합니다.
/^abc$/
/[A-Za-z0-9]+/
> /^a+b+$/.test('aaab')
true
> /^a+b+$/.test('aaa')
false
> /a(b+)a/.exec('_abbba_aba_')
[ 'abbba', 'bbb' ]
반환 배열은 인덱스 0에서 완전한 일치, 인덱스 1에서 첫 번째 그룹의 캡처 등을 포함합니다. 모든 일치를 얻기 위해이 방법을 반복적으로 호출하는 방법이 있습니다.
> '<a> <bbb>'.replace(/<(.*?)>/g, '[$1]')
'[a] [bbb]'
replace의 첫 번째 매개 변수는 /g 플래그를 가진 정규 표현식이어야 합니다. 그렇지 않으면 첫 번째 발생자만 교체됩니다. 또한 (String.prototype.replace: 검색 및 교체에서 논의 된 바와 같이) 대체를 계산하는 함수를 사용하는 방법이 있습니다.
수학은 수학적 함수를 가진 객체입니다. 몇 가지 예는 다음과 같습니다.
> Math.abs(-2)
2
> Math.pow(3, 2) // 3 to the power of 2
9
> Math.max(2, -1, 5)
5
> Math.round(1.9)
2
> Math.PI // pre-defined constant for π
3.141592653589793
> Math.cos(Math.PI) // compute the cosine for 180°
-1