가끔 친구와 술을마실 때면개발 이야기를하곤 합니다. (거의 술마실 때마다항상 하는 것같기도 하고;;) 하여튼대화 도중에 `세미콜론`에 대한 이야기가 나왔습니다.
"
파이썬으로 개발을 많이 하다가 자바스크립트를 해야 할 때면 세미콜론 정말 귀찮아. 자꾸 빼먹게 돼서 어디는 들어가 있고 어디는 안들어가 있고... 이거 정말 꼭 붙여야 하는 걸까? 자바스크립트는 세미콜론 없어도 문제 없잖아?? 자바같이 엄격한 애들은 에러 나서넣긴 하는데, 굳이 자바스크립트는..
"
여기서 간단히 설명하면,파이썬은세미콜론이 아닌 들여쓰기를 통해 구문구분이 됩니다. 따라서 세미콜론이필요 없습니다.
저는 프로그래밍을배우던….새싹일 때부터많은 강사가, 그리고 만났던 사수들이 예외사항이 생길 수 있다며 세미콜론을 꼭 붙이라고 했습니다. 그래서의심조차 하지않고 늘 사용해왔고 심지어 회사 컨벤션에 포함된 경우도 봤습니다. 그리고 플러그인프로그래밍할 때타 플러그인과의 충돌을막기 위해세미콜론으로시작하는 예도종종 봤습니다.
근데 이게 정말 필수였을까요? 궁금증을해결해보기 위해찾아봤습니다.
본문
세미콜론을 사용하지 않고개발한다고 해서구문 구분 시 세미콜론이 없는 것이 아닙니다. 인터프리터과정에서자동으로 구문 구분을해야 하는 곳에세미콜론을 붙여주기 때문입니다. 이 과정을 세미콜론 자동삽입(ASI, automatic semicolon insertion)이라고 합니다. 그리고 이 과정이 존재하기에 논쟁은 시작되었을 것 같습니다. 자동으로 붙여주는 것을 왜 우리가넣어야 하는가.
많은 사람이혹.시.모.르.는예외사항을 대비하라고 합니다. 하지만
반대 견해의사람들은 자동삽입이 되는 동작을 이해하고 코딩하면 문제가 되지 않을 것이라고 합니다.
예시
return
true;
이때 개발자는 return;true;로보겠지만, 인터프리터에서는returntrue;로인식합니다. 하지만 이것도 자동삽입되는 부분의 동작을 이해하면 문제가 되지 않을 수도 있습니다.
그렇습니다. 사용하지 말자는 사람의 의견대로 인터프리터에 자동삽입의 코딩스타일을 정립할 수 있다면 세미콜론을 강제하지 않아도 됨을 말합니다.
정답이 없기 때문에 빠르게 결론으로 가겠습니다.
짧게보는 이야기
1. 자바스크립트는 구문구분 시 세미콜론을넣어야 한다 2. 세미콜론을넣지않을 때인터프리터가 자동으로 넣어준다. 3. 자동으로넣어줄 때오류가 생길 예외사항에 대해 과거에많은 사람이세미콜론을 강제했다. 4. 인터프리터의과정을 이해하여 코딩할 경우 세미콜론이 없어도 충분히 예외사항이 생기지 않는다. 5. 인터프리터의과정에 따라 코딩스타일이 정립된다면 세미콜론을 강제할필요가 없다. 6. 하지만여전히 논쟁거리
결론
자바스크립트의 기본 규칙은 세미콜론을 붙이는 것이며
과거에 나온 자바스크립트 교재를 보면 대부분 세미콜론을 넣는 것이 바람직하다고 설명합니다. 자동삽입에 대한 이해가 없어도(할 필요도 없이) 세미콜론을넣게 되면문제를미리방지할 수 있습니다. 세미콜론을 마지막으로구문이 구분되니가독성에도 좋습니다. 그리고 사용해서 문제가 되는 것은 없으나 반대의 경우 문제가 될 경우가 조금이라도 있다면 개발자는 예외사항도무시하면 안 된다생각합니다.
(안전한걸하지 않을이유는 없겠죠.)
하지만 저와친구가 한 대화의 현실적인결론은 아래와 같습니다. 물론 세미콜론을 넣는 스타일로 정립된 저는 사용하자는 편에서 있지만요.
"
회사 컨벤션에 쓰라고 돼 있으면 쓰고 말라면 만다. 그 외 개인적인 코딩은 개인이 책임지기 때문에 알아서 한다.
클래스라는 추상화된 개념을 선언한 뒤, 이 클래스를 기반으로 객체에 상속을 지원합니다. 여기서 주목해야 할 점은 객체의 형식이 정의된 클래스는 객체가 아닌 개념이라는 점입니다.
// 1. 클래스 정의
public class Person{
public string country = "korea";
public string name;
public int age;
// 2. 클래스 생성자 정의
public Person(string name, int age){
this.name = name;
this.age = age;
}
}
// 3. 객체 생성
Person boy = new Person("yoonhee", "12");
프로토타입 기반
프로토타입 원형 객체를 생성한 뒤, 이 객체를 이용해서 클래스의 상속을 흉내 냅니다.
여기서 주목해야 할 점은 프로토타입은 객체입니다.
// 1. 프로토타입 객체 정의
var base = function(){
this.country = "korea"
}
// 2. 프로토타입 객체 생성자 정의
var Person = function(name, age){
this.name = name;
this.age = age;
}
// 3. 생성자에 프로토타입 상속
Person.prototype = base;
// 4. 객체 생성
var boy = new Person("yoonhee", "12");
매우 유사해 보이지만 프로토타입에서는 생성자에 프로토타입을 상속받는 절차가 필요한 것을 확인할 수 있습니다.
객체 지향 프로그래밍에서 인스턴스는 해당 클래스의 구조로 컴퓨터 저장공간에서 할당된 실체를 의미한다.
프로토타입 객체(Prototype Object)
자바스크립트는 함수(Function) 자료형으로 객체를 선언할 때 생성자(Constructor)를 부여받습니다.
함수 자료형
var func = new Function();
var protoFunc = new func();
var func2 = function(){};
var protoFunc2 = new func();
console.log(func.prototype); // { constructor : f(), __proto__ : Object }
console.log(func2.prototype); // { constructor : f(), __proto__ : Object }
function(){}는 new Function()으로 선언한것과 같습니다.
함수 자료형 외의 다른 자료형에서는 프로토타입 객체를 생성할 수 없습니다.
var obj = {};
var protoObj = new obj(); // obj is not a constructor
var num = 123;
var protoNum = new num(); // num is not a constructor
var boolean = true;
protoBoolean = new boolean() // boolean is not a constructor
그리고 이 생성자(Constructor)가 있는 객체만이 자바스크립트의 new 키워드를 통해 객체를 생성할 수 있습니다.
new 키워드를 통해 객체를 선언하면 함수의 생성과 함께 프로토타입 객체(Prototype Object)도 같이 생성됩니다.
그리고 객체와 객체사이에 참조하는속성들을레퍼런스변수라고 합니다. 또한, 이참조는 동적으로 추가된 사항에대해서도 접근할 수 있습니다.
레퍼런스 변수 예제
1.생성자를 부여받은 객체만이new 키워드를 통한 객체 생성이 가능하다고 한 것을기억해야 합니다.
function Person(x) {
this.x = x;
}; // 프로토타입 객체 생성자 정의
var A = new Person('hello'); // 객체 생성
console.log(A.x); // hello
// Person.x와 동일한 결과
console.log(A.prototype.x) // syntax error
// A는 생성자의 권한이 없는 단일객체이기에 문법오류를 일으킨다.
2.프로토타입 원형 객체의 내부 스코프에 선언한 변수 x와 prototype으로 선언한 x의 위치를 확인합니다.
function Person(){
this.x = 'Person x';
}; // 프로토타입 객체 생성자 정의
Person.prototype.x = 'prototype x'; // 프로토타입 선언
var newPerson = new Person(); // 객체 생성
console.log(newPerson.x); // Person x
console.log(newPerson.__proto__.x); // prototype x
console.log(newPerson);
/*
{
x : 'Person x',
__proto__ :
x : 'prototype x',
constructor : f Person(),
__proto__ : Object
}
*/
new 키워드를 통해 생성한 객체 newPerson은 원형 객체 Person을 참조하고 있기 때문에
Person.x = newPerson.x이 됩니다.
prototype으로 선언한 x는 __proto__ 레퍼런스 변수를 통해 원형 객체 Person의 x를 참조할 수 있습니다.
프로토타입 링크(Prototype Link)
__proto__ 속성은 프로토타입 링크라고 불리며 모든 객체에 존재하는 레퍼런스 속성이자 객체의 원형을 참조합니다. 객체가 생성될 때 프로토타입이 결정되며 사용자가 임의로 변경할수도 있습니다.
사용자가 임의로 동적으로 변경하는 특징을 사용해 상속을 구현할 수도 있습니다.
이 프로토타입 링크를 통해 상위 __proto__를 접근할 수 있으며 이것을 프로토타입 체인(Prototype chain)이라고 합니다. __proto__ 속성의 동작은 내부적으로 Object.getPrototypeOf가 호출되며 프로토타입객체를 반환합니다.
__proto__와 prototype는 둘다 프로토타입객체를 가리키고 있지만 두 속성의 관점은 차이가 있다고합니다.
{}나 new Object로 선언한 객체는 자바스크립트에서 제공하는 네이티브 코드를 원형으로 두고 있어서 __proto__는 네이티브 코드를 contstuctor로 가지고 있습니다.
var object = {};
var object2 = new Object();
예제
원형 객체 Person의 prototype을 상속받습니다.
function Person(){}
Person.prototype.getType = function(){
return "사람입니다";
};
var yoon = new Person();
var jun = new Person();
console.log(yoon.getType()); // 사람입니다
console.log(jun.getType()); // 사람입니다
1. __proto__와 prototype의 위치
function Person(){
this.x = 'Person x';
};
Person.prototype.x = 'prototype x';
var newPerson = new Person();
console.log(newPerson.x); // Person x
console.log(newPerson.__proto__.x); // prototype x'
- Person 함수 내부 스코프에 this.x를 선언
- Person의 prototype에 x를 선언
newPerson 객체의 x에 접근할 때 Person 내부 스코프에 선언한 대로 반환합니다.
__proto__.x로 참조 시 newPerson의 prototype에 접근하여 x를 반환합니다.
그렇다면 프로토타입 객체 원형의 내부 스코프에 this.x를 선언하지 않고 진행했을때에는 어떤 결과가 나오는지 확인해봅니다.
2. 프로토타입체인, 내부에 선언된 값이 없다면 상위를 참조
function Person(){};
Person.prototype.x = 'prototype x';
var newPerson = new Person();
console.log(newPerson.x); //prototype x
console.log(newPerson.__proto__.x); // prototype x'
- Person 내부에 선언된 x의 값을 찾고 x의 값이 없으면 __proto__를 통해 상위 객체에서 x의 값을 찾는다.
위의 예제에서는 prototype.x가 있기 때문에 prototype.x의 값을 반환한다.
프로토타입객체 내부에 변수가없으면 해당 변수의 값을 찾기 위해 상위 프로토타입을 이어 참조하면서 해당 변수가 있을때까지 반복하여 값을 찾습니다. 끝까지 값이 없으면 undefined를 반환합니다.