مشروع آلة حاسبة بـ JavaScript — دليل عملي شامل 2026
مشروع عملي لبناء آلة حاسبة كاملة بـ JavaScript و HTML و CSS — خطوة بخطوة مع الكود الكامل والشرح
في المقالات السابقة، تعلمت أساسيات JavaScript — المتغيرات، الشروط، الحلقات، الدوال، المصفوفات، والكائنات، وأخيراً DOM. الآن حان الوقت لتطبيق كل هذه المفاهيم في مشروع حقيقي: آلة حاسبة كاملة.
في هذا الدليل العملي، سنبني آلة حاسبة من الصفر — HTML للهيكل، CSS للتصميم، JavaScript للوظائف. مع الكود الكامل والشرح خطوة بخطوة.
ما سنبنيه
آلة حاسبة بوظائف:
- الجمع، الطرح، الضرب، القسمة
- النسبة المئوية
- تغيير الإشارة (+/-)
- المسح (C)
- الفاصلة العشرية
- عرض النتيجة مباشرة
لماذا هذا المشروع؟
- تطبيق عملي: تستخدم كل ما تعلمته.
- مشروع حقيقي: يمكنك إضافته لمعرض أعمالك.
- فهم DOM: تتعامل مع الأحداث والنصوص.
- منطق البرمجة: تفكر كالمبرمجين.
هيكل المشروع
سننشئ 3 ملفات:
calculator/
├── index.html
├── style.css
└── script.js
الخطوة 1: HTML — هيكل الآلة الحاسبة
index.html:
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>آلة حاسبة JavaScript</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="calculator">
<div class="display">
<div class="previous-operand"></div>
<div class="current-operand">0</div>
</div>
<div class="buttons">
<button class="span-two" data-action="clear">C</button>
<button data-action="delete">DEL</button>
<button data-action="operator" data-operator="/">÷</button>
<button data-number="7">7</button>
<button data-number="8">8</button>
<button data-number="9">9</button>
<button data-action="operator" data-operator="*">×</button>
<button data-number="4">4</button>
<button data-number="5">5</button>
<button data-number="6">6</button>
<button data-action="operator" data-operator="-">−</button>
<button data-number="1">1</button>
<button data-number="2">2</button>
<button data-number="3">3</button>
<button data-action="operator" data-operator="+">+</button>
<button data-action="sign">+/-</button>
<button data-number="0">0</button>
<button data-number=".">.</button>
<button data-action="equals">=</button>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
شرح:
display: شاشة الآلة الحاسبة (رقم سابق + رقم حالي).buttons: شبكة الأزرار.data-*: خصائص لتحديد نوع الزر (رقم، عملية، وظيفة).
الخطوة 2: CSS — تصميم الآلة الحاسبة
style.css:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, sans-serif;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 20px;
}
.calculator {
background: #1e293b;
border-radius: 20px;
padding: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
width: 100%;
max-width: 400px;
}
.display {
background: #0f172a;
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
text-align: left;
direction: ltr;
min-height: 100px;
display: flex;
flex-direction: column;
justify-content: space-between;
word-wrap: break-word;
word-break: break-all;
}
.previous-operand {
color: #94a3b8;
font-size: 1.2rem;
min-height: 1.5rem;
}
.current-operand {
color: #ffffff;
font-size: 2.5rem;
font-weight: bold;
}
.buttons {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
}
button {
padding: 20px;
font-size: 1.3rem;
font-weight: bold;
border: none;
border-radius: 12px;
cursor: pointer;
transition: all 0.2s;
background: #334155;
color: #ffffff;
}
button:hover {
background: #475569;
transform: scale(1.05);
}
button:active {
transform: scale(0.95);
}
.span-two {
grid-column: span 2;
background: #ef4444;
}
.span-two:hover {
background: #dc2626;
}
[data-action="operator"] {
background: #f59e0b;
}
[data-action="operator"]:hover {
background: #d97706;
}
[data-action="equals"] {
background: #10b981;
}
[data-action="equals"]:hover {
background: #059669;
}
[data-action="delete"],
[data-action="sign"] {
background: #64748b;
}
الخطوة 3: JavaScript — منطق الآلة الحاسبة
script.js:
// ==================== المتغيرات ====================
let currentOperand = "0";
let previousOperand = "";
let operation = undefined;
// ==================== العناصر ====================
const currentOperandEl = document.querySelector(".current-operand");
const previousOperandEl = document.querySelector(".previous-operand");
const buttons = document.querySelectorAll("button");
// ==================== الدوال ====================
// تحديث الشاشة
function updateDisplay() {
currentOperandEl.textContent = currentOperand;
if (operation != null) {
previousOperandEl.textContent = `${previousOperand} ${getOperatorSymbol(operation)}`;
} else {
previousOperandEl.textContent = "";
}
}
// الحصول على رمز العملية
function getOperatorSymbol(op) {
const symbols = {
"+": "+",
"-": "−",
"*": "×",
"/": "÷",
};
return symbols[op] || op;
}
// إضافة رقم
function appendNumber(number) {
if (number === "." && currentOperand.includes(".")) return;
if (currentOperand === "0" && number !== ".") {
currentOperand = number;
} else {
currentOperand += number;
}
}
// اختيار العملية
function chooseOperation(op) {
if (currentOperand === "") return;
if (previousOperand !== "") {
compute();
}
operation = op;
previousOperand = currentOperand;
currentOperand = "";
}
// الحساب
function compute() {
let computation;
const prev = parseFloat(previousOperand);
const current = parseFloat(currentOperand);
if (isNaN(prev) || isNaN(current)) return;
switch (operation) {
case "+":
computation = prev + current;
break;
case "-":
computation = prev - current;
break;
case "*":
computation = prev * current;
break;
case "/":
if (current === 0) {
alert("لا يمكن القسمة على صفر!");
clear();
return;
}
computation = prev / current;
break;
default:
return;
}
currentOperand = computation.toString();
operation = undefined;
previousOperand = "";
}
// المسح
function clear() {
currentOperand = "0";
previousOperand = "";
operation = undefined;
}
// الحذف
function deleteNumber() {
if (currentOperand.length === 1) {
currentOperand = "0";
} else {
currentOperand = currentOperand.slice(0, -1);
}
}
// تغيير الإشارة
function toggleSign() {
if (currentOperand === "0") return;
if (currentOperand.startsWith("-")) {
currentOperand = currentOperand.slice(1);
} else {
currentOperand = "-" + currentOperand;
}
}
// ==================== الأحداث ====================
buttons.forEach((button) => {
button.addEventListener("click", () => {
// أرقام
if (button.dataset.number) {
appendNumber(button.dataset.number);
updateDisplay();
return;
}
// عمليات
if (button.dataset.action === "operator") {
chooseOperation(button.dataset.operator);
updateDisplay();
return;
}
// وظائف
switch (button.dataset.action) {
case "clear":
clear();
break;
case "delete":
deleteNumber();
break;
case "equals":
compute();
break;
case "sign":
toggleSign();
break;
}
updateDisplay();
});
});
// ==================== لوحة المفاتيح ====================
document.addEventListener("keydown", (event) => {
const key = event.key;
// أرقام
if (/^[0-9.]$/.test(key)) {
appendNumber(key);
updateDisplay();
return;
}
// عمليات
if (["+", "-", "*", "/"].includes(key)) {
chooseOperation(key);
updateDisplay();
return;
}
// مسح
if (key === "Escape") {
clear();
updateDisplay();
return;
}
// حذف
if (key === "Backspace") {
deleteNumber();
updateDisplay();
return;
}
// يساوي
if (key === "Enter" || key === "=") {
event.preventDefault();
compute();
updateDisplay();
return;
}
});
// ==================== التهيئة ====================
updateDisplay();
شرح الكود خطوة بخطوة
1. المتغيرات الأساسية
let currentOperand = "0"; // الرقم الحالي المعروض
let previousOperand = ""; // الرقم السابق
let operation = undefined; // العملية الحالية (+, -, *, /)
2. تحديث الشاشة
function updateDisplay() {
currentOperandEl.textContent = currentOperand;
if (operation != null) {
previousOperandEl.textContent = `${previousOperand} ${operation}`;
} else {
previousOperandEl.textContent = "";
}
}
3. إضافة رقم
function appendNumber(number) {
if (number === "." && currentOperand.includes(".")) return;
if (currentOperand === "0" && number !== ".") {
currentOperand = number;
} else {
currentOperand += number;
}
}
المنطق:
- إذا كان الرقم نقطة عشرية والرقم يحتوي على نقطة، لا تفعل شيئاً.
- إذا كان الرقم الحالي
"0"، استبدله. - وإلا، أضف الرقم.
4. اختيار العملية
function chooseOperation(op) {
if (currentOperand === "") return;
if (previousOperand !== "") {
compute(); // احسب العملية السابقة أولاً
}
operation = op;
previousOperand = currentOperand;
currentOperand = "";
}
5. الحساب
function compute() {
const prev = parseFloat(previousOperand);
const current = parseFloat(currentOperand);
if (isNaN(prev) || isNaN(current)) return;
switch (operation) {
case "+": computation = prev + current; break;
case "-": computation = prev - current; break;
case "*": computation = prev * current; break;
case "/":
if (current === 0) { alert("لا يمكن القسمة على صفر!"); clear(); return; }
computation = prev / current; break;
}
currentOperand = computation.toString();
operation = undefined;
previousOperand = "";
}
6. الأحداث
buttons.forEach((button) => {
button.addEventListener("click", () => {
if (button.dataset.number) {
appendNumber(button.dataset.number);
} else if (button.dataset.action === "operator") {
chooseOperation(button.dataset.operator);
} else {
// معالجة الأزرار الأخرى
}
updateDisplay();
});
});
تمارين إضافية
تمرين 1: إضافة زر النسبة المئوية
أضف زر % يحول الرقم الحالي إلى نسبته.
الحل:
أضف في HTML:
<button data-action="percent">%</button>
أضف في JavaScript:
function percent() {
currentOperand = (parseFloat(currentOperand) / 100).toString();
}
// في switch
case "percent":
percent();
break;
تمرين 2: إضافة الذاكرة (M+ / M-)
أضف زرين لحفظ واسترجاع قيمة.
الحل:
let memory = 0;
// M+ : إضافة للذاكرة
function memoryAdd() {
memory += parseFloat(currentOperand) || 0;
}
// M- : طرح من الذاكرة
function memorySubtract() {
memory -= parseFloat(currentOperand) || 0;
}
// MR : استرجاع الذاكرة
function memoryRecall() {
currentOperand = memory.toString();
}
تمرين 3: إضافة الجذر التربيعي
أضف زر √ لحساب الجذر التربيعي.
الحل:
function squareRoot() {
const num = parseFloat(currentOperand);
if (num < 0) {
alert("لا يمكن حساب جذر عدد سالب!");
return;
}
currentOperand = Math.sqrt(num).toString();
}
تمرين 4: سجل العمليات
أضف قائمة تعرض آخر 5 عمليات.
الحل:
const history = [];
function addToHistory(expression, result) {
history.push(`${expression} = ${result}`);
if (history.length > 5) history.shift();
displayHistory();
}
function displayHistory() {
const historyEl = document.querySelector(".history");
historyEl.innerHTML = history.map(h => `<div>${h}</div>`).join("");
}
تمرين 5: الوضع الداكن/الفاتح
أضف زراً لتبديل الوضع.
الحل:
const themeBtn = document.querySelector(".theme-toggle");
themeBtn.addEventListener("click", () => {
document.body.classList.toggle("light-mode");
});
حل المشاكل الشائعة
🔴 المشكلة 1: القسمة على صفر
السبب: محاولة القسمة على صفر تنتج Infinity.
الحل: تحقق قبل القسمة:
if (current === 0) {
alert("لا يمكن القسمة على صفر!");
clear();
return;
}
🔴 المشكلة 2: النقطة العشرية تتكرر
السبب: إضافة . أكثر من مرة.
الحل:
if (number === "." && currentOperand.includes(".")) return;
🔴 المشكلة 3: الأرقام الطويلة تكسر التصميم
الحل: استخدم word-break: break-all في CSS، وحدد عدد الأرقام:
if (currentOperand.replace(/[^0-9]/g, "").length > 12) return;
🔴 المشكلة 4: النتائج العشرية غير دقيقة
السبب: JavaScript تعاني من مشاكل دقة الأرقام العشرية (0.1 + 0.2 ≠ 0.3).
الحل: استخدم toFixed:
currentOperand = computation.toFixed(10).replace(/\.?0+$/, "");
قائمة تحقق نهائية
| المهمة | الحالة |
|---|---|
| إنشاء ملف index.html | ⬜ |
| إنشاء ملف style.css | ⬜ |
| إنشاء ملف script.js | ⬜ |
| تشغيل الآلة الحاسبة في المتصفح | ⬜ |
| اختبار الجمع والطرح والضرب والقسمة | ⬜ |
| اختبار الحذف والمسح | ⬜ |
| حل تمرين واحد على الأقل إضافي | ⬜ |
ماذا بعد هذا المشروع؟
الآن بعد أن بنيت آلة حاسبة كاملة، أنت جاهز لـ:
- مشروع قائمة المهام — تطبيق أكثر تعقيداً.
- Async/Await — البرمجة غير المتزامنة.
- Fetch API — التعامل مع الخوادم.
الخلاصة
في هذا المشروع، طبقت:
- ✅ HTML لبناء الواجهة.
- ✅ CSS لتصميم جميل.
- ✅ JavaScript للمنطق والتفاعل.
- ✅ DOM للتعامل مع العناصر.
- ✅ الأحداث للتفاعل مع المستخدم.
- ✅ الدوال لتنظيم الكود.
هذا المشروع هو حجر الأساس لبناء تطبيقات أكثر تعقيداً. احتفظ بالكود، وطور فيه بنفسك!
هل بنيت آلة الحاسبة بنجاح؟ شاركنا في التعليقات!
التعامل مع DOM في JavaScript — دليل شامل 2026
مشروع قائمة المهام بـ JavaScript — دليل عملي شامل 2026
📚 مقالات ذات صلة
مشروع قائمة المهام بـ JavaScript — دليل عملي شامل 2026
مشروع عملي لبناء تطبيق قائمة مهام كامل بـ JavaScript — إضافة، حذف، تعديل، حفظ تلقائي، مع الكود الكامل والشرح
التعامل مع DOM في JavaScript — دليل شامل 2026
دليل عملي مفصل للتعامل مع DOM في JavaScript — التحديد، التعديل، الأحداث، الإنشاء، مع تمارين وحلول
المصفوفات والكائنات في JavaScript — دليل شامل 2026
دليل عملي مفصل للمصفوفات والكائنات في JavaScript — الإنشاء، التعديل، الطرق الشائعة، مع تمارين وحلول