javascript에서 은닉화를 위해 클로저를 사용한다.
typescript를 사용하면 손쉽게 적용 및 테스트가 가능하지만 Vanilla 스크립트로 작성시에는 테스트가 어려운 단점이 있다.
클로저를 테스트 하는 방법에 대한 개인적인 고민을 정리해 보았다.
ES6부터는 class 키워드
가 추가가 되면서 Java와 유사하게 Class를 선언하여 사용할 수 있게 되었지만 ES6 이전에도 prototype 객체
를 사용하여 클래스와 유사하게 사용을 할 수 있다.
다만 자유도가 너무 있다보니 비슷(?)하면서도 다양한 방식으로 사용이 가능하다.
정답이 있진 않지만 그중에서 가장 보편적인 방법을 사용하는 것에 옳다고 본다. 하지만 다양한 사용 방식에 대해 이해를 하면 보다 효율적인 코딩이 되지 않을까 싶어 정리해본다.
스코프
와프로토타입
에 대한 이해는 javascript의 기초이다. 다만 다른 언어들과 차이점들이 있어 쉽게 잊혀지는 것 같다. 아래 내용이 햇갈린다면 복습이 필요하다.
방법 1 생성자 함수를 통해 객체의 필드 값을 초기화 하고 prototype에 메서드를 정의
var Animal = (function () {
function Animal(name) {
this.name = name
}
Animal.prototype.getName = function() {
return this.name;
}
return Animal;
}());
var animal = new Animal('mung');
console.log(animal.getName());
방법 2 객체에 메서드를 추가하고 필드는 클로저로 구현하여 은닉화 하여 사용하는 방법
var Animal = function (name) {
var name = name;
this.getName = function() {
return name;
};
}
var animal = new Animal('mung');
console.log(animal.getName());
방법 3 2번 방식이랑 유사(클로저를 사용하는 점에서) 하지만 new 키워드를 안쓰고 함수 호출의 리턴 값으로 객체를 리턴
var Animal = function (name) {
var name = name;
var getName = function() {
return name;
};
return {
getName,
test: this
}
}
var animal = Animal('mung');
console.log(animal.getName());
/*
Animal 클래스는 return 값으로 객체를 리턴하기 때문에 결과물은 같긴하다.
생성자 함수의 return 값
- 객체를 return 한다면, this 대신 객체가 반환됩니다.
- 기본자료형을 return 한다면, return문이 무시되고 this가 리턴.
*/
var animal2 = new Animal('mung');
console.log(animal2.getName());
방법 1 vs 방법 2,3 의 가장 큰 차이는 prototype 사용 여부
와 은닉화
이다.
방법 1의 경우 정석적인? prototype을 통한 상속을 구현
하였다.
이를 통해 Dog 객첼르 100개 생성한다고 했을 Animal의 메서드가 정의된 prototype 객체는 하나만 존재
하게 된다.
하지만 2,3번의 경우는 생성할 때마다 this에 모든 메서드를 추가하고 있어 메서드들을 중복 생성
한다.
OOP에서는 내부 변수나 메서드들을 은닉화
하여 외부에 숨기고 외부에서의 접근은 공개된 멤버나 메서드를 하여 제공을 한다.
javascript에서도 class의 키워드가 추가되면서 기존 OOP로 개발하던 사람들은 은닉화를 하기를 바란다.
하지만 javascript에서는 접근 한정자가 없으며 객체의 필드나 메서드들은 외부에서 자유롭게 접근이 가능하다.
이를 위해 변수나 메서드들의 네이밍을 통해 은닉화를 처리하거나 하는 등의 다양한 편법들이 나왔지만 그중 은닉화를 위한 가장 좋은 방법은 클로저
를 사용하는 것이라고 생각한다.
하지만 클로저를 통한 은닉화는 치명적인 단점
이 존재하는데 바로 테스트를 작성하기 어렵다는 것이다.
처음 javascript를 접했을 때에는 최대한 은닉화를 다른 사람들이 실수로 내부 변수 등을 조작을 못하도록 막는게 최선이라고 생각하여 은닉화에 중점을 두었지만 테스트 작성에 어려움으로 인하여 지금은 은닉화를 안 하고 대신 탄탄한 테스트 코드를 작성하는 방향
으로 작성하길 선호하고 있다.
다만 레거시가 테스트가 어려운 코드의 경우 은닉화를 통해 강제성을 주는 것도 나쁘지 않다고 생각한다.
말이 샜는데 위 방법 중에 1번 방법을 선호
한다.
다면 요즘엔 ES6 작성 (class 키워드 사용)` 후 babel을 통해 transcompile을 하여 사용하므로 위 방법을 사용 할 일은 없어 보인다.
방법 1이 가장 많이 쓰이는 방법이며 방법 2,3은 쓰이는 방법인가 싶다.. 클래스 선언 방법으로 소개를 한 방법들에 대해 상속을 한다면 어떻게 할까 고민하면서 작성한 내용으로 아래와 같이 쓰이면 나름 상속은 구현이 될거 같다.
Animal 클래스를 상속받은 Dog 클래스를 예시로 든다.
방법 1의 상속
// Animal 클래스 정의
var Animal = (function () {
function Animal(name) {
this.name = name
}
Animal.prototype.getName = function() {
return this.name;
}
return Animal;
}());
// Dog 클래스 정의
var Dog = (function () {
function Dog(name, age) {
Animal.call(this, name); // 부모 생성자 호출.
this.age = age;
}
Dog.prototype = new Animal(); // 프로토 타입 프로퍼티에 부모 객체 설정
Dog.prototype.getAge = function() { // Dog 클래스 메서드 정의
return this.age;
}
return Dog;
}());
var dog = new Dog('mung', 5);
console.log(dog.getName());
console.log(dog.getAge());
방법 2의 상속
// Animal 클래스 정의
var Animal = function (name) {
var name = name;
this.getName = function() {
return name;
};
}
// Dog 클래스 정의
var Dog = function (name, age) {
Animal.call(this, name); // 부모 생성자 호출.
var age = age;
this.getAge = function() {
return age;
};
}
var dog = new Dog('mung', 5);
console.log(dog.getName());
console.log(dog.getAge());
방법 3의 상속
var Animal = function (name) {
var name = name;
var getName = function() {
return name;
};
return {
getName
}
}
// Dog 클래스 정의
var Dog = function (name, age) {
var animal = Animal.call(this, name); // 부모 생성자 호출.
var age = age;
var getAge = function() {
return age;
}
return Object.assign(
animal,
{
getAge
}
);
}
var dog = Dog('mung', 5);
console.log(dog.getName());
console.log(dog.getAge());
// 클래스 선언의 방법 3 주석코드에 설명한 것처럼 new 키워드를 붙여도 결과 값은 같긴하다.
var dog2 = new Dog('mung2', 3);
console.log(dog2.getName());
console.log(dog2.getAge());
클래스 상속의 경우도 방법 1 vs 방법 2,3 의 가장 큰 차이는 prototype 사용 여부
와 은닉화
로 보면 될 거 같다.
개발을 하다보면 요구사항들이 바뀌는 일이 빈번하다. 기존 코드에 대한 검증 및 새로운 코드에 의한 사이드이펙트에 대한 걱정은 많은 시간을 소요시킬 뿐이 아니라 이는 적지 않은 정신력을 소모하게 만든다.
이러한 문제들을 대해서 은탄환이 될 수 있는 것이 바로 테스트 코드이다.
탄탄한 테스트 코드는 그 자체로 스펙이 되며 스펙의 변화에 애자일하게 대응할 수 있으며 새로운 코드에 대한 확신을가질 수 있게 도와준다.
javascript에도 다양한 테스트 라이브러리가 존재하며 그중 jasmine
과 jest
에 대해서 간략하게 정리해보았다.
단위 테스트(Unit Test)란 가장 최소단위의 테스트로 보통 모듈 단위로 테스트를 한다.
통합 테스트(Integration Test)란 단위 테스트 보다 넓은 범위의 테스트로 보통 2개 이상의 모듈을 연결한 상태로 진행하는 테스트를 말함
E2E 테스트(End To End Test) 종단(Endpoint) 간 테스트로 사용자 입장에서 하는 테스트를 말함 UI(User Inerface) 테스트라고 불리기도한다.
단위 테스트 패턴으로, 테스트하기 곤란한 컴포넌트를 대체하여 테스트하는 것 특정한 동작을 흉내만 낼 뿐이지만 테스트 하기에는 적합하다. 다음 가지를 통칭하여 테스트 더블이라고 함
테스트를 모듈을 가져오기 위해
ES6 문법을 사용하기 위해서는 babel 설정이 필요
여기서는 다루지 않음.
- 브라우저 실행 환경의 프레임워크
- 테스트 러너로 karma를 사용
- 공홈에서 확인해보니 nodejs 실행 환경에서도 실행 가능.
Add Jasmine to your package.json
npm install --save-dev jasmine
Initialize Jasmine in your project
npx jasmine init
Set jasmine as your test script in your package.json
{
"scripts": {
"test": "jasmine"
}
}
Run your tests
npm run test
개인적으로 아래와 같은 형태로 테스트를 구성하는 것을 선호한다
기본 테스트 파일명: *[sS]pec.js
describe('A모듈 테스트', () => {
beforeEach(() => {
// 각 테스트 전에 실행
});
afterEach(() => {
// 각 테스트 이후에 실행
});
describe('A모듈.a메서드 테스트', () => {
it('a메서드 테스트 1', () => {
// ...
});
it('a메서드 테스트 2', () => {
// ...
};
})
});
- 페이스북에서 만든 테스트 프레임워크
- nodejs 실행 환경의 테스트 프레임워크
- 테스트러너를 포함한 프레임워크로 별도의 테스트러너가 없어도 된다.
Add Jest to your package.json
npm install --save-dev jest
Set jest as your test script in your package.json
{
"scripts": {
"test": "jest"
}
}
Run your tests
npm run test
개인적으로 아래와 같은 형태로 테스트를 구성하는 것을 선호한다
jasmine과 동일하게 구성 가능하며 it
메서드 대신 test
를 사용해도 된다.
기본 테스트 파일명: *.test.js
describe('A모듈 테스트', () => {
beforeEach(() => {
// 각 테스트 전에 실행
});
afterEach(() => {
// 각 테스트 이후에 실행
});
describe('A모듈.a메서드 테스트', () => {
it('a메서드 테스트 1', () => {
// ...
});
it('a메서드 테스트 2', () => {
// ...
};
})
});
대학교 프로그래밍 입문언어라는 python에 대한 기본적은 내용 간략히 정리. 자세한 내용은 공식 홈페이지의 레퍼런스 참고하자.
파이썬은 1991년 프로그래머인
귀도 반 로섬
이 발표한 고급 프로그래밍 언어로,플랫폼에 독립적
이며인터프리터식
,객체지향적
,동적 타이핑 대화형 언어
이다.
macOS에는 기본적으로 설치되어 있으며 필요시 공식 홈페이지에서 다운 받아 설치.
파이썬에서
블록
은콜론(:)
으로 시작하여 동일한들여쓰기 구간
을 의미함 클래스나 함수 선언 조건문 반복문 등을 사용할때 콜론(:)과 들여쓰기 블록 구분
자료형 없이 변수 선언 함수나 메서드 닽이
블록
내에서는지역변수
로 선언되는데 변수명 앞에global
을 붙이면 전역변수가 된다.
age = 20
name = 'song'
print(age) # 20 출력
print(name) #'song'출력
def 함수명(파라미터):
형태로 선언
def add(a,b): # 함수정의 끝에 : 을 입력해줘야한다.
return a+b # 함수 안의 내용은 탭으로 띄워줘야한다. 안 띄우면 indented block 예외가 예외발샐
print(add(2,3)) #5출력
lambda 인자 : 표현식
형태로 사용 파라미터로 익명함수 전달하는 용도같은로 보임 (개인적인 생각임) ```python add = lambda x,y : x + y add(3,5) # 8출력
(lambda x,y : x + y)(2,3) #5 출력 이렇게 즉시실행함수? 방식으로도 사용 가능.
### 조건문
#### if문
```python
a = 10
b = 5
if a > b:
print('a > b')
elif a == b:
print('a == b')
else:
print('a < b'
a = 10
while a <= 10:
print(a)
a = a + 1
numlist = [1,2,3]
for num in numlist:
print(num)
class Animal:
def __init__(self, name, age): # 생성자
self.name = name
self.age = age
def getName(self): # 메소드 선언
return self.name
ani = Animal('happy', 5)
ani.getName() # 'happy' 출력
class Animal:
def __init__(self, name, age): # 생성자
self.name = name
self.age = age
def getName(self): # 메소드 선언
return self.name
class Dog(Animal): # Animal 상속
def speak(self):
print('멍멍')
dog = new Dog('happy', 3)
dog.getName() # 'happy' 출력
dog.speak() # '멍멍' 출력
import 모듈 # 모듈.변수 or 모듈.함수 형태로 호출
from 모듈 import 변수 or 함수 # 필요한 변수나 함수만 가져오기
from 모듈 import * # 모듈의 모든 변수나 함수를 전부가져와서 모듈명 없이 사용가능하나 기존의 변수나 함수가 모듈의 것으로 덮어씌여질수 있음
del 모듈 # 모듈 지우기
reload(모듈) # 모듈 다시 불러오기
try:
실행 코드
except [ 처리할 예외명 [ as 에러 메시지 변수 ]]:
예외가 발생 했을 때 실행할 코드
[ else: ]
예외가 발생 안했을 때 실행할 코드
[ finally: ]
예외가 발생하든 안하든 실행할 코드
예제 ```python def division(a,b): res = 0 try: res = a/b except: print(‘예외 발생’) return res
division(2, 0) # ‘예외 발생’ 출력 ```
codepen.html
{% assign username = include.username %}
{% unless username %}
{% assign username = site.codepen_username %}
{% endunless %}
<p data-height="228" data-theme-id="0" data-slug-hash="{{ include.hash }}" data-default-tab="result" data-user="{{ username }}" class='codepen'>See the Pen <a href='https://codepen.io/{{ username }}/pen/{{ include.hash }}/'>{{ include.title }}</a> by {{ username }} (<a href='https://codepen.io/{{ username }}'>@{{ username }}</a>) on <a href='https://codepen.io'>CodePen</a>.</p>
<script async src="//assets.codepen.io/assets/embed/ei.js"></script>
codepen_username: username
포스팅애 아래 처럼 추가하면 된다.
{% include codepen.html hash="zYvOave" title="Enyo Template" %}
hash
: cdepen hash값
exrport
나 크를 카피하면 hash값을 알수 있다.title
: 적당한 제목 입력.See the Pen Hello Codepen by kijungsong (@kijungsong) on CodePen.
기본적으로 고령자또는 장애를를 가진 사람들이
차별 및 제한 없이 웹을 사용
할 수 있게 하는 것웹접근성 준수 의무자 및 적용시기는 장애인차별금지법(장차법) 제21조 제1항 및 시행령 제14조에 규정
2013년 4월 11일부터 모든 법인은 웹접근성을 준수
스크린리더, 화면확대 도구, 음성 인식, 키보드 오버레이 등의 보조과학기술을 이용
Chrome 확장 프로그램 OpenWAX(Open Web Accessibility eXtension)
로 진단 가능