Interview question
How do you implement encapsulation in JavaScript before private fields existed (using closures)? Private fields के आने से पहले closures से encapsulation कैसे implement करें?
Answer
Before the # syntax was standardized, closures were the primary way to achieve true data privacy - variables inside a constructor function that are never attached to 'this' are inaccessible from outside.
// Closure-based encapsulation - the classic pre-# approach
function BankAccount(initialBalance) {
let balance = initialBalance; // truly private - not attached to 'this'
const transactionHistory = [];
this.deposit = function(amount) {
balance += amount;
transactionHistory.push({ type: 'deposit', amount });
return balance;
};
this.withdraw = function(amount) {
if (amount > balance) {
throw new Error('Insufficient funds');
}
balance -= amount;
transactionHistory.push({ type: 'withdraw', amount });
return balance;
};
this.getBalance = function() {
return balance; // controlled read access
};
this.getHistory = function() {
return [...transactionHistory]; // return a copy, prevent external mutation
};
}
const account = new BankAccount(100);
account.deposit(50);
console.log(account.getBalance()); // 150
console.log(account.balance); // undefined - truly inaccessible, not just convention
// Comparison with the modern private field syntax
class ModernBankAccount {
#balance;
#transactionHistory = [];
constructor(initialBalance) {
this.#balance = initialBalance;
}
deposit(amount) {
this.#balance += amount;
this.#transactionHistory.push({ type: 'deposit', amount });
return this.#balance;
}
getBalance() {
return this.#balance;
}
}
// Trade-off: closures create a new function per instance (memory cost per method),
// while class methods on the prototype are shared - # fields give privacy
// WITHOUT this memory overhead, which is why they're preferred today# syntax standardize होने से पहले, closures true data privacy पाने का मुख्य तरीका था - constructor function के अंदर वो variables जो 'this' से attach नहीं हैं, बाहर से inaccessible होते हैं।
// Closure-based encapsulation - classic pुराना approach
function BankAccount(initialBalance) {
let balance = initialBalance; // truly private
const transactionHistory = [];
this.deposit = function(amount) {
balance += amount;
transactionHistory.push({ type: 'deposit', amount });
return balance;
};
this.withdraw = function(amount) {
if (amount > balance) throw new Error('Insufficient funds');
balance -= amount;
transactionHistory.push({ type: 'withdraw', amount });
return balance;
};
this.getBalance = function() {
return balance;
};
this.getHistory = function() {
return [...transactionHistory];
};
}
const account = new BankAccount(100);
account.deposit(50);
console.log(account.getBalance()); // 150
console.log(account.balance); // undefined - truly inaccessible
// Modern private field syntax से comparison
class ModernBankAccount {
#balance;
#transactionHistory = [];
constructor(initialBalance) {
this.#balance = initialBalance;
}
deposit(amount) {
this.#balance += amount;
this.#transactionHistory.push({ type: 'deposit', amount });
return this.#balance;
}
getBalance() {
return this.#balance;
}
}
// Trade-off: closures हर instance में नया function बनाते हैं (memory cost),
// जबकि class methods prototype पर shared होते हैं - # fields बिना इस
// overhead के privacy देते हैं, इसीलिए आजकल preferred हैंWas this answer clear?