أساسيات JavaScript

ميثودات الكائنات وكلمة this المفتاحية

45 دقيقة الدرس 17 من 60

ما هي ميثودات الكائنات؟

في JavaScript، ميثود الكائن هو ببساطة دالة مخزنة كخاصية في كائن. تسمح الميثودات للكائنات بامتلاك سلوك بالاضافة الى تخزين البيانات. عندما تعرف دالة داخل كائن، يمكن لتلك الدالة الوصول الى خصائص الكائن نفسه والتعامل معها. هذا يجعل الكائنات وحدات قوية متكاملة تجمع بين البيانات والمنطق للعمل مع تلك البيانات. فهم ميثودات الكائنات اساسي لكتابة كود JavaScript منظم وقابل لاعادة الاستخدام.

لقد عملت سابقا مع ميثودات مدمجة مثل console.log() و Array.push() و String.toUpperCase(). كل واحدة منها هي دالة مخزنة على كائن. الان ستتعلم كيفية انشاء ميثودات كائنات خاصة بك وفهم كيف تربط كلمة this المفتاحية الميثود بالكائن الاب.

تعريف الميثودات في الكائنات

هناك طريقتان رئيسيتان لتعريف ميثود داخل كائن. الطريقة التقليدية تستخدم تعبير دالة معين لخاصية. صيغة الاختصار الحديثة التي قدمت في ES6 توفر طريقة انظف لكتابة نفس الشيء. كلتا الطريقتين تعملان بشكل متطابق، لكن الاختصار مفضل في JavaScript الحديثة لانه اكثر اختصارا واسهل في القراءة.

مثال: طريقة تعبير الدالة التقليدية

const dog = {
    name: 'Buddy',
    breed: 'Golden Retriever',
    age: 3,
    bark: function() {
        console.log('Woof! Woof!');
    },
    describe: function() {
        console.log('This dog is named ' + this.name);
    }
};

dog.bark();      // Woof! Woof!
dog.describe();  // This dog is named Buddy

مثال: صيغة اختصار ميثود ES6

const dog = {
    name: 'Buddy',
    breed: 'Golden Retriever',
    age: 3,
    bark() {
        console.log('Woof! Woof!');
    },
    describe() {
        console.log('This dog is named ' + this.name);
    }
};

dog.bark();      // Woof! Woof!
dog.describe();  // This dog is named Buddy
نصيحة احترافية: فضل دائما صيغة اختصار ميثود ES6 عند تعريف الميثودات في الكائنات الحرفية. انها اكثر اختصارا وتتجنب فوضى كلمة function وهي المعيار المتبع في مشاريع JavaScript الحديثة. صيغة الاختصار ايضا توضح فورا ان الدالة مقصودة كميثود.

فهم كلمة this المفتاحية

كلمة this المفتاحية هي واحدة من اهم المفاهيم واكثرها سوء فهم في JavaScript. داخل ميثود الكائن، this تشير الى الكائن الذي تنتمي اليه الميثود. انها مرجع ديناميكي يسمح للميثود بالوصول الى الخصائص والميثودات الاخرى على نفس الكائن. بدون this، لن يكون لدى الميثودات طريقة للاشارة الى البيانات المخزنة بجانبها في الكائن.

قيمة this لا تتحدد عند كتابة الدالة. بل تتحدد في وقت استدعاء الدالة، بناء على كيفية استدعائها. هذا تمييز حاسم يربك العديد من المطورين.

مثال: استخدام this للوصول الى خصائص الكائن

const student = {
    firstName: 'Sarah',
    lastName: 'Johnson',
    grades: [88, 92, 79, 95, 84],
    getFullName() {
        return this.firstName + ' ' + this.lastName;
    },
    getAverage() {
        const sum = this.grades.reduce((total, grade) => total + grade, 0);
        return sum / this.grades.length;
    },
    getSummary() {
        return this.getFullName() + ' has an average grade of ' + this.getAverage().toFixed(1);
    }
};

console.log(student.getFullName());  // Sarah Johnson
console.log(student.getAverage());   // 87.6
console.log(student.getSummary());   // Sarah Johnson has an average grade of 87.6
ملاحظة: لاحظ كيف تستدعي getSummary() كلا من this.getFullName() و this.getAverage(). يمكن للميثودات استدعاء ميثودات اخرى على نفس الكائن باستخدام this. هكذا تغلف الكائنات السلوك المرتبط وتسمح للميثودات بالبناء على بعضها البعض.

