19.12.2023 8 min read

Truthy وFalsy في JavaScript وكيفية التبديل بينهما؟

بواسطة Mirza Leka

نظرة معمّقة على قيم truthy وfalsy في JavaScript، تغطي المعاملات المنطقية، والدمج اللاإلغائي (nullish coalescing)، والتسلسل الاختياري، ومعاملات الإسناد المنطقي.

True and False post-its

نصائح وحيل لتحسين طريقة كتابتك لـ JavaScript.

صورة من Aarohi Achwal عبر Parenting Firstcry

ما هو Falsy؟

ببساطة، هي أي قيمة تُقيَّم كـ false أو قابلة للإلغاء (nullable) أو فارغة.

  • False => Falsy
  • Null => Falsy
  • Undefined => Falsy
  • سلسلة نصية فارغة => Falsy
  • مصفوفة بلا عناصر => Falsy
  • كائن بلا مفاتيح (Object.keys(obj).length === 0) => Falsy
  • صفر => Falsy

هذا يعني أنه إذا كان لديك متغيّر:

const name = '';

وشرط تريد فيه فحص المتغيّر:

if (CHECK IF NAME IS EMPTY) {
  throw new Error('Missing name');
}

فأنت لست بحاجة لمقارنته بسلسلة نصية فارغة أو null أو undefined:

// Unnecessary
if (name === '' || name === undefined || name === null) { ... }

أو تحويله إلى قيمة منطقية (boolean) للتحقق مما إذا كان Falsy (كما تفعل في لغات أخرى ذات كتابة صارمة). بدلًا من ذلك، اعتبرها قيمة Falsy (مثل قيمة منطقية) وضع فقط بادئة ! وستُقيّمها JavaScript نيابة عنك:

// Simpler
if (!name) {
  throw new Error('Missing name');
}

ما هو Truthy؟ حسنًا، إنه عكس Falsy:

  • True
  • رقم أكبر أو أصغر من الصفر
  • سلسلة نصية بحرف واحد على الأقل
  • مصفوفة أو كائن بعنصر واحد على الأقل
  • متغيّر له قيمة، مثل ('A'، 1، {}، [])

تنوّع النتائج

// name = '';
!name === !false // True

// name = undefined;
!name === !false // True

// name = null;
!name === !false // True

// name = [];
!name.length === !false // True

// name = 0
!name === !false // True

وبالمثل، إذا كانت النتيجة معاكسة، ستُقيَّم كقيمة Truthy.

// sport = 'Football';
!sport === !true // True

// sport = '    ';
!sport === !true // True

// sport = ['Football'];
!sport.length === !true // True

// sport = 1
!sport === !true // True
Logical AND and OR operators

من الطرق الشائعة للتبديل بين قيم truthy وfalsy استخدام المعاملات المنطقية:

  • And (&&)
  • Or (||)

&&

عند إعداد شرط بين قيمتين، سيلتقط معامل && القيمة التي تُقيَّم كـ False.

إذا كانت أي من القيمتين في الشرط Falsy، ستكون النتيجة false:

true && false // False
false && true // False
false && false // False

فقط إذا كانت كلتا القيمتين Truthy، سيُقيَّم معامل && كـ true:

true && true // True

ضع في اعتبارك أن && ستُقيّم جميع القيم في الشرط حتى تجد أول قيمة Falsy. وإلا، ستأخذ آخر قيمة.

true && 'Hello' && 100; // 100 (Truthy value)

التحقق من إدخال المستخدم

إذا فشل أي شرط، ستُقيَّم العبارة كـ False.

const email = 'hello';

