JavaScript/JavaScript 입문
<script> 태그로 JS 불러오기 - Inline, Internal, External 방식 완전 가이드
코딩하는 패션이과생
2025. 5. 15. 23:39
반응형
script 태그란?
<script>
태그는 HTML 문서에 JavaScript 코드를 포함시키거나 외부 JavaScript 파일을 연결하는 HTML 요소입니다. 웹페이지에 동적 기능을 추가하기 위해 반드시 필요한 태그입니다.
🎯 script 태그의 역할
- JavaScript 코드 실행
- 외부 JavaScript 파일 연결
- 브라우저에게 JavaScript 코드 위치 알림
- 코드 실행 타이밍 제어
Inline JavaScript (인라인 방식)
📝 인라인 방식이란?
인라인 JavaScript는 HTML 요소의 속성 안에 직접 JavaScript 코드를 작성하는 방식입니다.
기본 문법
<!-- onclick 속성에 JavaScript 코드 작성 -->
<button onclick="alert('버튼 클릭!')">클릭하세요</button>
<!-- onmouseover 이벤트 -->
<div onmouseover="this.style.backgroundColor='yellow'">
마우스를 올려보세요
</div>
<!-- href 속성에 JavaScript 코드 -->
<a href="javascript:alert('링크 클릭!')">JavaScript 링크</a>
💭 실제 예제
<!DOCTYPE html>
<html>
<head>
<title>인라인 JavaScript 예제</title>
</head>
<body>
<h1>인라인 JavaScript 데모</h1>
<!-- 버튼 클릭 이벤트 -->
<button onclick="changeTitle()">제목 변경</button>
<!-- 색상 변경 버튼 -->
<button onclick="document.body.style.backgroundColor='lightblue'">
배경색 변경
</button>
<!-- 현재 시간 표시 -->
<button onclick="alert('현재 시간: ' + new Date().toLocaleTimeString())">
시간 보기
</button>
<script>
function changeTitle() {
document.getElementsByTagName('h1')[0].textContent = '제목이 변경되었습니다!';
}
</script>
</body>
</html>
✅ 인라인 방식의 장점
- 간단함: 작은 기능을 빠르게 추가 가능
- 직관적: 요소와 동작이 한눈에 보임
- 테스트: 프로토타이핑이나 간단한 테스트에 유용
❌ 인라인 방식의 단점
- 유지보수 어려움: HTML과 JavaScript가 섞여 있음
- 재사용성 부족: 같은 코드 반복 작성
- 보안 문제: XSS 공격에 취약할 수 있음
- 가독성 저하: 복잡한 코드를 작성하기 어려움
Internal JavaScript (내부 방식)
📄 내부 방식이란?
내부 JavaScript는 HTML 문서의 <script>
태그 안에 JavaScript 코드를 직접 작성하는 방식입니다.
기본 문법
<script>
// JavaScript 코드 작성
console.log("Hello World");
</script>
💡 실제 예제
<!DOCTYPE html>
<html>
<head>
<title>내부 JavaScript 예제</title>
<script>
// 페이지 로드 전에 실행
console.log("head의 script 실행");
// 함수 정의
function showWelcome() {
alert("환영합니다!");
}
</script>
</head>
<body>
<h1 id="title">내부 JavaScript 데모</h1>
<button onclick="showWelcome()">환영 메시지</button>
<button onclick="changeColor()">색상 변경</button>
<button onclick="showInfo()">정보 보기</button>
<script>
// body 끝에서 실행 - DOM 요소에 접근 가능
console.log("body의 script 실행");
function changeColor() {
const title = document.getElementById('title');
const colors = ['red', 'blue', 'green', 'purple', 'orange'];
const randomColor = colors[Math.floor(Math.random() * colors.length)];
title.style.color = randomColor;
}
function showInfo() {
const info = {
title: document.getElementById('title').textContent,
time: new Date().toLocaleString(),
url: window.location.href
};
alert(`제목: ${info.title}\n시간: ${info.time}\nURL: ${info.url}`);
}
// 페이지 로드 완료 후 실행
window.onload = function() {
console.log("페이지 로드 완료!");
};
</script>
</body>
</html>
📍 script 태그 위치별 특징
<!DOCTYPE html>
<html>
<head>
<script>
// ❌ DOM 요소에 접근 불가 - 아직 로드되지 않음
// const title = document.getElementById('title'); // null
// ✅ 함수 정의는 가능
function initPage() {
console.log("페이지 초기화");
}
</script>
</head>
<body>
<h1 id="title">제목</h1>
<script>
// ✅ 위의 DOM 요소에 접근 가능
const title = document.getElementById('title');
title.style.color = 'blue';
// ✅ head의 함수 호출 가능
initPage();
</script>
</body>
</html>
✅ 내부 방식의 장점
- 관리 용이: 한 파일에서 HTML과 JavaScript 관리
- 빠른 로딩: 별도 파일 요청 없어 로딩 시간 단축
- 프로토타이핑: 개발 초기 단계에서 유용
❌ 내부 방식의 단점
- 파일 크기: HTML 파일이 커질 수 있음
- 재사용 불가: 다른 페이지에서 사용 불가
- 캐싱 불가: JavaScript 코드 재사용으로 인한 성능 저하
External JavaScript (외부 방식)
🔗 외부 방식이란?
외부 JavaScript는 별도의 .js
파일에 JavaScript 코드를 작성하고, HTML에서 src
속성으로 연결하는 방식입니다.
기본 문법
<script src="파일경로/script.js"></script>
📁 파일 구조 예제
project/
├── index.html
├── about.html
└── js/
├── main.js
├── utils.js
└── app.js
💾 실제 예제
main.js 파일:
// main.js
console.log("외부 JavaScript 파일 로드됨");
// 전역 변수
let pageLoadTime = new Date();
// 유틸리티 함수들
function formatDate(date) {
return date.toLocaleDateString('ko-KR');
}
function formatTime(date) {
return date.toLocaleTimeString('ko-KR');
}
// 페이지 초기화 함수
function initializePage() {
// 페이지 로드 시간 표시
const loadTimeElement = document.getElementById('loadTime');
if (loadTimeElement) {
loadTimeElement.textContent = `페이지 로드 시간: ${formatTime(pageLoadTime)}`;
}
// 이벤트 리스너 등록
setupEventListeners();
}
function setupEventListeners() {
// 모든 버튼에 클릭 이벤트 추가
const buttons = document.querySelectorAll('button');
buttons.forEach(button => {
button.addEventListener('click', function() {
console.log(`버튼 클릭됨: ${this.textContent}`);
});
});
}
// DOM 로드 완료 후 실행
document.addEventListener('DOMContentLoaded', initializePage);
utils.js 파일:
// utils.js - 유틸리티 함수들
const Utils = {
// 랜덤 색상 생성
getRandomColor() {
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7'];
return colors[Math.floor(Math.random() * colors.length)];
},
// 요소 애니메이션
animateElement(element, duration = 300) {
element.style.transition = `all ${duration}ms ease`;
element.style.transform = 'scale(1.1)';
setTimeout(() => {
element.style.transform = 'scale(1)';
}, duration);
},
// 로컬 스토리지 헬퍼
storage: {
set(key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
get(key) {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : null;
}
}
};
index.html 파일:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>외부 JavaScript 예제</title>
<!-- CDN에서 외부 라이브러리 로드 -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<h1>외부 JavaScript 데모</h1>
<p id="loadTime"></p>
<button onclick="changeBackgroundColor()">배경색 변경</button>
<button onclick="showCurrentTime()">현재 시간</button>
<button onclick="saveToStorage()">데이터 저장</button>
<button onclick="loadFromStorage()">데이터 불러오기</button>
<!-- 외부 JavaScript 파일들 로드 -->
<script src="js/utils.js"></script>
<script src="js/main.js"></script>
<!-- 페이지별 스크립트 -->
<script>
function changeBackgroundColor() {
document.body.style.backgroundColor = Utils.getRandomColor();
Utils.animateElement(document.body);
}
function showCurrentTime() {
alert(`현재 시간: ${formatTime(new Date())}`);
}
function saveToStorage() {
const data = {
timestamp: new Date().toISOString(),
page: 'index',
visits: (Utils.storage.get('visits') || 0) + 1
};
Utils.storage.set('pageData', data);
alert('데이터가 저장되었습니다!');
}
function loadFromStorage() {
const data = Utils.storage.get('pageData');
if (data) {
alert(`저장된 데이터:\n마지막 방문: ${formatDate(new Date(data.timestamp))}\n방문 횟수: ${data.visits}`);
} else {
alert('저장된 데이터가 없습니다.');
}
}
</script>
</body>
</html>
✅ 외부 방식의 장점
- 재사용성: 여러 HTML 파일에서 동일한 JS 파일 사용
- 유지보수: 코드 분리로 관리가 용이
- 캐싱: 브라우저가 JS 파일을 캐시하여 성능 향상
- 협업: 팀 개발 시 역할 분담 가능
- 모듈화: 기능별로 파일 분리 가능
❌ 외부 방식의 단점
- HTTP 요청: 추가 네트워크 요청 필요
- 경로 관리: 파일 경로 오류 가능성
- 의존성: 파일 로드 순서 고려 필요
세 방식 비교 분석
📊 종합 비교표
특징 | Inline | Internal | External |
---|---|---|---|
코드 위치 | HTML 속성 내 | <script> 태그 내 |
별도 .js 파일 |
재사용성 | ❌ 낮음 | ❌ 불가능 | ✅ 높음 |
유지보수 | ❌ 어려움 | ⚠️ 보통 | ✅ 쉬움 |
성능 | ✅ 빠름 | ✅ 빠름 | ⚠️ 추가 요청 |
캐싱 | ❌ 불가능 | ❌ 불가능 | ✅ 가능 |
디버깅 | ❌ 어려움 | ⚠️ 보통 | ✅ 쉬움 |
협업 | ❌ 어려움 | ❌ 어려움 | ✅ 쉬움 |
🎯 언제 어떤 방식을 사용할까?
Inline JavaScript 사용 시기:
- 매우 간단한 이벤트 처리 (1-2줄)
- 프로토타이핑이나 테스트
- 이메일 템플릿 (외부 파일 불가)
Internal JavaScript 사용 시기:
- 해당 페이지에만 필요한 코드
- 작은 프로젝트나 단일 페이지
- 서버 사이드 렌더링 최적화
External JavaScript 사용 시기:
- 재사용 가능한 기능
- 대규모 프로젝트
- 팀 개발 환경
- 성능 최적화가 중요한 경우
script 태그의 추가 속성
🔄 async와 defer 속성
<!-- 기본 방식: HTML 파싱 중단하고 JS 실행 -->
<script src="script.js"></script>
<!-- async: 백그라운드에서 로드하고 완료되면 즉시 실행 -->
<script src="script.js" async></script>
<!-- defer: 백그라운드에서 로드하고 HTML 파싱 완료 후 실행 -->
<script src="script.js" defer></script>
📈 로딩 순서 비교
일반 script: HTML 파싱 ──┐ ┌─── HTML 파싱
↓ ↑
JS 다운로드 + 실행
async script: HTML 파싱 ────────────────────
JS 다운로드 ──┐
↓
JS 실행
defer script: HTML 파싱 ─────────────────┬─
JS 다운로드 ───────────────┘
↓
JS 실행
🔧 기타 유용한 속성
<!-- 타입 지정 (ES6 모듈) -->
<script type="module" src="module.js"></script>
<!-- 무결성 검증 -->
<script src="https://cdn.example.com/library.js"
integrity="sha384-abc123..."
crossorigin="anonymous"></script>
<!-- noscript 대체 내용 -->
<noscript>
<p>JavaScript가 비활성화되어 있습니다.</p>
</noscript>
실무에서의 모범 사례
🏆 권장 사항
- 외부 파일 우선 사용
<!-- ✅ 권장 --> <script src="js/main.js" defer></script>
2. **로딩 순서 최적화**
```html
<!DOCTYPE html>
<html>
<head>
<!-- 필수 라이브러리는 head에 -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
</head>
<body>
<!-- 콘텐츠 -->
<!-- 페이지별 스크립트는 body 끝에 -->
<script src="js/utils.js"></script>
<script src="js/main.js"></script>
<script src="js/page-specific.js"></script>
</body>
</html>
- 환경별 파일 로드
<!-- 개발 환경 --> <script src="js/app.js"></script>
### 🛡️ 보안 고려사항
```html
<!-- CSP (Content Security Policy) 설정 -->
<meta http-equiv="Content-Security-Policy"
content="script-src 'self' https://trusted-cdn.com;">
<!-- 신뢰할 수 있는 CDN 사용 -->
<script src="https://cdn.jsdelivr.net/npm/library@1.0.0/dist/library.min.js"
integrity="sha384-..."
crossorigin="anonymous"></script>
완전한 예제
🎉 실제 프로젝트 구조
프로젝트 파일 구조:
my-website/
├── index.html
├── about.html
├── css/
│ └── style.css
└── js/
├── config.js # 설정 파일
├── utils.js # 유틸리티 함수
├── components.js # UI 컴포넌트
└── main.js # 메인 로직
index.html:
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript 로딩 방식 완전 예제</title>
<link rel="stylesheet" href="css/style.css">
<!-- 설정 파일 먼저 로드 -->
<script src="js/config.js"></script>
</head>
<body>
<header>
<h1>JavaScript 로딩 방식 데모</h1>
<nav>
<button onclick="showSection('inline')">Inline</button>
<button onclick="showSection('internal')">Internal</button>
<button onclick="showSection('external')">External</button>
</nav>
</header>
<main>
<section id="inline" class="demo-section">
<h2>Inline JavaScript</h2>
<button onclick="alert('Inline 방식 알림!')">
Inline 알림
</button>
<div onmouseover="this.style.backgroundColor='yellow'"
onmouseout="this.style.backgroundColor='transparent'">
마우스를 올려보세요 (Inline)
</div>
</section>
<section id="internal" class="demo-section">
<h2>Internal JavaScript</h2>
<button id="internalBtn">Internal 버튼</button>
<div id="internalDiv">Internal 영역</div>
</section>
<section id="external" class="demo-section">
<h2>External JavaScript</h2>
<button id="externalBtn">External 버튼</button>
<div id="counter">카운터: <span id="count">0</span></div>
</section>
</main>
<!-- Internal JavaScript -->
<script>
// Internal 방식 데모
document.getElementById('internalBtn').addEventListener('click', function() {
const div = document.getElementById('internalDiv');
div.innerHTML = `<p>Internal 방식으로 업데이트됨! 시간: ${new Date().toLocaleTimeString()}</p>`;
div.style.backgroundColor = '#e3f2fd';
});
// 섹션 표시/숨김 함수
function showSection(sectionName) {
const sections = document.querySelectorAll('.demo-section');
sections.forEach(section => {
section.style.display = 'none';
});
document.getElementById(sectionName).style.display = 'block';
}
// 페이지 로드 시 첫 번째 섹션 표시
window.addEventListener('load', function() {
showSection('inline');
});
</script>
<!-- External JavaScript 파일들 -->
<script src="js/utils.js"></script>
<script src="js/components.js"></script>
<script src="js/main.js"></script>
</body>
</html>
js/config.js:
// 전역 설정
window.APP_CONFIG = {
version: '1.0.0',
debug: true,
apiUrl: 'https://api.example.com',
colors: {
primary: '#2196F3',
secondary: '#FF9800',
success: '#4CAF50',
error: '#F44336'
}
};
js/utils.js:
// 유틸리티 함수들
const Utils = {
log(message) {
if (APP_CONFIG.debug) {
console.log(`[${new Date().toISOString()}] ${message}`);
}
},
formatNumber(num) {
return num.toLocaleString();
},
debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
};
js/components.js:
// UI 컴포넌트
const Components = {
createButton(text, onclick) {
const button = document.createElement('button');
button.textContent = text;
button.onclick = onclick;
return button;
},
showToast(message, type = 'info') {
const toast = document.createElement('div');
toast.className = `toast toast-${type}`;
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(() => {
toast.remove();
}, 3000);
}
};
js/main.js:
// 메인 애플리케이션 로직
let counter = 0;
// External 방식 데모
function initExternalDemo() {
const btn = document.getElementById('externalBtn');
const countSpan = document.getElementById('count');
btn.addEventListener('click', Utils.debounce(function() {
counter++;
countSpan.textContent = Utils.formatNumber(counter);
Utils.log(`카운터 업데이트: ${counter}`);
Components.showToast(`카운터가 ${counter}로 업데이트되었습니다!`, 'success');
// 색상 변경
btn.style.backgroundColor = counter % 2 === 0 ?
APP_CONFIG.colors.primary : APP_CONFIG.colors.secondary;
}, 300));
}
// DOM 로드 완료 후 실행
document.addEventListener('DOMContentLoaded', function() {
Utils.log('애플리케이션 초기화됨');
initExternalDemo();
});
마무리
<script>
태그를 사용한 JavaScript 로딩 방식은 웹 개발의 핵심 기초입니다. 각 방식의 특징을 이해하고 상황에 맞게 선택하는 것이 중요합니다.
✅ 핵심 정리
- Inline: 간단한 이벤트 처리용
- Internal: 페이지별 특화 코드용
- External: 재사용 가능한 모듈용
🚀 실무 권장사항
- 가능한 한 External 방식 우선 사용
- defer 속성으로 로딩 최적화
- 파일을 기능별로 분리하여 관리
- 캐싱과 압축을 통한 성능 향상
이제 여러분은 JavaScript를 HTML에 효과적으로 연결하는 방법을 알게 되었습니다. 실제 프로젝트에서 이 지식을 활용해보세요!
이 글이 JavaScript 연결 방식 이해에 도움이 되셨나요? 어려운 부분이나 추가 질문이 있다면 댓글로 남겨주세요! 💬