1. 용어의 이해
(1) 표현식과 문장
표현식은 값을 만들어내는 구문입니다. 예컨대
1234
1 + 2
'abc'
위 구문은 1234, 3, 'abc'의 값을 나타내므로 표현식이라 할 수 있습니다. 반면 문장은 이러한 표현식을 통해 실제 자바스크립트(javascript)의 구문을 아래와 같이 만든 것입니다.
var i = 1 + 2;
alert('값은 ' + i + '입니다.');
문법상 자바스크립트는 문장의 끝에 세미콜론(;)을 필요로 하지 않지만 C언어처럼 ;으로 끝나는 것이 관례입니다.
(2) 키워드
자바스크립트 내부에서 특정한 용도로 사용되는 단어들을 '키워드'라고 부릅니다.(자바스크립트뿐만 아니라 다른 언어들도 '키워드'라는 단어를 동일한 의미로 사용합니다.) 이를테면 var는 키워드 중 하나로서 변수를 선언할 때 사용됩니다. 이러한 키워드는 아래서 설명하고 있는 '키워드'로서는 단독으로 사용할 수 없습니다.
var i = 10;
일반적으로 자바스크립트에서는 아래의 단어들을 키워드로서 취급합니다.
break | case | catch | continue | default |
delete | do | else | false | finally |
for | function | if | in | instanceof |
new | null | return | switch | this |
throw | true | try | typeof | var |
void | while | with |
아래 단어들은 현재 키워드로 규정되어 있지는 않지만 향후에 키워드로 사용될 가능성이 있는 단어들입니다. 때문에 국제 웹 표준화 기구인 W3C에서는 아래 단어들을 되도록이면 사용하지 말게 권고하고 있습니다.
abstract | await | boolean | byte | char |
double | enum | final | float | goto |
implements | int | interface | long | native |
package | private | protected | public | short |
static | synchronized | throws | transient | volatile |
아래 단어는 처음에는 키워드가 아니었지만 2009년 당시 새로운 자바스크립트 표준이 발표될 때 키워드로 추가된 언어들입니다.
class | const | debugger | export | extends |
import | let | super | yield |
(3) 식별자
개발자가 직접 작성하는 변수나 함수 등의 이름을 '식별자'라고 합니다. 예를 들어
var i = 10;
이라고 하면 i가 식별자에 해당됩니다. 한마디로 이름을 지으면 그 이름이 식별자인 것입니다. 다만 식별자를 정할 때는 다음과 같은 규칙을 지켜야 합니다.
- 키워드는 식별자로 사용이 불가능합니다. 다만 키워드를 포함하는 단어는 가능합니다. 예를 들어 for 단어는 키워드이기에 식별자로 활용할 수 없지만 forage처럼 식별자를 포함하면서 식별자가 아닌 단어는 사용할 수 있습니다.
- 숫자를 사용할 수는 있지만 숫자로 시작할 수 없습니다.
- 특수문자는 _와 &만 사용할 수 있습니다.
- 공백은 사용할 수 없습니다.
참고로 한국어, 중국어, 일본어등 알파벳 이외의 다른 국가의 문자도 식별자로 사용될 수 있습니다. 하지만 권장하지는 않습니다.
식별자는 위에서 언급한 규칙만 지켜진다면 어떤 것이든 식별자로서 사용이 가능합니다. 다만, 강제적으로 규정된 것은 아니지만 관례상 다음과 같은 규칙이 추가적으로 존재합니다. 따르지 않아도 되지만 되도록이면 아래 규칙을 따라가는 것이 좋습니다.
- 생성자 함수는 대문자로 시작하도록 합니다.
- 변수, 함수, 메서드 등의 다른 이름은 소문자로 시작합니다.
- 여러 단어가 결합된 식별자의 경우 첫 단어를 제외하고 그다음 단어의 첫 글자를 대문자로 표시합니다. 예를 들어 image와 change, return단어를 결합하는 경우 imageChangeReturn처럼 표현합니다.
(4) 주석
아래 자바스크립트 구문중 //와 /* ~ */부분이 주석입니다.
/*
작성일 : 어제
작성자 : 홍길동
*/
var i = 0;
var j = 10;
alert(i + j); //결과표시
프로그램 처리와는 전혀 관련이 없으며 주로 프로그램 중간에 개발자의 코멘트를 넣는 용도로 사용됩니다. //한 줄 주석을 /* 에서 */ 까지는 여러 줄 주석으로 사용됩니다.
2. 데이터형
(1) 문자열
자바스크립트에서 문자열은 홀 따옴표(')나 쌍 따옴표(")로 감싸서 표현합니다.
var s = '안녕!';
var s = "안녕하세요!";
홀 따옴표/큰따옴표 어떤 것이든 사용할 수 있으며 문자열 안에서 홀 따옴표나 큰따옴표 자체를 표시하고자 한다면 본래 문자열 표현에 사용된 따옴표와는 다른 따옴표를 사용해야 합니다. 예컨대 홀 따옴표를 통해 문자열을 표현했다면
'안녕하세요'
큰따옴표를 통해 쌍 따옴표 자체를 표시하는 것으로 처리해야 합니다.
'"안녕"하세요'
또한 문자열 데이터를 다루다 보면 종종 이스케이프 문자를 사용해야 하는 경우가 있습니다. 이스케이프 문자는 \ 문자를 통해 본래 알파벳 대신 다른 의미를 부여하여 문자열 표현에 사용됩니다.
예를 들어 문자열에서 줄 바꿈을 구현하고자 한다면 다음과 같이 \n 이스케이프 문자를 사용합니다.
alert('안녕\n하세요.');
이외 다른 이스케이프 문자로는 다음과 같은 것들이 있습니다.
\t | 탭문자 |
\n | 줄바꿈 |
\' | 작은따음표 표현 |
\" | 쌍따옴표 표현 |
\\ | 역 슬래시 |
마자믹으로 문자열끼리의 연결은 덧셈기호를 사용해 처리합니다.
var h = '안녕';
h += '하세요.';
alert(h);
//또는
var h = '안녕';
alert(h + '하세요.');
+= 표시는 자기 자신에 우변 값을 더한다는 의미입니다.
기존에는 이렇게 문자열을 더하는 경우 +기호만으로 연결해야 했는데 문자열 연결과 관련해서 '템플릿 문자열'이라는 기능을 활용할 수도 있습니다.
예를 들어
특정 변수나 계산의 결과를 표현하기 위해서 아래와 같이 했다면
var i = 10;
alert('i의 값은 ' + i + ' 입니다.');
' 문자 대신 `문자로 문자열을 감싸고 내부에 표현하고자 하는 식을 ${}로 처리하면 복잡하게 +기호를 사용하지 않고도 깔끔하게 문자열을 표현할 수 있습니다.
var i = 10;
alert(`i의 값은 ${i} 입니다.`);
다만 이 방법은 마이크로소프트의 익스플로러에서는 사용할 수 없습니다.
(2) 숫자
1234나 78.9와 같은 것들을 숫자 데이터형으로 취급할 수 있습니다.
var i = 10;
var j = 7.8;
alert(i + j);
위에서 보듯 숫자 데이터형은 숫자이므로 기본적인 사칙연산이 가능합니다. 여러 숫자 데이터를 연산하는 경우 우선순위는 일반적인 사칙연산의 우선순위와 같지만 괄호를 사용해 가장 먼저 계산을 수행하도록 우선순위를 바꿀 수 있습니다.
var i = 2 * (3 + 1);
alert(i);
사직 연산과 다르게 % 는 나머지 연산은 수행합니다. 따라서 아래 코드는 6을 4로 나눈 나머지를 표시하게 됩니다.
var i = 6 % 4;
alert(i);
(3) 배열
배열은 여러 개의 값을 한꺼번에 다룰 수 있는 데이터형으로 대괄호([])를 사용해 다음과 같이 선언합니다.
var arr = ['a', 'b', 'c'];
위 예제에서 배열은 a, b, c 3개의 문자 요소가 있으며 배열 자체를 보려면 배 열명만 있으면 되지만
alert(arr);
배열 안에 요소에 개별적으로 접근하려면 대괄호를 통해 요소의 순서인 인덱스를 전달하면 됩니다.
alert(arr[1]);
예제에서 인덱스는 1로 설정했으며 요소의 시작은 0부터 시작하므로 1에 해당하는 b라는 문자를 출력하게 됩니다. 다음 예제는 인덱스 2(c)에 새로운 값을 설정하는 방법을 보여주고 있습니다.
var arr = ['a', 'b', 'c'];
arr[2] = 'd';
alert(arr[2]);
문자열의 경우에도 문자 배열로서 취급할 수 있습니다.
var arr = 'abcdefg';
alert(arr[3]);
따라서 상기 예제는 d를 출력합니다.
배열의 크기는 length속성을 사용하면 확인할 수 있으며 기존 배열에 요소를 추가하고자 한다면 push메서드를 사용합니다. (단 push는 문자열에서는 사용할 수 없습니다.)
var arr = [1, 2, 3, 4];
alert(arr.length); //요소가 4개 이므로 4를 출력
arr.push(5); //요소추가
alert(arr.length); //push로 요소를 추가했으므로 5을 출력
참고로 배열은 서로 다른 성격의 데이터형을 모두 포함할 수 있습니다.
var arr = [1, 'b', false, function () {}, [10, 20]];
alert(arr[4]);
예제에서 첫번째 요소는 숫자를, 두 번째는 문자를, 세 번째는 불평과 네 번째는 함수, 다섯 번째는 배열 자체를 요소로 설정하고 있습니다.
배열을 상대로 복사를 수행하면 얕은 복사라고 하여 원본과 복사본의 메모리주소를 같게 만드는 방법으로 복사를 수행합니다. 복사를 수행하는 시스템입장에서 이 방법은 복사를 위한 매우 효휼적인 방법이지만 원본의 값이 바뀌면 복사본의 값이 똑같이 바뀌는 현상을 겪에 됩니다.
그래서 기본적으로는 배열에 대해 값을 포함한 전체 복사(깊은 복사)를 수행하기 위해서 배열을 순회하며 일일이 값을 대입하는 방식으로 복사해야 합니다.
하지만 '전개연산자'라는것을 사용하면 쉽게 배열에 대해 깊은 복사를 수행할 수 있습니다.
var myArray = [1, 2, 3, 4, 5];
var myArray2 = [...myArray];
myArray[1] = 10;
alert(myArray2[1]);
심지어 다음과 같이 2개의 배열을 결합해 사용할 수 있으며
var myArray = [1, 2, 3, 4, 5];
var myArray2 = [10, 20, 30, 40, 50];
var myArray3 = [...myArray, ...myArray2];
동일한 방법으로 새로운 배열을 선언하면서 결합하는 것도 가능합니다.
var myArray = [1, 2, 3, 4, 5];
var myArray2 = [10, 20, 30, ...myArray];
전개 연산자에 대한 내용은 다음글을 참고바랍니다.
[Web/Javascript] - [javascript] 함수
마지막으로 배열은 구조분해할당이라고 해서 다음과 같은 방법으로 변수에 할당할 수 있습니다.
var myArray = [1, 2, 3, 4, 5];
var [ a, b, , , c ] = myArray;
위와 같이 하면 변수 a에 1, 변수 b에 2가 대입됩니다. 만약 배열에서 제외하고자 하는 배열값이 있다면 ,로 생략할 수 있으며 때문에 마지막 변수 c에는 5가 대입됩니다.
(4) bool(불)
불(bool)은 참/거짓을 표현하는 데 사용되며 true는 참, false는 거짓입니다. 아래 코드는 ==연산자를 통해 비교를 수행하고 있으며 i는 10이므로 true를 표시합니다.
var i = 10;
alert(i == 10);
참고로 비교 연산자는 다음과 같은 것들이 있습니다.
비교 연산자는 | |
단순 숫자뿐 아니라
alert(10 > 9); //결과 true
문자열에도 적용할 수 있으며
alert('a' > 'b'); //결과 false
이때는 유니코드 문자의 코드값을 기준으로 처리하게 됩니다.
불(bool) 자료형에서 알아두어야 할 중요한 연산자가 있는데 바로 논리 연산자라는 것입니다. 논리 연산자는 다음과 같은 것들이 있습니다.
! | 논리 부정 |
&& | 논리곱 |
|| | 논리합 |
논리 부정의 경우에는 참을 거짓으로 거짓을 참으로 뒤바꾸는 연산자입니다. 예컨대 아래 예제의 경우
alert(!(1 > 2)); //결과 true
1 보다는 2가 더 큰 수이므로 본래는 false가 되어야 하지만 앞에 논리 부정 연산자로 인해 false는 true로 바뀌게 되어 결과는 true가 됩니다.
논리곱은 비교대상이 모두 참인 경우에만 참이 되며 그 외에는 모두 거짓이 됩니다. 이를 표로 표현하면 다음과 같습니다.
비교대상1 | 비교대상2 | 결과 |
true | true | true |
true | false | false |
false | true | false |
false | false | false |
반면 논리합은 비교대 상중 단 하나라도 참이면 결과는 참이 되며 모두 거짓인 경우에만 결과가 거짓이 됩니다. 이를 표로 표현하면 다음과 같습니다.
비교대상1 | 비교대상2 | 결과 |
true | true | true |
true | false | true |
false | true | true |
false | false | false |
이외에 함수, 객체, undefined 자료형은 개별적으로 관련 내용을 다룰 때 알아보고자 합니다.
3. 변수
(1) 변수
특정 값을 저장하고자 하는 데 사용되며 다음과 같이 변수를 선언하고 저장할 값을 할당하는 방법으로 사용됩니다.
var i = 10; //var로 i변수를 선언하고 10의 값을 할당
var s = 'abc'; //var로 s변수를 선언하고 'abc'값을 할당
위와 같이 하나씩 변수를 할당하는 방법도 있고 다수의 변수를 선언해 할당하는 방법도 존재합니다.
var i, s;
i = 10;
s = 'abd';
//또는
var i = 10, s = 'abd';
또한 변수는 다음과 같이 여러 번 할당이 가능합니다.
var i = 10;
i = 20;
i = 30;
//또는
var i = 10;
var i = 20;
var i = 30;
이렇게 되면 마지막에 할당한 값이 30이 i에 남게 됩니다.
참고로 변수가 정수형인지 문자열형인지에 대한 데이터형은 변수에 값이 할당될 때 해당 값의 데이터 타입으로 결정됩니다. 만약 특정 데이터 값이나 변수의 데이터형이 어떤 것인지 확인해야 한다면 typeof를 연산자를 사용하면 됩니다.
var i = 10;
alert(typeof(i)); //i변수의 데이터형을 출력 -> number
alert(typeof('abc')); //abc값의 데이터형을 출력 -> string
참고로 변수를 선언만 하고 값을 할당하지 않은 채로 타입을 확인하게 되면 undefined가 출력됩니다. undefined도 하나의 데이터형으로 취급할 수 있으며 초기화하지 않은 데이터형을 의미합니다.
변수를 선언할 때는 var라는 키워드를 사용했는데 이것 이외에 const라는 키워드를 사용할 수도 있습니다.
const i = 10;
alert(i);
var로 변수를 선언하면 해당 변수의 값은 언제든지 바뀔 수 있지만 const로 변수를 선언하면 선언할 때의 초기값 이외에 다른 값으로는 변수의 값을 바꿀 수 없습니다.
const i = 10;
i = 12; //오류 값을 바꿀 수 없습니다.
alert(i);
값을 바꿀 수 없는 변수를 '상수'라고 하며 상수를 사용하는 이유는 값이 바뀌는 경우에 대한 별도의 처리를 필요로 하지 않으므로 '변수'보다 성능적으로 우위에 있기 때문입니다. 다만 javascript에서는 상수의 개념이 조금 다른데
const obj = { n : 10, s : 'abc' };
obj.n = 20;
console.log(obj.n);
위와 같이 객체를 가지고 있는 경우 객체의 속성은 변경이 가능하다는 특징이 있습니다.
변수를 선언할 수 있는 또 하나는 let이 있습니다.
let a = 10;
console.log(a);
let은 var와 같이 변수를 선언하고 사용할 수 있지만 큰 차이점은 const와 let은 블록 스코프라서 { 에서 } 로 끝나는 경우 const와 let변수는 더이상 유효하지 않습니다.
if (true) {
const i = 10;
let j = 20;
}
alert(i); //변수가 사용된 블록 밖에서 접근하므로 오류
alert(j); //변수가 사용된 블록 밖에서 접근하므로 오류
반면 var는 function을 벗어나지 않는 이상 유효합니다.
마지막으로 변수 선언을 위한 키워드를 하나만 더 살펴보겠습니다. let 키워드가 그것인데 let은 선언된 범위 안에서만 유효하다는 특징을 갖습니다. 예를 들어
{
var i = 10;
}
{
alert(i);
}
위 예제의 경우 아주 정상적으로 실행되어 10이라는 결과를 표시합니다. 예제에서 사용된 중괄호({})는 각각의 실행 범위를 구분하기 위한 용도라고 생각해 주세요. 변수 i에 값을 할당하는 범위와 변수 i의 값을 확인하는 범위가 서로 다르지만(구분되어 있지만) var키워드는 변수를 전역으로 처리하기에 오류가 발생하지 않는 것입니다.
즉, 모든 범위에서 변수를 사용할 수 있는 상태가 되는 것이죠. 하지만 let키워드를 사용하면 해당 변수가 선언된 범위 안에서만 사용 가능한 변수가 됩니다.
{
let i = 10;
alert(i); //정상 i의 유효범위 안에 있음
}
{
alert(i); //오류 i의 유효범위를 벗어남
}
변수를 var로 선언하면 어떤 범위 안에서든지 사용이 가능해야 하므로 항상 변수가 메모리에 상주하는 상태가 되지만 let은 유효 범위를 벗어나면 자동으로 삭제되므로 메모리 관리에 있어서 좀 더 유연한 대처가 가능하다는 이점이 있습니다.
var 이외에 const나 let키워드로 선언된 변수는 재선언이 불가능하며 마이크로소프트의 익스플로러에서는 동작하지 않음을 참고하 식 바랍니다.
(2) 복합 대입 연산자
변수 자체의 값을 연산하기 위해 사용하는 연산자로서 다음과 같은 복합 대입 연산자가 존재합니다.
+= | 변수에 값을 더합니다. |
-= | 변수에 값을 뺍니다. |
*= | 변수에 값을 곱합니다. |
/= | 변수에 값을 나눕니다. |
%= | 변수의 값에 나머지를 구합니다. |
위의 복합 대입 연산자는 다음과 같이 사용할 수 있습니다.
var i = 10; //변수 i에 10값을 할당
i += 5; //변수값에 5를 더함
alert(i); //결과는 15
(3) 증감 연산자
복합 대입 연산자와 마찬가지로 변수의 값을 연산하기 위한 연산자입니다. 다만 증감 연산자는 복합 대입 연산자처럼 우변에 특정 값을 지정해 연산할 값을 나타내지만 증감 연산자는 연산자만 존재하며 1의 값을 기본으로 연산합니다.
++ | 변수에 값을 더합니다. |
-- | 변수에 값을 뺍니다. |
따라서 증감 연산자는 다음과 같이 사용할 수 있습니다.
var i = 10; //변수 i에 10값을 할당
i++; //변수 i에 1값을 더함
alert(i); //결과는 11
증감 연산자는 단순하지만 주의해야 할 것이 있습니다. 증감 연산자를 변수의 앞에 사용하느냐 또는 뒤에 사용하느냐에 따라 다른 결과를 가져오기 때문입니다.
예를 들어
var i = 10; //변수 i에 10값을 할당
alert(i++);
위의 결과로는 10을 표시하게 됩니다. alert함수를 통해 변수의 값을 확인하려고 하고 있는데 문제는 ++연산자를 변수의 뒤에 두었기 때문에 i의 현재 값(10)을 먼저 출력한 뒤 그다음 변수의 값을 1 증가시키기 때문입니다.
var i = 10; //변수 i에 10값을 할당
alert(++i);
반면 위 결과는 11을 표시합니다. ++연산자를 변수의 앞에 두어 alert함수로 i의 값을 표시하기 이전에 먼저 연산을 수행하게 되고 그 뒤에 결과를 표시하기 때문입니다.
증감 연산자가 앞에 있는 걸 전위, 뒤에 있는걸 후위라고 하는데 위에서 처럼 연산자를 전위에 놓으면 변수의 다른 처리가 먼저 실행되기 이전에 연산자가 먼저 적용되며 후위에 놓으면 다른 처리가 먼저 실행된 후 연산을 적용하게 됩니다.
(4) 삼항 연산자
if 조건문과 비슷하게 동작하지만 엄밀히 연산로 분류되는 삼항 연산자는 if 조건문을 간결하게 작성하기 위해 종종 사용되곤 합니다.
var i = 10;
var s = (i == 10 ? 'i는 10' : 'i는 10이 아님');
alert(s);
삼항 연산자는 위 예제에서 처럼 우선 참/거짓의 조건이 되는 식이 오고 ? 뒤에는 참일 때, : 뒤에는 거짓일 때 실행하는 부분으로 나누어 처리를 작성하면 됩니다.
5. 입력
javascript에서 특정값을 사용자에게 입력받으려면 prompt함수를 사용할 수 있습니다.
var s = prompt('입력하세요.', 'hello');
물론 입력한 값은 변수 s에 들어가게 됩니다.
반면 사용자로부터 '예/아니요'형태의 결정만 받아야 한다면 confirm함수를 사용하면 됩니다.
var yn = confirm('계속 진행 하시겠습니까?');
if (yn) {
//
}
이때 '확인'을 선택하면 true가 '취소'를 선택하면 false가 confirm 함수로부터 반환됩니다.
6. 형 변환
숫자 데이터를 문자열로 혹은 문자열 데이터를 숫자 데이터로 변환하는 등의 처리를 '형 변환'이라고 합니다. 예를 들어
alert('123' + 456);
위 결과는 '123456'이 됩니다. +연산자를 사용하긴 했지만 앞에 '123'데이터가 문자열형이므로 뒤의 숫자 데이터인 456을 문자열 '456'으로 자동 형 변환했기 때문입니다.
반면 +를 *연산자로만 바꾸고 실행하면
alert('123' * 456);
56088이 출력되는데 +연산자를 제외한 다른 연산자에서는 문자열형을 숫자형으로 자동 형 변환하여 처리하기 때문입니다.
물론 위에서 처럼 자동으로 형 변환을 수행하는 대신 임의로 형변환을 수행할 수도 있습니다.
alert(Number('123') + 456);
위 예제에서 사용된 Number함수는 특정 데이터를 숫자형 데이터로 변환시켜주는 함수입니다. Number함수에 따라 문자열 '123'데이터는 숫자형 123으로 변환되고 그 값을 456과 더하게 되므로 결과는 579가 됩니다.
참고로 숫자로 나타낼 수 없는 데이터형인 경우 NaN(Not a Number)을 출력하게 됩니다.
alert(Number('abc')); //NaN
Number와 달리 String함수는 데이터를 문자열형으로 바꿔주는 함수입니다. 따라서 아래 예제는 456을 문자열형의 데이터인 '456'으로 바꿨으므로 결과는 '123456'이 됩니다.
alert('123' + String(456));
숫자, 문자열 이외에 참/거짓만 가지는 불 데이터형으로 형변환을 수행할 수도 있습니다.
alert(Boolean(0));
Boolean은 데이터를 불데이터형으로 형 변환하는 함수이며 0 값은 false로 형 변환됩니다. 그밖에 아래 예제 모두 false로 형 변환을 수행하며
alert(Boolean(0));
alert(Boolean(NaN));
alert(Boolean(''));
alert(Boolean(null));
alert(Boolean(undefined));
다른 것은 모두 true로 현변 환이 수행됩니다.
7. 일치 연산자
위에서 불(Boolean) 데이터를 언급할 때 == 연산자가 있다는 것을 언급했었습니다. == 연산자는 좌우 양변의 값이 일치하는지를 확인하는 연산자입니다.
alert(123 == 123); //true
그런데 다음과 같은 경우에도 true로 결과가 반환됩니다.
alert(123 == '123'); //true
값은 123으로 같은데 데이터형은 틀립니다. 그런데도 true로 나오는 건 자동적으로 형 변환이 수행되었기 때문입니다. 만약 데이터의 '값'뿐만 아니라 데이터의 '형'까지도 비교해야 한다면 === 연산자를 사용해야 합니다.
alert(123 === '123'); //false
=== 연산자는 값뿐만 아니라 데이터의 형까지도 비교하고 같으면 true를 반환합니다. 반대로!== 연산자도 존재하는데 데이터형 또는 값이 다른 경우 true를 반환합니다.
'Web > Javascript' 카테고리의 다른 글
[javascript] 객체 (0) | 2020.04.30 |
---|---|
[javascript] 함수 (0) | 2020.03.27 |
[javascript] 반복문 (0) | 2020.03.24 |
[javascript] 조건문 (0) | 2020.03.17 |
[javascript] 개요 (0) | 2020.03.12 |