NodeJS - NodeJS 실행을 위한 JavaScript 문법1
JavaScript ES2015+
const, let
먼저 const와 let이 공통적으로 가지는 특징인 블록 스코프(범위)에 대해 알아보자
var와 const
if(true){
var x = 3;
}
console.log(x); //3
if(true){
const y = 3;
}
console.log(ㅛ); //Uncaught ReferenceError: y is not defined
위 코드에서 x는 정상적으로 출력되는데 y는 에러가 발생합니다. var는 함수 scope를 가지므로 if문의 블록과 관계없이 접근할 수 있다. 하지만 const와 let 블록 scope를 가지므로 블록밖에서는 변수에 접근할 수 없다.
블록의 범위는 if,while,for,function 등에서 볼 수 있는 중괄호 '{}' 사이이다. 함수scope 대신 블록 scope를 사용함으로써 호이스팅 같은 문제도 해결되고 코드 관리도 수월해 졌다.
const, let과 var의 scope는 종류가 다르다 는 차이점이 있다. 그렇다면 const와 let 간의 차이는 무엇일까? const는 한 번 값을 할당하면 다른 값을 할당할 수 없습니다. 즉 다른 값을 할당하려고 하면 에러가 발생합니다. 또한 초기화 할 때 값을 할당하지 않으면 에러가 발생한다. 따라서 const로 선언한 변수를 상수라고 부른다.
const와 let
const a = 0;
a = 1; //Uncaught TypeError: Assignment to constant variable.
let b = 0;
b = 1; //1
const c; //Uncaught SyntaxError: Missing initializer in const declaration
객제 리터럴
다음 코드는 oldObject 객체에 동적으로 속성을 추가하고 있습니다.
var sayNode = function(){
console.log('Node');
};
var es = 'ES';
var oldObject ={
sayJS: function(){
cosole.log('JS');
},
sayNode:sayNode,
};
oldObject[es + 6] = 'Fantastic';
oldObject.sayNode(); //Node
oldObject.sayJS(); //JS
console.log(oldObject.ES6); //Fantastic
위코드를 다음과 같이 다시 쓸 수 도 있다.
var sayNode = function(){
console.log('Node');
};
var es = 'ES';
const newObject ={
say(){
console.log('JS');
},
sayNode,
[es+6]:'Fantastic',
};
newObject.sayNode(); //Node
newObject.sayJS(); JS
console.log(newObject.ES6); //Fantastic
새로운 버전에서는 sayJS 같은 객체의 메서드에 함수를 연결할 때 더는 콜론(:)과 function을 붙이지 않아도된다. sayNode:sayNode처럼 속성 명과 변수 명이 동일한 경우에는 한 번만 써도 되게 변경되었다.
{ name:name, age:age } //ES5
{ name,age } // ES2015
화살표 함수
const add3 = (x , y) => x + y;
const add4 =(x , y) => (x + y);
화살표 함수에 내부에 return문 밖에 없는 경우에는 return문을 생략할 수 잇다. 중괄호 대신 add3과 add4처럼 return할 식을 바로 적으면 된다. add4처럼 보기 좋게 소괄호로 감쌀 수도 있다.
function not1(x){
return !x;
}
const not2 = x => !x;
not2처럼 매개변수가 한 개변 매개변수를 소 괄호로 묶어주지 않아도 된다. return 문을 줄이는 문법은 자주 사용된다.
기존 function과 다른 점은 this 바인드 방식이다.
var relationship 1 ={
name: 'zero',
friends:['nero','hero','xero'],
logFriends: function(){
var that = this; //relationship1을 가르키는 this를 that에 저장
this.friedns.forEach(function(friend){
console.log(that.name,friend)
});
},
};
relationahip1.logFriends();
relationaship1.logFriends()안의 forEach문에서 function 선언문을 사용했다. 각자 다른 함수 scope의 this를 가지므로 that이라는 변수를 사용해서 relationship1에 간접적으로 접근하고 있다.
원래는 함수안에 함수를 만들경우 함수안에 함수블러의 scope를 가지므로 that변수에 this를 저장하지 않고 this.name을 쓰면 friends 배열객체에 name 변수를 찾게된다.
const relationship2. = {
name:'zero',
friends: ['nero','hero','xero'],
logFriends(){
this.friends.forEach(friens => {
console.log(this.name,friend);
});
},
};
relationship2.logFriends();
relationaship1.logFriends()안의 forEach문에서는 화살표 함수를 사용했다. 따라서 바깥 scope인 logFriends()의 this를 그대로 사용할 수 있다. 상위 scope의 this를 그대로 물려받는것이다.
구조분해 할당
const candyMachine = {
status:{
name: 'node',
count: 5,
},
getCandy(){
this.status.count--;
return this.status.count;
},
};
const {getCandy,status:{count}} = candyMachine;
candyMachine 객체 안의 속성을 찾아서 변수와 매칭한다. count처럼 여러 단계 안의 속성도 찾을 수 있다. getCandy와 count 변수가 초기화 된 것이다.
배열에 대한 구조분해 할당
var array = ['nodejs',{},10,true];
var node = array[0];
var obj = array[1];
var bool = array[3];
const array = ['nodejs',{},10,true];
const [node,obj,,bool] = array;
obj 와 bool 사이의 요소인 10에는 변수명을 지어주지 않았으므로 10은 무시한다.
클래스 와 프로토타입
instanceof
instanceof 연산자는 생성자의 prototype 속성이 객체의 프로토타입 테인 어딘가에 존재하는지 판별한다.
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
const auto = new Car("Honda", "Accord", 1998);
console.log(auto instanceof Car);
// expected output: true
console.log(auto instanceof Object);
// expected output: true
}
프로토타입 기반
var Human = function (type) {
this.type = type || "human";
};
Human.isHuman = function (human) {
return human instanceof Human;
};
Human.prototype.breathe = function () {
alert("h-a-a-a-m");
};
var Zero = function (type, firstName, lastName) {
Human.apply(this, arguments);
this.firstName = firstName;
this.lastName = lastName;
};
Zero.prototype = Object.create(Human.prototype);
Zero.prototype.constructor = Zero; //상속하는 부분
Zero.prototype.sayName = function () {
alert(this.firstName + "" + this.lastName);
};
var oldZero = new Zero("human", "zero", "Cho");
Human.isHuman(oldZero);
true;
Human 생성자 함수가 있고, 그 함수를 Zero 생성자 함수가 상속한다. Zero 생성자 함수를 봄녀 상속받기 위한 코드가 상당히 난해 하다는 것을 알 수있다. Human.apply과 Object.create 부분이 상속받는 부분이다.
클래스 기반
class Human {
constructor(type = "human") {
this.type = type;
}
static isHuman(human) {
return human instanceof Human;
}
breathe() {
alert("h-a-a-a-m");
}
}
class Zero extends Human {
constructor(type, firstName, lastName) {
super(type);
this.firstName = firstName;
this.lastName = lastName;
}
sayName() {
super.breathe();
alert(`${this.firstName} ${this.lastName}`);
}
}
const newZero = new Zero("human", "Zero", "Cho");
Human.isHuman(newZero); // true
전반적으로 class안으로 그룹화된 것을 확인할 수 있다. 이렇게 클래스 문법으로 바뀌었더라도 자바스크립트는 프로토타입 기반으로 동작한다는 것을 명심해야한다.
출처
모던 JavaScript 튜토리얼 - https://ko.javascript.info/
MDN 웹개발 학습하기 > JavaScript - 동적인 클라이언트 사이드 스크립트 언어 - https://developer.mozilla.org/ko/docs/Learn/JavaScript
Node.js 교과서 - 조현영 저