this في سياقات مختلفة

قيمة this تتغير حسب اين وكيف يتم استدعاء الدالة. فهم هذه السياقات المختلفة ضروري لتجنب الاخطاء. دعنا نفحص كل سياق بعناية.

السياق العام

عند استخدام this خارج اي دالة او كائن، تشير الى الكائن العام. في المتصفح، الكائن العام هو window. في Node.js، هو كائن global. في الوضع الصارم، this في النطاق العام تكون undefined بدلا من ذلك.

مثال: this في السياق العام

// في المتصفح (الوضع غير الصارم)
console.log(this);           // كائن Window
console.log(this === window); // true

// في الوضع الصارم
'use strict';
function showThis() {
    console.log(this);       // undefined
}
showThis();

سياق الدالة (الدوال العادية)

في استدعاء دالة عادية (غير ميثود)، this تعود افتراضيا الى الكائن العام في الوضع غير الصارم، او undefined في الوضع الصارم. هذا غالبا مصدر ارتباك لان المطورين يتوقعون ان this تشير الى شيء ذي معنى.

مثال: this في الدوال العادية

function regularFunction() {
    console.log(this);
}

// الوضع غير الصارم: this هي كائن Window
regularFunction();  // Window {...}

// الوضع الصارم: this هي undefined
'use strict';
function strictFunction() {
    console.log(this);
}
strictFunction();  // undefined

سياق الميثود

عندما تستدعى دالة كميثود لكائن (باستخدام نقطة التدوين)، this تشير الى الكائن الموجود على يسار النقطة. هذا هو الاستخدام الاكثر شيوعا والاكثر بديهية لـ this.

مثال: this في سياق الميثود

const car = {
    brand: 'Toyota',
    model: 'Camry',
    year: 2024,
    getInfo() {
        return this.brand + ' ' + this.model + ' (' + this.year + ')';
    }
};

console.log(car.getInfo());  // Toyota Camry (2024)

// this تشير الى ما هو على يسار النقطة
const anotherCar = {
    brand: 'Honda',
    model: 'Civic',
    year: 2023,
    getInfo: car.getInfo  // استعارة الميثود
};

console.log(anotherCar.getInfo());  // Honda Civic (2023)

دوال السهم و this

دوال السهم لا تملك ربط this خاص بها. بدلا من ذلك، ترث this من النطاق المعجمي المحيط -- النطاق الذي تم فيه تعريف دالة السهم. هذا السلوك مختلف جذريا عن الدوال العادية وهو احد الاسباب الرئيسية لتقديم دوال السهم في ES6.

مثال: دوال السهم ترث this

const team = {
    name: 'Engineering',
    members: ['Alice', 'Bob', 'Charlie'],

    // دالة عادية: this تشير الى team
    listMembers() {
        // دالة السهم ترث this من listMembers
        this.members.forEach((member) => {
            console.log(member + ' is on the ' + this.name + ' team');
        });
    }
};

team.listMembers();
// Alice is on the Engineering team
// Bob is on the Engineering team
// Charlie is on the Engineering team

مثال: لماذا لا يجب استخدام دوال السهم كميثودات

const user = {
    name: 'David',

    // خطا: دالة سهم كميثود
    greetArrow: () => {
        console.log('Hello, ' + this.name);  // this ليست كائن user
    },

    // صحيح: ميثود عادية
    greetRegular() {
        console.log('Hello, ' + this.name);  // this هي كائن user
    }
};

user.greetArrow();    // Hello, undefined (this تشير الى النطاق الخارجي)
user.greetRegular();  // Hello, David
خطا شائع: لا تستخدم ابدا دوال السهم لتعريف ميثودات الكائنات. دوال السهم لا تربط this الخاصة بها، لذلك this داخل ميثود دالة سهم لن تشير الى الكائن. استخدم دائما تعبيرات الدوال العادية او صيغة اختصار ميثود ES6 لميثودات الكائنات.

call و apply و bind

يوفر JavaScript ثلاث ميثودات تسمح لك بتعيين قيمة this صراحة عند استدعاء دالة: call() و apply() و bind(). هذه ادوات اساسية للتحكم في سياق الدالة.

Function.prototype.call()

