We are still cooking the magic in the way!
الارقام وكائن Math
مقدمة في الارقام في جافاسكريبت
الارقام هي واحدة من نوعين اساسيين من البيانات البدائية التي ستعمل معها باستمرار في جافاسكريبت الى جانب النصوص. على عكس العديد من لغات البرمجة الاخرى التي تميز بين الاعداد الصحيحة والعشرية والمزدوجة وانواع رقمية اخرى، فان جافاسكريبت لديها نوع رقمي واحد فقط. كل رقم في جافاسكريبت سواء كان 42 او 3.14 او -100 يمثل كقيمة عشرية مزدوجة الدقة بحجم 64 بت وفقا لمعيار IEEE 754. هذه البساطة تجعل البدء بجافاسكريبت سهلا لكنها تقدم ايضا بعض الخصائص ومشاكل الدقة التي يجب على كل مطور فهمها. في هذا الدرس ستتعلم كيف تعمل الارقام في جافاسكريبت وكيفية تحليلها وتنسيقها وكيفية استخدام كائن Math القوي للحسابات.
انواع الارقام: الاعداد الصحيحة والعشرية
على الرغم من ان جافاسكريبت تعامل جميع الارقام كقيم عشرية داخليا يمكنك العمل معها كما لو كانت اعدادا صحيحة او عشرية. لا يوجد نوع منفصل للاعداد الصحيحة -- التمييز يكون فقط في كيفية استخدامك للارقام.
مثال: الاعداد الصحيحة والعشرية
// الاعداد الصحيحة
let count = 42;
let negative = -17;
let zero = 0;
// الاعداد العشرية
let pi = 3.14159;
let temperature = -40.5;
let tiny = 0.001;
// كلاهما نفس النوع
console.log(typeof count); // number
console.log(typeof pi); // number
console.log(typeof NaN); // number (نعم NaN من نوع number!)
// جافاسكريبت لا تميز بين int و float
console.log(10 === 10.0); // true
console.log(1 === 1.0000); // true
// فواصل الارقام (ES2021) -- لتحسين القراءة
let billion = 1_000_000_000;
let bytes = 0xFF_FF;
let fraction = 0.000_001;
console.log(billion); // 1000000000
console.log(bytes); // 65535
// الترميز العلمي
let large = 3e8; // 3 x 10^8 = 300000000
let small = 1.5e-6; // 1.5 x 10^-6 = 0.0000015
console.log(large); // 300000000
console.log(small); // 0.0000015
// قواعد عددية اخرى
let binary = 0b1010; // ثنائي (اساس 2) = 10
let octal = 0o755; // ثماني (اساس 8) = 493
let hex = 0xFF; // سداسي عشر (اساس 16) = 255
console.log(binary); // 10
console.log(octal); // 493
console.log(hex); // 255
_) قدم في ES2021 وليس له اي تاثير على القيمة. هو فقط لتحسين القراءة مشابه لكيفية كتابة 1,000,000 على الورق. استخدمه بحرية لجعل الارقام الكبيرة اسهل في القراءة في الكود.القيم الرقمية الخاصة
لدى جافاسكريبت عدة قيم رقمية خاصة ستصادفها. فهمها ضروري لكتابة كود متين يتعامل مع الحالات الحدية بشكل صحيح.
مثال: القيم الرقمية الخاصة
// اللانهاية
console.log(Infinity); // Infinity
console.log(-Infinity); // -Infinity
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log(Infinity + 1); // Infinity
console.log(Infinity * Infinity); // Infinity
// NaN (ليس رقما)
console.log(NaN); // NaN
console.log(0 / 0); // NaN
console.log('hello' * 2); // NaN
console.log(Math.sqrt(-1)); // NaN
// NaN لا تساوي اي شيء بما في ذلك نفسها!
console.log(NaN === NaN); // false
console.log(NaN == NaN); // false
// استخدم Number.isNaN() للتحقق من NaN (وليس isNaN العامة)
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN('hello')); // false (صحيح!)
console.log(isNaN('hello')); // true (خاطئ! isNaN العامة تحول النوع)
// الصفر الموجب والسالب
console.log(0 === -0); // true (تعتبر متساوية)
console.log(Object.is(0, -0)); // false (Object.is تميز بينهما)
console.log(1 / 0); // Infinity
console.log(1 / -0); // -Infinity
isNaN() العامة للتحقق من NaN. فهي تحول معاملها الى رقم اولا لذلك isNaN('hello') تعيد true رغم ان النص 'hello' ليس NaN -- انه نص. استخدم دائما Number.isNaN() بدلا من ذلك التي تعيد true فقط لقيمة NaN الفعلية.نطاق الاعداد الصحيحة الآمنة: Number.MAX_SAFE_INTEGER
لان جافاسكريبت تستخدم تمثيل النقطة العائمة 64 بت هناك حد لمدى دقة تمثيلها للاعداد الصحيحة. بعد نطاق معين تصبح العمليات الحسابية على الاعداد الصحيحة غير موثوقة. توفر جافاسكريبت ثوابت لمساعدتك على فهم هذه الحدود.
مثال: حدود سلامة الاعداد الصحيحة
// اكبر عدد صحيح آمن: 2^53 - 1
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991
// ابعد من النطاق الآمن تفقد الدقة
console.log(9007199254740991); // 9007199254740991 (صحيح)
console.log(9007199254740992); // 9007199254740992 (يبدو صحيحا)
console.log(9007199254740993); // 9007199254740992 (خطا! نفس ما سبق)
// التحقق مما اذا كان الرقم عددا صحيحا آمنا
console.log(Number.isSafeInteger(42)); // true
console.log(Number.isSafeInteger(9007199254740991)); // true
console.log(Number.isSafeInteger(9007199254740992)); // false
console.log(Number.isSafeInteger(3.14)); // false (ليس عددا صحيحا)
// حدود رقمية اخرى
console.log(Number.MAX_VALUE); // 1.7976931348623157e+308
console.log(Number.MIN_VALUE); // 5e-324 (اصغر رقم موجب)
console.log(Number.EPSILON); // 2.220446049250313e-16
// BigInt للارقام ابعد من نطاق الاعداد الصحيحة الآمنة (ES2020)
let huge = 9007199254740993n; // لاحظ لاحقة 'n'
console.log(huge); // 9007199254740993n (صحيح!)
let hugeCalc = BigInt(9007199254740991) + 2n;
console.log(hugeCalc); // 9007199254740993n
// BigInt لا يمكن خلطها مع الارقام العادية
// console.log(huge + 1); // TypeError!
console.log(huge + 1n); // 9007199254740994n (يجب استخدام BigInt)
تحليل الارقام: parseInt و parseFloat
عندما تستقبل بيانات من مدخلات المستخدم او معاملات URL او واجهات برمجة التطبيقات غالبا تصل كنص. توفر جافاسكريبت دالتين اساسيتين لتحويل النصوص الى ارقام: parseInt() للاعداد الصحيحة وparseFloat() للاعداد العشرية.
مثال: parseInt و parseFloat
// parseInt - تحلل نصا وتعيد عددا صحيحا
console.log(parseInt('42')); // 42
console.log(parseInt('42.9')); // 42 (تقطع ولا تقرب)
console.log(parseInt(' 100 ')); // 100 (تزيل المسافات)
console.log(parseInt('10px')); // 10 (تتوقف عند الحرف غير الرقمي)
console.log(parseInt('width: 200')); // NaN (لا يمكن البدء بحرف غير رقمي)
console.log(parseInt('')); // NaN
// parseInt مع الاساس -- حدد الاساس دائما!
console.log(parseInt('0xFF', 16)); // 255 (سداسي عشر)
console.log(parseInt('111', 2)); // 7 (ثنائي)
console.log(parseInt('777', 8)); // 511 (ثماني)
console.log(parseInt('10', 10)); // 10 (عشري صريح)
// parseFloat - تحلل نصا وتعيد عددا عشريا
console.log(parseFloat('3.14')); // 3.14
console.log(parseFloat('3.14.15')); // 3.14 (تتوقف عند النقطة الثانية)
console.log(parseFloat('.5')); // 0.5
console.log(parseFloat('100px')); // 100
console.log(parseFloat('abc')); // NaN
// مُنشئ Number() -- تحويل اكثر صرامة
console.log(Number('42')); // 42
console.log(Number('42.9')); // 42.9
console.log(Number('10px')); // NaN (اكثر صرامة من parseInt!)
console.log(Number('')); // 0 (النص الفارغ يصبح 0)
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
// عامل الجمع الاحادي -- اختصار لـ Number()
console.log(+'42'); // 42
console.log(+'3.14'); // 3.14
console.log(+'hello'); // NaN
console.log(+true); // 1
console.log(+''); // 0
// مثال عملي: تحليل مدخلات المستخدم بامان
function parseUserAge(input) {
let age = parseInt(input, 10);
if (Number.isNaN(age) || age < 0 || age > 150) {
return null;
}
return age;
}
console.log(parseUserAge('25')); // 25
console.log(parseUserAge('abc')); // null
console.log(parseUserAge('-5')); // null
console.log(parseUserAge('200')); // null
parseInt(). بدونه كانت parseInt('08') تفسر كثماني في المتصفحات القديمة وتعيد 0 بدلا من 8. المتصفحات الحديثة تستخدم الاساس 10 افتراضيا لكن تحديد parseInt(value, 10) يجعل نيتك واضحة ويمنع الاخطاء الدقيقة.تنسيق الارقام: toFixed و toPrecision
عند عرض الارقام للمستخدمين غالبا تحتاج للتحكم في عدد المنازل العشرية او الارقام المعنوية المعروضة. توفر جافاسكريبت طريقتين لهذا الغرض: toFixed() للمنازل العشرية وtoPrecision() للارقام المعنوية.
مثال: toFixed و toPrecision
// toFixed(digits) -- تنسق الى منازل عشرية ثابتة (تعيد نصا)
let price = 19.5;
console.log(price.toFixed(2)); // "19.50"
console.log(price.toFixed(0)); // "20" (تقرب!)
console.log(price.toFixed(4)); // "19.5000"
let pi = 3.14159;
console.log(pi.toFixed(2)); // "3.14"
console.log(pi.toFixed(3)); // "3.142" (تقرب لاعلى)
// مهم: toFixed تعيد نصا وليس رقما
let formatted = (19.99).toFixed(2);
console.log(typeof formatted); // string
console.log(formatted + 1); // "19.991" (ربط نصوص!)
console.log(parseFloat(formatted) + 1); // 20.99 (صحيح!)
// toPrecision(digits) -- تنسق الى N رقما معنويا (تعيد نصا)
let num = 123.456;
console.log(num.toPrecision(6)); // "123.456"
console.log(num.toPrecision(5)); // "123.46"
console.log(num.toPrecision(4)); // "123.5"
console.log(num.toPrecision(3)); // "123"
console.log(num.toPrecision(2)); // "1.2e+2"
console.log(num.toPrecision(1)); // "1e+2"
// toString مع الاساس -- تحويل الى قواعد مختلفة
let decimal = 255;
console.log(decimal.toString(16)); // "ff" (سداسي عشر)
console.log(decimal.toString(2)); // "11111111" (ثنائي)
console.log(decimal.toString(8)); // "377" (ثماني)
// مثال عملي: تنسيق العملة
function formatCurrency(amount, currency = 'USD') {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: currency
}).format(amount);
}
console.log(formatCurrency(1234.5)); // $1,234.50
console.log(formatCurrency(1234.5, 'EUR')); // (يورو)1,234.50
// تنسيق الارقام الكبيرة بفواصل
function formatNumber(num) {
return num.toLocaleString('en-US');
}
console.log(formatNumber(1234567.89)); // 1,234,567.89
console.log(formatNumber(1000000)); // 1,000,000
toFixed() وtoPrecision() تعيدان نصوصا وليس ارقاما. هذا مصدر متكرر للاخطاء. اذا كنت تحتاج لاجراء حسابات اخرى حول النتيجة الى رقم باستخدام parseFloat() او عامل الجمع الاحادي +.التحقق من انواع الارقام: isFinite و isInteger
توفر جافاسكريبت طرقا مساعدة على كائن Number للتحقق من طبيعة القيم الرقمية. هذه ضرورية للتحقق من المدخلات والبرمجة الدفاعية.
مثال: طرق التحقق من الارقام
// Number.isFinite -- تتحقق مما اذا كانت القيمة رقما منتهيا
console.log(Number.isFinite(42)); // true
console.log(Number.isFinite(3.14)); // true
console.log(Number.isFinite(Infinity)); // false
console.log(Number.isFinite(-Infinity)); // false
console.log(Number.isFinite(NaN)); // false
console.log(Number.isFinite('42')); // false (بدون تحويل!)
// isFinite العامة مقابل Number.isFinite
console.log(isFinite('42')); // true (تحول النص الى رقم!)
console.log(Number.isFinite('42')); // false (بدون تحويل صحيح!)
// Number.isInteger -- تتحقق مما اذا كانت القيمة عددا صحيحا
console.log(Number.isInteger(42)); // true
console.log(Number.isInteger(42.0)); // true (42.0 هي نفسها 42)
console.log(Number.isInteger(42.5)); // false
console.log(Number.isInteger('42')); // false (يجب ان تكون من نوع number)
console.log(Number.isInteger(Infinity)); // false
console.log(Number.isInteger(NaN)); // false
// Number.isNaN -- تتحقق مما اذا كانت القيمة NaN
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN(42)); // false
console.log(Number.isNaN('NaN')); // false (انها نص وليست NaN)
console.log(Number.isNaN(undefined)); // false
// مثال عملي: التحقق من المدخلات الرقمية
function isValidNumber(value) {
let num = Number(value);
return Number.isFinite(num);
}
console.log(isValidNumber('42')); // true
console.log(isValidNumber('3.14')); // true
console.log(isValidNumber('hello')); // false
console.log(isValidNumber('')); // true (انتبه! Number('') هي 0)
// تحقق افضل
function isValidNumericInput(value) {
if (typeof value === 'string' && value.trim() === '') return false;
let num = Number(value);
return Number.isFinite(num);
}
console.log(isValidNumericInput('')); // false (صحيح!)
console.log(isValidNumericInput(' ')); // false (صحيح!)
console.log(isValidNumericInput('42')); // true
كائن Math: طرق التقريب
كائن Math هو كائن مدمج في جافاسكريبت يوفر ثوابت ودوال رياضية. انه ليس مُنشئا -- لا يمكنك انشاء نسخ منه. بدلا من ذلك تستخدم طرقه وخصائصه الثابتة مباشرة. لنبدا بطرق التقريب التي هي من بين الاكثر استخداما.
مثال: Math.round و Math.ceil و Math.floor و Math.trunc
// Math.round -- تقرب الى اقرب عدد صحيح
console.log(Math.round(4.5)); // 5
console.log(Math.round(4.4)); // 4
console.log(Math.round(4.6)); // 5
console.log(Math.round(-4.5)); // -4 (تقرب نحو +اللانهاية)
console.log(Math.round(-4.6)); // -5
// Math.ceil -- تقرب دائما لاعلى (نحو +اللانهاية)
console.log(Math.ceil(4.1)); // 5
console.log(Math.ceil(4.9)); // 5
console.log(Math.ceil(4.0)); // 4 (عدد صحيح بالفعل)
console.log(Math.ceil(-4.1)); // -4 (نحو +اللانهاية!)
console.log(Math.ceil(-4.9)); // -4
// Math.floor -- تقرب دائما لاسفل (نحو -اللانهاية)
console.log(Math.floor(4.1)); // 4
console.log(Math.floor(4.9)); // 4
console.log(Math.floor(4.0)); // 4
console.log(Math.floor(-4.1)); // -5 (نحو -اللانهاية!)
console.log(Math.floor(-4.9)); // -5
// Math.trunc -- تزيل الجزء العشري (تقطع نحو الصفر)
console.log(Math.trunc(4.9)); // 4
console.log(Math.trunc(4.1)); // 4
console.log(Math.trunc(-4.9)); // -4 (نحو الصفر وليس نحو -اللانهاية)
console.log(Math.trunc(-4.1)); // -4
// مقارنة تقريب الارقام السالبة
let n = -4.3;
console.log(Math.round(n)); // -4
console.log(Math.ceil(n)); // -4
console.log(Math.floor(n)); // -5
console.log(Math.trunc(n)); // -4
// مثال عملي: التقريب الى N منازل عشرية
function roundTo(num, decimals) {
let factor = Math.pow(10, decimals);
return Math.round(num * factor) / factor;
}
console.log(roundTo(3.14159, 2)); // 3.14
console.log(roundTo(3.14159, 3)); // 3.142
console.log(roundTo(3.14159, 0)); // 3
// مثال عملي: حساب عدد الصفحات
function getPageCount(totalItems, itemsPerPage) {
return Math.ceil(totalItems / itemsPerPage);
}
console.log(getPageCount(101, 10)); // 11
console.log(getPageCount(100, 10)); // 10
console.log(getPageCount(1, 10)); // 1
Math.floor() وMath.trunc() للارقام السالبة. Math.floor(-4.3) تعطي -5 (تقرب نحو اللانهاية السالبة) بينما Math.trunc(-4.3) تعطي -4 (تزيل الجزء العشري). للارقام الموجبة تتصرفان بشكل متماثل.Math.max و Math.min
تعيد طريقتا Math.max() وMath.min() اكبر واصغر الارقام المعطاة. تقبلان اي عدد من المعاملات وتستخدمان بشكل متكرر لتقييد القيم ضمن نطاق.
مثال: Math.max و Math.min
// الاستخدام الاساسي
console.log(Math.max(1, 5, 3, 9, 2)); // 9
console.log(Math.min(1, 5, 3, 9, 2)); // 1
// مع الارقام السالبة
console.log(Math.max(-10, -5, -1)); // -1
console.log(Math.min(-10, -5, -1)); // -10
// حالات حدية
console.log(Math.max()); // -Infinity (بدون معاملات)
console.log(Math.min()); // Infinity (بدون معاملات)
console.log(Math.max(5, NaN, 3)); // NaN (اي معامل NaN يعيد NaN)
// الاستخدام مع المصفوفات عبر عامل الانتشار
let scores = [85, 92, 78, 96, 88];
console.log(Math.max(...scores)); // 96
console.log(Math.min(...scores)); // 78
// تقييد قيمة ضمن نطاق
function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
console.log(clamp(150, 0, 100)); // 100
console.log(clamp(-20, 0, 100)); // 0
console.log(clamp(50, 0, 100)); // 50
// مثال عملي: ايجاد نطاق القيم
function getRange(numbers) {
let min = Math.min(...numbers);
let max = Math.max(...numbers);
return { min, max, range: max - min };
}
let temps = [72, 68, 75, 80, 65, 78];
console.log(getRange(temps));
// { min: 65, max: 80, range: 15 }
الارقام العشوائية: Math.random
تعيد طريقة Math.random() رقما عشريا شبه عشوائي بين 0 (شامل) و 1 (غير شامل). بدمجها مع الضرب والجمع والتقريب يمكنك توليد ارقام عشوائية في اي نطاق.
مثال: توليد الارقام العشوائية
// الاستخدام الاساسي -- تعيد [0, 1)
console.log(Math.random()); // مثلا 0.7234567891234567
// عدد صحيح عشوائي بين 0 و max (غير شامل)
function randomInt(max) {
return Math.floor(Math.random() * max);
}
console.log(randomInt(10)); // 0-9
console.log(randomInt(100)); // 0-99
// عدد صحيح عشوائي بين min و max (شامل)
function randomRange(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(randomRange(1, 6)); // 1-6 (رمي نرد)
console.log(randomRange(10, 20)); // 10-20
console.log(randomRange(-5, 5)); // -5 الى 5
// عدد عشري عشوائي في نطاق
function randomFloat(min, max) {
return Math.random() * (max - min) + min;
}
console.log(randomFloat(1.5, 3.5)); // مثلا 2.345678...
// مثال عملي: خلط مصفوفة (خوارزمية فيشر-ياتس)
function shuffle(arr) {
let array = [...arr]; // انشاء نسخة
for (let i = array.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
let deck = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10'];
console.log(shuffle(deck));
// مثلا ['7', '3', 'A', '10', '5', '8', '2', '9', '4', '6']
// مثال عملي: توليد لون عشوائي
function randomColor() {
let r = randomRange(0, 255);
let g = randomRange(0, 255);
let b = randomRange(0, 255);
return `rgb(${r}, ${g}, ${b})`;
}
console.log(randomColor()); // مثلا rgb(142, 87, 203)
// مثال عملي: توليد لون سداسي عشري عشوائي
function randomHexColor() {
return '#' + Math.floor(Math.random() * 0xFFFFFF)
.toString(16)
.padStart(6, '0');
}
console.log(randomHexColor()); // مثلا #8e57cb
// مثال عملي: اختيار عنصر عشوائي من مصفوفة
function randomElement(arr) {
return arr[Math.floor(Math.random() * arr.length)];
}
let greetings = ['Hello', 'Hi', 'Hey', 'Greetings', 'Welcome'];
console.log(randomElement(greetings)); // مثلا "Hey"
Math.round(Math.random() * max) لتوليد اعداد صحيحة عشوائية. هذا يعطي النقاط الطرفية (0 و max) نصف احتمالية القيم الاخرى فقط. استخدم دائما Math.floor(Math.random() * (max + 1)) للتوزيع المنتظم. ايضا Math.random() ليست آمنة تشفيريا -- للتطبيقات الحساسة امنيا مثل توليد الرموز استخدم crypto.getRandomValues() بدلا من ذلك.Math.abs: القيمة المطلقة
تعيد طريقة Math.abs() القيمة المطلقة لرقم -- مسافته من الصفر دائما موجبة. هذا مفيد لحساب الفروقات والمسافات والمقادير بغض النظر عن الاتجاه.
مثال: Math.abs
console.log(Math.abs(5)); // 5
console.log(Math.abs(-5)); // 5
console.log(Math.abs(0)); // 0
console.log(Math.abs(-3.14)); // 3.14
// مثال عملي: حساب الفرق بين قيمتين
function difference(a, b) {
return Math.abs(a - b);
}
console.log(difference(10, 7)); // 3
console.log(difference(7, 10)); // 3 (نفس النتيجة بغض النظر عن الترتيب)
// مثال عملي: التحقق مما اذا كان رقمان متقاربين تقريبيا
function approximately(a, b, tolerance = 0.001) {
return Math.abs(a - b) < tolerance;
}
console.log(approximately(0.1 + 0.2, 0.3)); // true
console.log(approximately(3.14159, 3.14)); // false
console.log(approximately(3.14159, 3.14, 0.01)); // true
// مثال عملي: حساب المسافة بين نقطتين
function distance(x1, y1, x2, y2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}
console.log(distance(0, 0, 3, 4)); // 5
console.log(distance(1, 1, 4, 5)); // 5
القوى والجذور: Math.pow و Math.sqrt وعامل الاس
توفر جافاسكريبت عدة طرق لحساب القوى والجذور. طريقة Math.pow() وعامل الاس ** يتعاملان مع القوى بينما Math.sqrt() تحسب الجذور التربيعية.
مثال: القوى والجذور
// Math.pow(الاساس, الاس)
console.log(Math.pow(2, 3)); // 8 (2^3)
console.log(Math.pow(5, 2)); // 25 (5^2)
console.log(Math.pow(10, 6)); // 1000000 (10^6)
console.log(Math.pow(2, -1)); // 0.5 (2^-1 = 1/2)
console.log(Math.pow(8, 1/3)); // 2 (الجذر التكعيبي لـ 8)
// عامل الاس ** (ES2016) -- مفضل على Math.pow
console.log(2 ** 3); // 8
console.log(5 ** 2); // 25
console.log(10 ** 6); // 1000000
console.log(2 ** -1); // 0.5
console.log(8 ** (1/3)); // 2
// Math.sqrt -- الجذر التربيعي
console.log(Math.sqrt(16)); // 4
console.log(Math.sqrt(2)); // 1.4142135623730951
console.log(Math.sqrt(0)); // 0
console.log(Math.sqrt(-1)); // NaN (لا يمكن اخذ جذر تربيعي لرقم سالب)
// Math.cbrt -- الجذر التكعيبي (ES6)
console.log(Math.cbrt(27)); // 3
console.log(Math.cbrt(8)); // 2
console.log(Math.cbrt(-8)); // -2 (تعمل مع الارقام السالبة!)
// Math.hypot -- الجذر التربيعي لمجموع المربعات (ES6)
console.log(Math.hypot(3, 4)); // 5 (وتر مثلث 3-4-5)
console.log(Math.hypot(5, 12)); // 13
console.log(Math.hypot(3, 4, 5)); // 7.0710678... (مسافة ثلاثية الابعاد)
// مثال عملي: الفائدة المركبة
function compoundInterest(principal, rate, years, timesPerYear = 12) {
return principal * Math.pow(1 + rate / timesPerYear, timesPerYear * years);
}
let result = compoundInterest(1000, 0.05, 10);
console.log(result.toFixed(2)); // 1647.01 ($1000 بنسبة 5% لمدة 10 سنوات)
// مثال عملي: التحقق مما اذا كان الرقم قوة لـ 2
function isPowerOfTwo(n) {
if (n <= 0) return false;
return Math.log2(n) % 1 === 0;
}
console.log(isPowerOfTwo(64)); // true
console.log(isPowerOfTwo(100)); // false
الثوابت الرياضية: Math.PI وغيرها
يوفر كائن Math عدة ثوابت رياضية كخصائص. هذه قيم للقراءة فقط يمكنك استخدامها في حساباتك.
مثال: ثوابت Math
// Math.PI -- نسبة المحيط الى القطر
console.log(Math.PI); // 3.141592653589793
// Math.E -- رقم اويلر (اساس اللوغاريتم الطبيعي)
console.log(Math.E); // 2.718281828459045
// Math.LN2 -- اللوغاريتم الطبيعي لـ 2
console.log(Math.LN2); // 0.6931471805599453
// Math.LN10 -- اللوغاريتم الطبيعي لـ 10
console.log(Math.LN10); // 2.302585092994046
// Math.SQRT2 -- الجذر التربيعي لـ 2
console.log(Math.SQRT2); // 1.4142135623730951
// مثال عملي: حسابات الدائرة
function circleArea(radius) {
return Math.PI * radius ** 2;
}
function circleCircumference(radius) {
return 2 * Math.PI * radius;
}
console.log(circleArea(5).toFixed(2)); // 78.54
console.log(circleCircumference(5).toFixed(2)); // 31.42
// مثال عملي: تحويل الدرجات الى راديان والعكس
function degreesToRadians(degrees) {
return degrees * (Math.PI / 180);
}
function radiansToDegrees(radians) {
return radians * (180 / Math.PI);
}
console.log(degreesToRadians(90)); // 1.5707963... (PI/2)
console.log(degreesToRadians(180)); // 3.1415926... (PI)
console.log(radiansToDegrees(Math.PI)); // 180
// الدوال المثلثية
console.log(Math.sin(degreesToRadians(30))); // 0.5 (تقريبا)
console.log(Math.cos(degreesToRadians(60))); // 0.5 (تقريبا)
console.log(Math.tan(degreesToRadians(45))); // 1 (تقريبا)
مشاكل دقة النقطة العائمة والحلول
واحدة من اشهر الخصائص الغريبة في جافاسكريبت (وجميع اللغات التي تستخدم حساب النقطة العائمة IEEE 754) هي ان بعض الحسابات العشرية تنتج نتائج غير متوقعة. هذا ليس خطا في جافاسكريبت -- انه قيد اساسي في كيفية تمثيل اجهزة الكمبيوتر للكسور العشرية في النظام الثنائي. فهم هذه المشكلة ومعرفة الحلول امر ضروري لكل مطور جافاسكريبت.
مثال: مشاكل دقة النقطة العائمة
// المثال الكلاسيكي
console.log(0.1 + 0.2); // 0.30000000000000004 (وليس 0.3!)
console.log(0.1 + 0.2 === 0.3); // false!
// مشاكل دقة اخرى
console.log(0.1 + 0.7); // 0.7999999999999999
console.log(1.1 + 2.2); // 3.3000000000000003
console.log(0.3 - 0.1); // 0.19999999999999998
console.log(0.6 * 3); // 1.7999999999999998
console.log(1.4 - 1.0); // 0.39999999999999997
// لماذا يحدث هذا:
// 0.1 في النظام الثنائي هو 0.0001100110011... (يتكرر للابد)
// تماما مثل 1/3 = 0.333... في العشري. 1/10 لا نهائي في الثنائي.
// جافاسكريبت يمكنها تخزين 64 بت فقط لذلك تقرب مما يخلق اخطاء صغيرة.
مثال: حلول لمشاكل النقطة العائمة
// الحل 1: المقارنة بتسامح (Number.EPSILON)
function areEqual(a, b) {
return Math.abs(a - b) < Number.EPSILON;
}
console.log(areEqual(0.1 + 0.2, 0.3)); // true
// الحل 2: استخدام toFixed لاغراض العرض
let total = 0.1 + 0.2;
console.log(total.toFixed(2)); // "0.30" (نص!)
console.log(parseFloat(total.toFixed(2))); // 0.3 (رقم)
// الحل 3: العمل بالاعداد الصحيحة (سنتات بدلا من دولارات)
function addMoney(a, b) {
// تحويل الى سنتات والجمع ثم التحويل مرة اخرى
let centsA = Math.round(a * 100);
let centsB = Math.round(b * 100);
return (centsA + centsB) / 100;
}
console.log(addMoney(0.1, 0.2)); // 0.3 (صحيح!)
console.log(addMoney(19.99, 5.01)); // 25 (صحيح!)
// الحل 4: استخدام دالة تقريب
function roundTo(num, decimals) {
let factor = 10 ** decimals;
return Math.round(num * factor) / factor;
}
console.log(roundTo(0.1 + 0.2, 1)); // 0.3
console.log(roundTo(1.1 + 2.2, 1)); // 3.3
// مثال عملي: مجموع سلة التسوق
function calculateTotal(items) {
let totalCents = items.reduce((sum, item) => {
return sum + Math.round(item.price * 100) * item.quantity;
}, 0);
return totalCents / 100;
}
let cartItems = [
{ name: 'Widget', price: 9.99, quantity: 3 },
{ name: 'Gadget', price: 14.50, quantity: 2 },
{ name: 'Tool', price: 0.99, quantity: 10 }
];
console.log(calculateTotal(cartItems)); // 68.87 (صحيح!)
// مثال عملي: مقارنة الاسعار
function comparePrices(price1, price2) {
let cents1 = Math.round(price1 * 100);
let cents2 = Math.round(price2 * 100);
if (cents1 < cents2) return -1;
if (cents1 > cents2) return 1;
return 0;
}
console.log(comparePrices(0.1 + 0.2, 0.3)); // 0 (متساويتان صحيح!)
=== بعد العمليات الحسابية. نتيجة 0.1 + 0.2 ليست بالضبط 0.3 في جافاسكريبت. للحسابات المالية اعمل دائما بأصغر وحدة عملة (سنتات او قروش وغيرها) باستخدام الاعداد الصحيحة وحول الى العشري للعرض فقط. هذا يزيل اخطاء الدقة تماما.طرق Math اضافية
يوفر كائن Math العديد من الطرق المفيدة الاضافية ابعد مما غطيناه. اليك عدة طرق اضافية جديرة بالمعرفة لعمليات رياضية متنوعة.
مثال: طرق Math اضافية
// Math.sign -- تعيد -1 او 0 او 1 للدلالة على الاشارة
console.log(Math.sign(42)); // 1
console.log(Math.sign(-42)); // -1
console.log(Math.sign(0)); // 0
// Math.log و Math.log2 و Math.log10 -- اللوغاريتمات
console.log(Math.log(Math.E)); // 1 (اللوغاريتم الطبيعي لـ e)
console.log(Math.log2(8)); // 3 (لوغاريتم اساس 2 لـ 8)
console.log(Math.log10(1000)); // 3 (لوغاريتم اساس 10 لـ 1000)
// مثال عملي: حساب نسبة التغيير
function percentChange(oldValue, newValue) {
if (oldValue === 0) return newValue === 0 ? 0 : Infinity;
return roundTo(((newValue - oldValue) / Math.abs(oldValue)) * 100, 2);
}
function roundTo(num, decimals) {
let factor = 10 ** decimals;
return Math.round(num * factor) / factor;
}
console.log(percentChange(100, 125)); // 25
console.log(percentChange(200, 150)); // -25
console.log(percentChange(50, 75)); // 50
// مثال عملي: التحويل بين مقاييس الحرارة
function celsiusToFahrenheit(c) {
return roundTo(c * 9 / 5 + 32, 1);
}
function fahrenheitToCelsius(f) {
return roundTo((f - 32) * 5 / 9, 1);
}
console.log(celsiusToFahrenheit(0)); // 32
console.log(celsiusToFahrenheit(100)); // 212
console.log(fahrenheitToCelsius(98.6)); // 37
// مثال عملي: حاسبة مؤشر كتلة الجسم
function calculateBMI(weightKg, heightM) {
let bmi = weightKg / (heightM ** 2);
return roundTo(bmi, 1);
}
console.log(calculateBMI(70, 1.75)); // 22.9
انماط تحويل الارقام
التحويل بين الانواع المختلفة والارقام مهمة شائعة. اليك ملخص لتقنيات التحويل المختلفة ومتى تستخدم كل واحدة.
مثال: تحويلات الارقام الشاملة
// نص الى رقم -- عدة طرق
let str = '42.5';
console.log(Number(str)); // 42.5 (صارم)
console.log(parseFloat(str)); // 42.5 (متساهل)
console.log(parseInt(str, 10)); // 42 (عدد صحيح فقط)
console.log(+str); // 42.5 (اختصار الجمع الاحادي)
// رقم الى نص
let num = 42.5;
console.log(String(num)); // "42.5"
console.log(num.toString()); // "42.5"
console.log(num.toFixed(1)); // "42.5"
console.log(num + ''); // "42.5" (ضمني تجنب هذا)
console.log(`${num}`); // "42.5" (قالب نصي)
// منطقي الى رقم
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(+true); // 1
console.log(+false); // 0
// رقم الى منطقي
console.log(Boolean(0)); // false
console.log(Boolean(42)); // true
console.log(Boolean(-1)); // true
console.log(Boolean(NaN)); // false
console.log(Boolean(Infinity)); // true
// مثال عملي: جمع قيم من مدخلات النموذج
function sumInputValues(values) {
return values
.map(v => parseFloat(v) || 0)
.reduce((sum, n) => sum + n, 0);
}
let formValues = ['10', '20.5', 'invalid', '30', ''];
console.log(sumInputValues(formValues)); // 60.5
تمرين عملي
ابنِ مجموعة من دوال الادوات الرياضية التي تحل مشاكل واقعية. اختبر كل دالة بثلاث مدخلات مختلفة على الاقل بما في ذلك الحالات الحدية:
- rollDice(sides, count) -- تحاكي رمي عدة نرد. تاخذ عدد اوجه كل نرد وعدد النرد المراد رميها. تعيد كائنا يحتوي على مصفوفة الرميات الفردية والمجموع الكلي (مثلا
rollDice(6, 3)قد تعيد{ rolls: [4, 2, 6], total: 12 }). - formatBytes(bytes) -- تحول عدد البايتات الى نص قابل للقراءة مع الوحدات المناسبة. مثلا
formatBytes(1024)تعيد"1.00 KB"وformatBytes(1234567)تعيد"1.18 MB". ادعم البايت و KB و MB و GB و TB. - calculateTip(billAmount, tipPercent, splitCount) -- تحسب البقشيش والمجموع لكل شخص لفاتورة مطعم. تعامل مع دقة النقطة العائمة بالعمل بالسنتات. اعد كائنا يحتوي على مبلغ البقشيش والمجموع والحصة لكل شخص.
- randomPassword(length) -- تولد كلمة مرور عشوائية بالطول المحدد باستخدام احرف كبيرة وصغيرة وارقام واحرف خاصة. تاكد من تضمين حرف واحد على الاقل من كل فئة.
- statisticsOf(numbers) -- تاخذ مصفوفة من الارقام وتعيد كائنا يحتوي على: الحد الادنى والحد الاقصى والمجموع والمتوسط (مقرب الى منزلتين عشريتين) والوسيط والمدى. تعامل مع المصفوفات ذات الاطوال الفردية والزوجية لحساب الوسيط.
لكل دالة فكر في الحالات الحدية بعناية: ماذا يحدث مع القيم الصفرية والارقام السالبة والمصفوفات الفارغة والارقام الكبيرة جدا والمدخلات غير الصالحة؟ استخدم Number.isFinite() للتحقق واعمل بالاعداد الصحيحة للعملات وقرب النتائج دائما بشكل مناسب للعرض.