BioPlayground

🧬
목록으로

JavaScript로 실험 데이터 다루기

실험 데이터를 JavaScript로 처리하는 법. 변수, 조건문, 반복문, 함수를 바이오 예제로 배웁니다.

입문
|
90
|
검증 완료 (2026-06)
자바스크립트변수조건문반복문함수실험 데이터 처리
트랙 진행률0/11 (0%)

JavaScript로 실험 데이터 다루기

지난 시간에 HTML/CSS로 실험 프로토콜 웹페이지를 만들었습니다. 깔끔하지만, 그 페이지는 마치 겔 이미지 "사진"과 같습니다 — 보기만 할 수 있고, 반응하지 않죠.

JavaScript를 더하면 웹페이지가 살아 움직입니다. OD 값을 입력하면 자동으로 농도를 계산하고, 역가가 기준치 이하면 경고를 띄우고, 96개 시료의 결과를 한 번에 처리할 수 있습니다. HTML이 겔 이미지라면, JavaScript는 그 이미지를 분석하는 ImageJ 소프트웨어입니다.

변수: 실험 노트에 데이터 적어두기

변수(variable)는 데이터에 이름표를 붙여 저장하는 것입니다. 실험 노트에 "시료 농도: 2.5 μg/mL"이라고 적어두는 것과 같습니다.

javascript
const geneName = "BRCA1";
const sampleConcentration = 2.5;
let experimentStatus = "진행중";

console.log(geneName);            // "BRCA1"
console.log(sampleConcentration); // 2.5
console.log(experimentStatus);    // "진행중"

const는 변하지 않는 값에, let은 변할 수 있는 값에 씁니다. 유전자 이름은 실험 중에 바뀌지 않으니 const, 실험 상태는 "진행중"에서 "완료"로 바뀌니 let입니다.

JavaScript에는 세 가지 기본 데이터 타입이 있습니다:

javascript
// 문자열(String) — 유전자 이름, 시료 라벨
const proteinTarget = "EGFR";

// 숫자(Number) — 농도, OD값, 온도
const reactionTemp = 37;
const odValue = 0.85;

// 불리언(Boolean) — 참/거짓 판정
const isPositive = true;
const hasContamination = false;

console.log(typeof proteinTarget); // "string"
console.log(typeof reactionTemp);  // "number"
console.log(typeof isPositive);    // "boolean"

문자열은 따옴표로, 숫자는 그대로, 불리언은 true/false로 씁니다. PCR 결과가 양성인지 음성인지 — 딱 두 가지 상태만 존재하는 것이 바로 불리언입니다.

조건문: 실험 결과 판정하기

조건문(conditional)은 "밴드가 있으면 양성, 없으면 음성"처럼 상황에 따라 다른 행동을 하는 로직입니다. 실험에서 매일 하는 의사결정을 코드로 옮긴 것이죠.

javascript
const ctValue = 28.5;
const threshold = 35;

if (ctValue < threshold) {
  console.log("양성 (Positive)");
} else {
  console.log("음성 (Negative)");
}
// 출력: "양성 (Positive)"

console.assert(ctValue < threshold, "Ct 28.5는 threshold 35 미만");

조건이 여러 개일 때는 else if를 씁니다:

javascript
const purityRatio = 1.95;

let qualityGrade;
if (purityRatio >= 1.8 && purityRatio <= 2.0) {
  qualityGrade = "순수 DNA";
} else if (purityRatio < 1.8) {
  qualityGrade = "단백질 오염 의심";
} else {
  qualityGrade = "RNA 오염 의심";
}

console.log(`A260/A280 = ${purityRatio} → ${qualityGrade}`);
// 출력: "A260/A280 = 1.95 → 순수 DNA"

console.assert(qualityGrade === "순수 DNA");

여기서 ===는 "정확히 같은가?"를 비교하는 연산자입니다. =(값을 넣는 것)과 헷갈리지 마세요. 실험에서 "농도를 설정하는 것"과 "농도를 측정해서 확인하는 것"은 완전히 다른 행위입니다. 대입은 =, 비교는 ===입니다.

배열과 반복문: 시료 목록 일괄 처리