ميثود call() تستدعي دالة فورا مع قيمة this محددة ووسائط تمرر بشكل فردي.

مثال: استخدام call() لتعيين this

function introduce(greeting, punctuation) {
    console.log(greeting + ', I am ' + this.name + punctuation);
}

const person1 = { name: 'Alice' };
const person2 = { name: 'Bob' };

introduce.call(person1, 'Hello', '!');   // Hello, I am Alice!
introduce.call(person2, 'Hey there', '.');  // Hey there, I am Bob.

Function.prototype.apply()

ميثود apply() تعمل تماما مثل call()، الا انها تاخذ الوسائط كمصفوفة بدلا من فرديا. هذا مفيد عندما تكون لديك وسائط مخزنة في مصفوفة او تريد تمرير عدد ديناميكي من الوسائط.

مثال: استخدام apply() مع وسائط المصفوفة

function introduce(greeting, punctuation) {
    console.log(greeting + ', I am ' + this.name + punctuation);
}

const person = { name: 'Charlie' };
const args = ['Greetings', '!!!'];

introduce.apply(person, args);  // Greetings, I am Charlie!!!

// مثال عملي: ايجاد الاقصى في مصفوفة
const numbers = [5, 12, 3, 8, 21, 1];
const max = Math.max.apply(null, numbers);
console.log(max);  // 21

Function.prototype.bind()

ميثود bind() لا تستدعي الدالة فورا. بدلا من ذلك، تعيد دالة جديدة مع this مربوطة بشكل دائم بالقيمة المحددة. الدالة المربوطة يمكن استدعاؤها لاحقا، او تخزينها في متغير، او تمريرها كاستدعاء راجع.

مثال: استخدام bind() لانشاء دالة مربوطة

const calculator = {
    value: 0,
    add(amount) {
        this.value += amount;
        console.log('Value: ' + this.value);
    }
};

// بدون bind، ستفقد this سياقها
const addFunction = calculator.add;
// addFunction(5);  // ستفشل: this.value غير معرفة

// مع bind، يتم تعيين this بشكل دائم الى calculator
const boundAdd = calculator.add.bind(calculator);
boundAdd(5);   // Value: 5
boundAdd(10);  // Value: 15

// bind يمكنها ايضا تعيين وسائط مسبقا (تطبيق جزئي)
const addTen = calculator.add.bind(calculator, 10);
addTen();  // Value: 25
نصيحة احترافية: تذكر الفرق: call() و apply() تستدعيان الدالة فورا، بينما bind() تعيد دالة جديدة للاستخدام لاحقا. طريقة مساعدة للتذكر: Call تستدعي فورا (Call)، Apply تستخدم مصفوفة (Array)، Bind تبني دالة جديدة (Build).

this في معالجات الاحداث

عندما تستخدم دالة كمعالج حدث في DOM، this تشير الى عنصر HTML الذي استقبل الحدث. هذا مفيد للغاية للتعامل مع العنصر الذي اطلق الحدث دون الحاجة الى البحث عنه مرة اخرى.

مثال: this في معالجات الاحداث

// استخدام دالة عادية كمعالج حدث
document.querySelector('.btn').addEventListener('click', function() {
    // this تشير الى عنصر الزر الذي تم النقر عليه
    console.log(this.textContent);
    this.style.backgroundColor = 'blue';
    this.classList.toggle('active');
});

// تحذير: دالة السهم لا تربط this بالعنصر
document.querySelector('.btn').addEventListener('click', () => {
    // this لا تشير الى الزر -- تشير الى النطاق الخارجي
    console.log(this);  // كائن Window او undefined في الوضع الصارم
});

this مع setTimeout و setInterval

مصدر شائع جدا للاخطاء يتعلق باستخدام this داخل setTimeout او setInterval. عندما تمرر دالة عادية لهذه دوال المؤقت، this تفقد سياقها الاصلي لان الدالة تستدعى بواسطة اليات المؤقت، وليس كميثود على كائنك.

مثال: فقدان this مع setTimeout

const countdown = {
    count: 5,
    start() {
        // مشكلة: الدالة العادية تفقد this
        setTimeout(function() {
            console.log(this.count);  // undefined -- this هي Window
        }, 1000);
    }
};

countdown.start();  // undefined

مثال: ثلاثة حلول لـ setTimeout

