JavaScript Object Inheritance Patterns: Static Methods and Private Variables Implementation
JavaScript provides several mechanisms for implementing object-oriented patterns including inheritance, static methods, and private variables. Understanding these concepts helps create more robust and maintainable code structures.
Basic Constructor Pattern with Private Variables
The following example demonstrates how to implement private variables using closure within constructor functions:
function createLogger(message) {
console.log(message);
}
function HumanBeing() {
// Private variables declared in closure
let internalName = "Anonymous";
let internalGender = "Male";
// Set defaults if no instance properties exist
internalGender = (this.gender) ? this.gender : internalGender;
internalName = (this.name) ? this.name : internalName;
// Public method with access to private variables
this.moveAround = function () {
createLogger("This " + internalGender + " is walking, their name is: " + internalName);
}
// Static method attached directly to constructor
HumanBeing.communicate = function (message) {
createLogger("Speaking: " + message);
}
}
Inheritance Implementation
Inheritance can be achieved through various methods. Here's an example using apply() to inherit from a parent constructor:
function Learner() {
// Inherit from parent constructor
HumanBeing.apply(this);
// Local private variables
let learnerName = this.name;
let studyCounter = 0;
this.takeCourse = function (subject) {
studyCounter++;
createLogger("Name: " + learnerName + ", studying " + subject);
}
this.getResults = function () {
createLogger("Test score: " + studyCounter);
}
}
Usage Examples
Creating instances and demonstrating the inheritance pattern:
// Create basic person instance
let individual1 = new HumanBeing();
individual1.moveAround();
// Apply constructor to existing object
let individual2 = { "name": "Tanaka", "gender": "Female" };
HumanBeing.apply(individual2);
individual2.moveAround();
console.log("-----------------------------------");
// Create student-like object
let pupil = { "name": "Sato", "gender": "Female" };
Learner.call(pupil);
pupil.takeCourse("MATHEMATICS");
pupil.takeCourse("MATHEMATICS");
pupil.takeCourse("MATHEMATICS");
pupil.getResults();
// Modify object properties
Object.assign(pupil, { "name": "Yamada" });
Learner.call(pupil);
pupil.moveAround();
Understanding Object.assign Behavior
The Object.assign() method merges objects with specific behavior patterns. The target object gets modified, and later properties override earlier ones:
const sourceObject = {
propA: 1,
propB: 2,
propC: 3
};
let targetObject = {propC: 4, propD: 5};
const result = Object.assign(targetObject, sourceObject);
console.log(result.propC, result.propD); // Output: 3 5
console.log(sourceObject); // Original unchanged
console.log(result); // Modified target
console.log(targetObject); // Same reference as result
console.log(result === targetObject); // true
Key Considerations
Private variables maintain their encapsulation through closures, ensuring data integrity. The counter variable in the Learner example remains isolated from external modification. When using Object.assign(), remember that it modifies the first parameter object directly.
Static methods attached directly to constructors provide utility functions accessible without instance creation. These patterns demonstrate fundamental JavaScript object-oriented programming techniques.