if (email.includes('@') && email.includes('.com') {
  console.log('Email is valid!');
} else {
  console.log('Email is invalid!');
}

عرض المحتوى الديناميكي

في أطر عمل الويب مثل React، يمكنك عرض عناصر HTML (أو مكونات) فقط عند تحقق شرط معين.

<div>
  { conditionIsMet && <h1>Hello World</h1> }
</div>

تجنّب القيم القابلة للإلغاء

من الأخطاء الشائعة التي يرتكبها المطورون محاولة قراءة قيمة من خاصية يكون أصلها (parent) بقيمة null أو undefined.

const array = [];
console.log(array.length); ✔️

const newArray = null;
console.log(newArray.length); ❌ // Exception

لحل هذا، تأكد أولًا أن الخاصية الجذر ليست null أو undefined، ثم حاول قراءة محتوى الخاصية المطلوبة.

if (newArray !== null && newArray.length === 0) {
  console.log('newArray is empty!');
}

||

يعمل معامل الـ OR المنطقي (||) بشكل معاكس لمعامل &&. فهو يبحث عن أي قيمة في الشرط تُقيَّم كـ Truthy ويأخذ تلك القيمة.

true || true // True
true || false // True
false || true // True

فقط إذا كانت كلتا القيمتين Falsy، ستكون النتيجة false:

false || false // False

ستُقيّم || جميع القيم في الشرط حتى تجد أول قيمة Truthy. وإلا، ستأخذ آخر قيمة.

false || undefined || null // Null

البحث ضمن مجموعة من العناصر

يمكن استخدام معامل || لتصفية العناصر التي تحقق شرطًا أو آخر.

const clothes = [
  {
    type: 'Shirt',
    color: 'Black',
    size: 'XL',
    price: 0
  },
  {
    type: 'Shirt',
    color: 'White',
    size: 'XL',
    price: 100
  },
  {
    type: 'Skirt',
    color: 'Red',
    size: 'L',
    price: 50
  }
];

const favClothes = clothes
  .filter(item => item.color === 'Black' || item.color === 'White');

console.log('favClothes :>> ', favClothes);
/*
  [
    { type: 'Shirt', color: 'Black', size: 'XL' },
    { type: 'Shirt', color: 'White', size: 'XL' }
  ]
*/

تعيين قيم افتراضية

إذا كانت إحدى العبارات Falsy، يمكنك استخدام معامل || لإعداد قيمة افتراضية:

function findHero(hero) {
  const defaultHero = 'Goku';
  const myHero = hero || defaultHero;

  return heroes.find(h => h.name === myHero);
}

معاملات متعددة

عندما يكون لديك عدة معاملات && و|| في عبارة واحدة، تُطبَّق قاعدة الأسبقية. سيُقيَّم أول شرطين، ثم تُقيَّم نتيجتهما مقابل القيمة الثالثة:

console.log(true && null || false ); // False
// #1 true && null (where null is Falsy) === Null
// #2 null || false === False
console.log(false || 100 && undefined ); // Undefined
// #1 false || 100 (where 100 is Truthy) === 100
// #2 100 && undefined (truthy && falsy) === Undefined
console.log(null || 0 && '' || true); // True
console.log(null || 0 && '' && false); // 0
Double question marks

أدخل ES2020 معاملًا جديدًا، الدمج اللاإلغائي (Nullish Coalescing)، المعروف أيضًا باسم Elvis operator.

const possiblyNull = null;

const result = possiblyNull ?? 'Default Value';

console.log(result); // 'Default Value'
const possiblyUndefined = undefined;

const result = possiblyUndefined ?? 'Default Value';

console.log(result); // 'Default Value'

يعمل بشكل مشابه لمعامل ||. لكن بينما يُطبَّق || على جميع قيم falsy، يقتصر معامل الدمج اللاإلغائي فقط على قيم null وundefined.

إذا استُخدم مع أنواع أخرى، فسيعيد ببساطة القيمة الأولى:

false ?? true // False
true ?? false // True
Optional chaining operator A?.B

طريقة أخرى لتجنّب الخصائص القابلة للإلغاء هي استخدام معامل التسلسل الاختياري (Optional Chaining).

بدلًا من تكرار نفسك:

if (newArray !== null && newArray.length === 0) {
  console.log('newArray is empty!');
}

يمكنك تطبيق التسلسل الاختياري:

if (newArray?.length === 0) {
  console.log('newArray is empty!');
}

ما سيفعله هذا هو:

إذا كان الأمر كذلك، سيُقيَّم الشرط كـ null/false ما يُنهي العبارة (ينتقل إلى حالة else).

  • يقيّم ما إذا كانت newArray قابلة للإلغاء
  • يتحقق من طول newArray (بعد تقييم newArray بالفعل)

وهذا أنظف بكثير. كما يعمل مع أي عدد من الخصائص لديك:

const name = currentUser?.username?.name?.firstName;

يمكنك أيضًا الجمع بين التسلسل الاختياري ومعاملات أخرى:

const name = user?.username ?? 'Default Username';
console.log(name);

ستُطبع 'Default Username' إذا:

  • كان user قيمته null أو undefined
  • كان user.username قيمته null أو undefined

بدلًا من ذلك، إذا افترضنا أن خاصية user معرَّفة بالفعل (لها قيمة)، يمكنك تعيين قيمة افتراضية لـ user.username باستخدام تفكيك الكائن (Object Destructuring):

const { username = 'Default Username' } = user;
console.log(name);

حيث ستساوي username 'Default Username' فقط إذا كانت undefined أو null.

Ternary operator A?B:C

طريقة شائعة ومباشرة للتبديل بين قيم truthy وfalsy هي استخدام المعامل الثلاثي (Ternary Operator). يعمل كالتالي:

  • إذا تحقق الشرط كـ true (أ)
  • ستكون النتيجة الخيار الأول (ب)
  • وإلا، ستكون النتيجة الخيار الآخر (ج)
const isGreaterThan = 10 > 1 ? true : false;
console.log(isGreaterThan); // True
//
const isLesserThan = 10 < 1 ? true : false;
console.log(isLesserThan); // False
Logical assignment operators

أحدث إضافة إلى JavaScript هي مجموعة من معاملات الإسناد المنطقي (Logical Assignment). فكّر في كل ما تعلمته حتى الآن مجتمعًا مع القدرة على إسناد القيم أثناء التنفيذ.

فبدلًا من:

function setHero(myHero) {
  myHero = myHero ?? 'Goku';
  return myHero;
}

const result = setHero();
console.log(result) // 'Goku'

ستفعل:

function setHero(myHero) {
  myHero ??= 'Goku';
  return myHero;
}

const result = setHero();
console.log(result) // 'Goku'

الدافع وراء هذا هو تقليل الخطوة الإضافية اللازمة للتحقق من القيم ثم إسنادها. الآن يحدث كل ذلك دفعة واحدة.

بالنسبة للسيناريوهات الأخرى من نوع Falsy، يمكنك استخدام معامل || المعتاد:

function setSalary(mySalary) {
  const minimum_salary = 1000;
  mySalary ||= minimum_salary;
  return mySalary;
}

const result = setSalary();
console.log(result) // 1000

هذا ينطبق أيضًا على سيناريوهات أكثر تعقيدًا:

const cybertruck = { 
  topSpeedInKmh: 180, 
  maximumBatteryLife: null, 
  towingCapacity: undefined
};

const defaultTopSpeed = 100;
const defaultBatteryCapacity = '122.4 kWh'
const defaultTowingCapacity = '11 000 pounds'

cybertruck.topSpeedInKmh ||= defaultMaxSpeed; // takes first truthy value
cybertruck.maximumBatteryLife ??= defaultBatteryCapacity; // avoids null
cybertruck.towingCapacity &&= defaultTowingCapacity; // takes falsy value

console.log(cybertruck.topSpeedInKmh); // 180
console.log(cybertruck.maximumBatteryLife); // '122.4 kWh'
console.log(cybertruck.towingCapacity); // undefined
Greater than comparison A > B

التقييم الضمني

إذا كانت القيمة تُقيَّم كـ truthy أو falsy، فلست بحاجة للتصريح صراحة بأن النتيجة true أو false.

# صريح

if (value === true) { ... }

# ضمني

if (value) { ... }

# صريح

const isGreaterThan = 10 > 1 ? true : false;

# ضمني

const isGreaterThan = 10 > 1;

# صريح

const freeItem = clothes.find(item => item.price === 0);

# ضمني

const freeItem = clothes.find(item => !item.price);
// { type: 'Shirt', color: 'Black', size: 'XL', price: 0 }

التحويل إلى Boolean

يمكنك أيضًا تحويل قيمة صراحةً إلى قيمة منطقية (boolean) باستخدام زوج من علامات التعجب.

const greeting = 'Hello';
const truthy = !!greeting; // True
const empty = '';
const falsy = !!empty; // False

بدلًا من ذلك، يمكنك استخدام دالة البناء Boolean():

const greeting = 'Hello';
const empty = '';

console.log(Boolean(greeting)); // True
console.log(Boolean(empty)); // False
قراءات إضافية عرض الكل
الخطوة التالية

طبّق هذه الأفكار على منتجك

يساعد استوديو فالنس الفرق ذات المخاطر العالية على تحويل الوضوح الهندسي إلى تسليم منتج معياري.