const countdown = {
    count: 5,

    // الحل 1: دالة سهم (ترث this)
    startArrow() {
        setTimeout(() => {
            console.log(this.count);  // 5 -- السهم يرث this
        }, 1000);
    },

    // الحل 2: bind()
    startBind() {
        setTimeout(function() {
            console.log(this.count);  // 5 -- مربوطة بـ countdown
        }.bind(this), 1000);
    },

    // الحل 3: تخزين this في متغير (نمط قديم)
    startVariable() {
        const self = this;
        setTimeout(function() {
            console.log(self.count);  // 5 -- باستخدام المرجع المحفوظ
        }, 1000);
    }
};

countdown.startArrow();     // 5
countdown.startBind();      // 5
countdown.startVariable();  // 5
ملاحظة: حل دالة السهم هو الاسلوب الاكثر شيوعا في JavaScript الحديثة لانه نظيف ومختصر ويوصل النية بوضوح. حل bind() مفيد عندما تحتاج لتمرير وسائط. حل المتغير (const self = this) هو نمط اقدم قد تراه في قواعد الكود القديمة.

فقدان this: مشكلة شائعة

واحدة من اكثر الاخطاء التي يواجهها مطورو JavaScript هي فقدان سياق this عن طريق الخطا. يحدث هذا عندما تستخرج ميثود من كائن وتستدعيها بشكل منفصل، او عندما تمرر ميثود كاستدعاء راجع. فهم سبب حدوث هذا وكيفية اصلاحه امر بالغ الاهمية.

مثال: كيف تضيع this

const user = {
    name: 'Emma',
    greet() {
        console.log('Hello, I am ' + this.name);
    }
};

// يعمل: استدعيت كميثود
user.greet();  // Hello, I am Emma

// معطل: استخرجت واستدعيت كدالة مستقلة
const greetFn = user.greet;
greetFn();  // Hello, I am undefined

// معطل: مررت كاستدعاء راجع
setTimeout(user.greet, 1000);  // Hello, I am undefined

// الاصلاح 1: استخدم bind
const boundGreet = user.greet.bind(user);
boundGreet();  // Hello, I am Emma

// الاصلاح 2: غلف في دالة سهم
setTimeout(() => user.greet(), 1000);  // Hello, I am Emma
خطا شائع: تمرير ميثود كائن مباشرة كاستدعاء راجع لدوال مثل setTimeout و addEventListener و forEach و map او Promise.then سيتسبب في فقدان this لربطها. استخدم دائما bind() او غلاف دالة سهم للحفاظ على السياق عند تمرير الميثودات كاستدعاءات راجعة.

تسلسل الميثودات

تسلسل الميثودات هو نمط قوي حيث تعيد كل ميثود this (الكائن نفسه)، مما يسمح لك باستدعاء ميثودات متعددة في عبارة واحدة. هذا ينشئ واجهات برمجة سلسة وقابلة للقراءة. العديد من المكتبات الشهيرة مثل jQuery و Lodash و Moment.js تستخدم تسلسل الميثودات بشكل مكثف.

مثال: بناء كائن قابل للتسلسل

const queryBuilder = {
    query: '',

    select(fields) {
        this.query += 'SELECT ' + fields + ' ';
        return this;  // اعد this للتسلسل
    },
    from(table) {
        this.query += 'FROM ' + table + ' ';
        return this;
    },
    where(condition) {
        this.query += 'WHERE ' + condition + ' ';
        return this;
    },
    orderBy(field, direction) {
        this.query += 'ORDER BY ' + field + ' ' + direction + ' ';
        return this;
    },
    build() {
        return this.query.trim() + ';';
    }
};

const sql = queryBuilder
    .select('name, email')
    .from('users')
    .where('age > 18')
    .orderBy('name', 'ASC')
    .build();

console.log(sql);
// SELECT name, email FROM users WHERE age > 18 ORDER BY name ASC;

مثال: الة حاسبة مع تسلسل الميثودات

const calculator = {
    result: 0,

    set(value) {
        this.result = value;
        return this;
    },
    add(value) {
        this.result += value;
        return this;
    },
    subtract(value) {
        this.result -= value;
        return this;
    },
    multiply(value) {
        this.result *= value;
        return this;
    },
    divide(value) {
        if (value === 0) {
            console.log('Error: Cannot divide by zero');
            return this;
        }
        this.result /= value;
        return this;
    },
    getResult() {
        return this.result;
    }
};