배열(array)은 여러 데이터를 순서대로 담는 상자입니다. 겔 위의 밴드들을 왼쪽부터 순서대로 나열한 것과 같습니다.

javascript
const sampleIds = ["S001", "S002", "S003", "S004", "S005"];
const odValues = [0.45, 1.23, 0.89, 0.12, 2.15];

console.log(sampleIds[0]);     // "S001" (첫 번째)
console.log(sampleIds.length); // 5 (총 개수)
console.log(odValues[2]);      // 0.89 (세 번째)

배열의 인덱스는 0부터 시작합니다. 96-well plate에서 A1이 0번째 well인 것과 같습니다.

반복문(loop)은 96-well plate의 모든 well에 같은 처리를 하는 것입니다. 시료가 5개든 500개든, 코드 한 번이면 전부 처리됩니다.

javascript
const geneList = ["TP53", "BRCA1", "EGFR", "KRAS", "MYC"];

for (let i = 0; i < geneList.length; i++) {
  console.log(`분석 대상 ${i + 1}: ${geneList[i]}`);
}
// 분석 대상 1: TP53
// 분석 대상 2: BRCA1
// 분석 대상 3: EGFR
// 분석 대상 4: KRAS
// 분석 대상 5: MYC

console.assert(geneList.length === 5, "유전자 목록은 5개");

for 반복문은 세 부분으로 구성됩니다: 시작값(let i = 0), 반복 조건(i < geneList.length), 증가식(i++). 매 회차마다 i가 1씩 늘어나면서, 배열의 처음부터 끝까지 순회합니다.

배열과 조건문을 합치면, 대량 시료의 QC 판정도 자동화됩니다:

javascript
const samples = ["S001", "S002", "S003", "S004"];
const concentrations = [2.5, 0.3, 1.8, 0.1];
const minConcentration = 0.5;

let passCount = 0;
for (let i = 0; i < samples.length; i++) {
  if (concentrations[i] >= minConcentration) {
    console.log(`${samples[i]}: PASS`);
    passCount++;
  } else {
    console.log(`${samples[i]}: FAIL (재추출 필요)`);
  }
}
console.log(`합격: ${passCount}/${samples.length}`);
// S001: PASS
// S002: FAIL (재추출 필요)
// S003: PASS
// S004: FAIL (재추출 필요)
// 합격: 2/4

console.assert(passCount === 2, "0.5 이상인 시료는 2개");

조건문 하나, 반복문 하나로 수동 QC 체크가 자동화되었습니다. 시료가 100개로 늘어나도 코드는 그대로입니다.

함수: 프로토콜을 재사용 가능하게

함수(function)는 실험 프로토콜의 한 단계를 재사용 가능하게 포장한 것입니다. "GC 함량 계산"이라는 프로토콜을 한 번 정의해두면, 어떤 서열이든 넣기만 하면 결과가 나옵니다.

javascript
function calculateGcContent(sequence) {
  let gcCount = 0;
  for (let i = 0; i < sequence.length; i++) {
    if (sequence[i] === "G" || sequence[i] === "C") {
      gcCount++;
    }
  }
  return (gcCount / sequence.length) * 100;
}

const gc1 = calculateGcContent("ATGCGATCGA");
const gc2 = calculateGcContent("AAATTTAAATTT");

console.log(`ATGCGATCGA → GC = ${gc1}%`);   // 50%
console.log(`AAATTTAAATTT → GC = ${gc2}%`);  // 0%

console.assert(gc1 === 50, "ATGCGATCGA의 GC 함량은 50%");
console.assert(gc2 === 0, "AAATTTAAATTT의 GC 함량은 0%");

함수의 구성 요소를 정리하면:

  • function calculateGcContent(sequence) — 함수 이름과 매개변수(parameter): 프로토콜 이름과 "무엇을 넣을지"
  • { ... } 안의 코드 — 프로토콜의 실제 절차
  • return — 결과를 돌려주는 것. 실험이 끝나고 데이터를 보고하는 단계
  • calculateGcContent("ATGCGATCGA") — 함수 호출. 매개변수 자리에 넣는 실제 값을 **인자(argument)**라고 합니다

희석 배수 계산도 함수로 만들 수 있습니다:

javascript
function dilutionVolume(stockConc, finalConc, finalVol) {
  return (finalConc * finalVol) / stockConc;
}

const needed = dilutionVolume(10, 1, 500);
console.log(`원액 ${needed} μL 필요`); // 원액 50 μL 필요

console.assert(needed === 50, "C1V1 = C2V2 검증");

한 번 함수를 만들어두면, 농도가 바뀌어도 숫자만 바꿔 넣으면 됩니다. 매번 계산기를 두드리는 것보다 훨씬 빠르고 실수가 없습니다.

직접 해보기 (Faded Example)

아래 빈칸을 채워 DNA 서열의 GC 함량 판정 코드를 완성하세요.

빈칸 채우기javascript
const sequence = "ATGCGCTA";
const gcThreshold = 40;
let gcCount = 0;
for (let i = 0; i < sequence.; i++) {
if (sequence[i] === "G" || sequence[i] === "") {
gcCount++;
}
}
const gcPercent = (gcCount / sequence.length) * ;
if (gcPercent >= gcThreshold) {
console.log("High GC");
} else {
console.log("Low GC");
}

흔한 에러 & 해결법

Q: ====를 헷갈립니다

=는 값을 넣는 것(대입), ===는 같은지 비교하는 것입니다. if (status = "pass")라고 쓰면 비교가 아니라 대입이 되어 항상 참(true)이 됩니다. 조건문 안에서는 반드시 ===를 쓰세요.

Q: 배열 마지막 요소에 접근하려면?

const genes = ["TP53", "BRCA1", "EGFR"]에서 genes[3]undefined입니다. 배열 인덱스는 0부터 시작하므로, 마지막 요소는 genes[genes.length - 1]로 접근합니다.

Q: const로 선언한 변수를 바꾸려 하면 에러가 납니다

TypeError: Assignment to constant variable.const는 한 번 정한 값을 변경할 수 없습니다. 값이 바뀌어야 하는 변수는 let으로 선언하세요.

Q: 함수를 호출했는데 undefined가 나옵니다

함수 안에 return이 없으면 결과를 돌려주지 않습니다. console.log()는 화면에 출력만 할 뿐 값을 돌려주지 않습니다. 계산 결과를 다른 곳에서 써야 한다면 반드시 return을 넣으세요.

Q: var로 선언한 강의 코드가 있는데, let/const와 뭐가 다른가요?

var는 ES6(2015) 이전의 옛날 선언 방식으로, 함수 스코프입니다. let/const블록 스코프여서 {} 안에서만 유효합니다. var는 블록을 무시하고 밖에서도 접근되기 때문에 예기치 않은 버그를 만듭니다:

javascript
if (true) {
  var x = 10;
  let y = 20;
}
console.log(x); // 10 (밖에서도 접근됨)
// console.log(y); // ReferenceError (블록 밖이라 접근 불가)

생활코딩 등 옛날 강의에서 var를 쓰는 건 강의 시점이 ES6 이전이라서입니다. 현대 JavaScript에서는 기본적으로 const, 값이 바뀌어야 할 때만 let을 쓰세요. var는 쓰지 마세요.

Q: ? :는 뭔가요? (삼항 연산자)

조건 ? 값1 : 값2 — 조건이 참이면 값1, 거짓이면 값2를 반환하는 연산자입니다. if/else를 한 줄로 압축한 것입니다:

javascript
const od = 1.85;
const result = od >= 1.0 ? "pass" : "fail";
// if (od >= 1.0) { result = "pass" } else { result = "fail" } 과 동일

Q: !는 뭔 뜻인가요?

!는 논리 부정(NOT) 연산자입니다. truefalse로, falsetrue로 뒤집습니다:

javascript
const hasPermission = false;
if (!hasPermission) {
  console.log("접근 거부"); // 이것이 실행됨
}

!변수명은 "변수가 거짓이면"이라고 읽으면 됩니다. !isPassed는 "통과하지 않았으면".

Q: DOM이 뭔가요? document.getElementById는 어디서 나온 건가요?

DOM(Document Object Model)은 브라우저가 HTML을 읽어서 JavaScript로 조작할 수 있는 트리 구조의 객체로 변환한 것입니다. document는 그 트리의 꼭대기이고, getElementById()는 트리에서 특정 요소를 찾는 메서드입니다:

javascript
// HTML: <div id="result">대기중</div>
const resultDiv = document.getElementById("result");
resultDiv.innerText = "분석 완료!";

HTML이 "설계도"라면, DOM은 브라우저가 그 설계도로 지은 "건물"입니다. JavaScript는 이 건물의 벽을 칠하거나 가구를 옮길 수 있습니다.

Q: 백틱(`)은 따옴표와 뭐가 다른가요?

백틱은 템플릿 리터럴을 만드는 문법입니다. 문자열 안에 ${변수명}으로 값을 직접 삽입할 수 있습니다:

javascript
const gene = "TP53";
const od = 2.15;

// 따옴표: 문자열 연결이 번거로움
const msg1 = gene + "의 OD값: " + od;

// 백틱: 깔끔하게 삽입
const msg2 = `${gene}의 OD값: ${od}`;

// 계산식도 가능
const msg3 = `30일 = ${60 * 60 * 24 * 30}초`;

작은따옴표(')나 큰따옴표(")로 쓰면 ${}가 그냥 글자로 출력됩니다. 반드시 백틱(`)을 써야 합니다.

Q: 표현식(expression)과 문장(statement)이 뭔가요?

표현식은 값으로 평가되는 코드입니다 — 변수에 담을 수 있습니다. 문장은 동작만 하고 값을 만들지 않습니다:

javascript
// 표현식: 값이 된다
1 + 1            // 2
od >= 1.0        // true
"pass"           // "pass"

// 문장: 동작만 한다 (값이 안 된다)
if (true) { }    // 조건문
for (let i...) { } // 반복문

함수도 return이 있으면 호출 결과가 값(표현식)이 되고, return이 없으면 undefined를 반환합니다. 앞의 "함수를 호출했는데 undefined가 나옵니다" Q&A와 연결되는 개념입니다.

Q: 화살표 함수(arrow function) => 는 뭔가요?

function 키워드 대신 =>로 함수를 짧게 쓰는 문법입니다. 콜백 함수에서 자주 씁니다:

javascript
// 기존 방식
samples.filter(function(s) {
  return s.status === "pass";
});

// 화살표 함수 방식 — 같은 동작
samples.filter((s) => {
  return s.status === "pass";
});

// 더 짧게 — 본문이 한 줄이면 중괄호와 return 생략 가능
samples.filter(s => s.status === "pass");

function(x) { return ... }x => ...는 대부분의 경우 동일하게 동작합니다. DevBench에서는 초보자가 읽기 쉬운 function 방식을 쓰지만, 실무 코드와 AI가 생성하는 코드에서는 화살표 함수를 압도적으로 많이 씁니다.

Q: JavaScript에서 에러가 나면 왜 전체가 멈추나요?

JavaScript는 코드를 위에서부터 차례대로 실행합니다. 중간에 에러가 발생하면 그 줄에서 멈추고, 아래 코드는 실행되지 않습니다:

javascript
console.log("1번 출력됨");
console.log("Hello".indexOf);  // 에러 발생 지점
console.log("3번 출력 안 됨"); // 실행되지 않음

그래서 Console에 에러가 뜨면, 에러 메시지에 나온 줄 번호를 먼저 확인하고 그 줄을 고쳐야 합니다. 아래쪽 코드가 안 도는 것은 아래쪽의 문제가 아니라, 위쪽 에러 때문입니다.

Q: 주요 연산자를 한눈에 보고 싶습니다

종류연산자의미예시결과
산술+ - * / %더하기, 빼기, 곱하기, 나누기, 나머지5 % 21
비교=== !== > <같은가(타입 포함), 다른가, 크다, 작다5 === "5"false
논리&& || !AND, OR, NOT!truefalse
대입= += -=할당, 더해서 할당, 빼서 할당x += 3x = x + 3
기타typeof ? :타입 확인, 삼항 연산자typeof 42"number"

비교 연산자에서 ==(느슨한 비교)와 ===(엄격한 비교)의 차이를 기억하세요. 5 == "5"true이지만 5 === "5"false입니다. 실무에서는 항상 ===를 쓰는 것이 안전합니다.