const answer = calculator
    .set(10)
    .add(5)
    .multiply(2)
    .subtract(8)
    .divide(2)
    .getResult();

console.log(answer);  // 11
نصيحة احترافية: مفتاح تسلسل الميثودات هو return this; في نهاية كل ميثود يجب ان تكون قابلة للتسلسل. الميثود الاخيرة في السلسلة (مثل build() او getResult()) عادة تعيد قيمة بدلا من this. هذا النمط يبقي كودك مضغوطا وقابلا للقراءة.

الحاصلات والمعينات (Getters و Setters)

يوفر JavaScript صيغة خاصة get و set تسمح لك بتعريف ميثودات تتصرف كخصائص. الحاصلات (Getters) تحسب قيمة ديناميكيا عند الوصول الى خاصية. المعينات (Setters) تشغل منطق التحقق او التحويل عند تعيين قيمة. معا، توفر وصولا متحكما فيه الى البيانات الداخلية للكائن.

مثال: الحاصلات والمعينات الاساسية

const person = {
    firstName: 'John',
    lastName: 'Doe',

    // حاصل: يتم الوصول اليه كخاصية وليس كاستدعاء ميثود
    get fullName() {
        return this.firstName + ' ' + this.lastName;
    },

    // معين: يتم التعيين كخاصية ويشغل المنطق خلف الكواليس
    set fullName(value) {
        const parts = value.split(' ');
        this.firstName = parts[0];
        this.lastName = parts[1];
    }
};

// استخدام الحاصل (لا حاجة لاقواس)
console.log(person.fullName);  // John Doe

// استخدام المعين (صيغة التعيين)
person.fullName = 'Jane Smith';
console.log(person.firstName);  // Jane
console.log(person.lastName);   // Smith
console.log(person.fullName);   // Jane Smith

مثال: المعينات للتحقق من الصحة

const product = {
    _name: '',
    _price: 0,

    get name() {
        return this._name;
    },
    set name(value) {
        if (typeof value !== 'string' || value.trim().length === 0) {
            console.log('Error: Name must be a non-empty string');
            return;
        }
        this._name = value.trim();
    },

    get price() {
        return '$' + this._price.toFixed(2);
    },
    set price(value) {
        if (typeof value !== 'number' || value < 0) {
            console.log('Error: Price must be a positive number');
            return;
        }
        this._price = value;
    }
};

product.name = 'Laptop';
product.price = 999.99;
console.log(product.name);   // Laptop
console.log(product.price);  // $999.99

product.price = -50;  // Error: Price must be a positive number
product.name = '';     // Error: Name must be a non-empty string
ملاحظة: اتفاقية وضع شرطة سفلية قبل الخصائص الداخلية (مثل _name و _price) تشير للمطورين الاخرين ان هذه الخصائص لا يجب الوصول اليها مباشرة. استخدم الحاصل والمعين للتعامل معها بدلا من ذلك. هذا نمط شائع للتغليف في JavaScript.

مثال واقعي: كائن المستخدم

دعنا نبني كائن مستخدم عملي يوضح الميثودات و this والحاصلات والمعينات وتسلسل الميثودات تعمل معا. هذا هو نوع الكائن الذي قد تنشئه في تطبيق حقيقي.

مثال: كائن مستخدم كامل

const user = {
    _firstName: 'Sarah',
    _lastName: 'Ahmed',
    _email: 'sarah@example.com',
    _loginCount: 0,
    _lastLogin: null,
    _preferences: {
        theme: 'dark',
        language: 'en',
        notifications: true
    },

    get fullName() {
        return this._firstName + ' ' + this._lastName;
    },
    set fullName(value) {
        const parts = value.split(' ');
        if (parts.length < 2) {
            console.log('Please provide both first and last name');
            return;
        }
        this._firstName = parts[0];
        this._lastName = parts.slice(1).join(' ');
    },

    get email() {
        return this._email;
    },
    set email(value) {
        if (!value.includes('@')) {
            console.log('Invalid email address');
            return;
        }
        this._email = value.toLowerCase();
    },

    login() {
        this._loginCount++;
        this._lastLogin = new Date().toISOString();
        console.log(this.fullName + ' logged in. Total logins: ' + this._loginCount);
        return this;
    },

    setPreference(key, value) {
        if (this._preferences.hasOwnProperty(key)) {
            this._preferences[key] = value;
            console.log('Preference ' + key + ' set to ' + value);
        } else {
            console.log('Unknown preference: ' + key);
        }
        return this;
    },

    getProfile() {
        return {
            name: this.fullName,
            email: this._email,
            logins: this._loginCount,
            lastLogin: this._lastLogin,
            preferences: { ...this._preferences }
        };
    }
};

// تسلسل الميثودات في العمل
user.login()
    .setPreference('theme', 'light')
    .setPreference('language', 'ar');

console.log(user.getProfile());

مثال واقعي: الة حاسبة مع التسلسل والسجل

هنا الة حاسبة اكثر تقدما تحتفظ بسجل لجميع العمليات وتدعم تسلسل الميثودات. هذا النمط يستخدم عادة في خطوط معالجة البيانات وواجهات برمجة البناء.

مثال: الة حاسبة متقدمة مع سجل

const advancedCalc = {
    _value: 0,
    _history: [],

    _record(operation) {
        this._history.push({
            operation: operation,
            result: this._value,
            timestamp: new Date().toLocaleTimeString()
        });
    },

    set(value) {
        this._value = value;
        this._record('set(' + value + ')');
        return this;
    },

    add(n) {
        this._value += n;
        this._record('add(' + n + ')');
        return this;
    },

    subtract(n) {
        this._value -= n;
        this._record('subtract(' + n + ')');
        return this;
    },

    multiply(n) {
        this._value *= n;
        this._record('multiply(' + n + ')');
        return this;
    },

    divide(n) {
        if (n === 0) {
            console.log('Cannot divide by zero');
            return this;
        }
        this._value /= n;
        this._record('divide(' + n + ')');
        return this;
    },

    get value() {
        return this._value;
    },

    get history() {
        return this._history.map(function(entry) {
            return entry.operation + ' = ' + entry.result;
        }).join(' -> ');
    },

    reset() {
        this._value = 0;
        this._history = [];
        return this;
    }
};

advancedCalc
    .set(100)
    .add(50)
    .multiply(2)
    .subtract(75)
    .divide(5);

console.log(advancedCalc.value);    // 45
console.log(advancedCalc.history);
// set(100) = 100 -> add(50) = 150 -> multiply(2) = 300 -> subtract(75) = 225 -> divide(5) = 45

ملخص قواعد this

اليك دليل مرجعي سريع يلخص كيف تتصرف this في كل سياق:

  • النطاق العام -- this تشير الى الكائن العام (window في المتصفحات) او undefined في الوضع الصارم.
  • استدعاء دالة عادية -- this هي الكائن العام او undefined في الوضع الصارم.
  • استدعاء ميثود (obj.method()) -- this هي الكائن الموجود على يسار النقطة.
  • دالة سهم -- this موروثة من النطاق المعجمي المحيط. دوال السهم لا تربط this الخاصة بها ابدا.
  • معالج حدث (دالة عادية) -- this هي عنصر DOM الذي استقبل الحدث.
  • call() / apply() -- this تعين صراحة الى الوسيط الاول.
  • bind() -- تعيد دالة جديدة حيث this مربوطة بشكل دائم الى الوسيط الاول.
  • المنشئ (كلمة new المفتاحية) -- this تشير الى مثيل الكائن المنشا حديثا.

تمرين عملي

انشئ كائن bankAccount بالميزات التالية: خصائص لـ _owner (نص) و _balance (رقم يبدا بـ 0) و _transactions (مصفوفة فارغة). اضف حاصلا يسمى balance يعيد الرصيد بتنسيق العملة (مثلا "$1,250.00"). اضف معينا يسمى owner يتحقق من ان الاسم مكون من حرفين على الاقل. انشئ ميثودات deposit(amount) و withdraw(amount) تتحقق من المبالغ الايجابية وتحدث الرصيد وتسجل كل معاملة في مصفوفة _transactions مع النوع والمبلغ والرصيد الجديد وتعيد this لتسلسل الميثودات. اضف ميثود getStatement() تعيد نصا منسقا لجميع المعاملات. اختبر كائنك بتسلسل عدة ايداعات وسحوبات ثم اطبع الكشف. تاكد من ان ميثود السحب تمنع السحب على المكشوف بالتحقق من كفاية الرصيد قبل المعالجة.