JavaScript Object-Oriented Programming Fundamentals: Prototypes, Constructors, and This Binding
Object-Oriented Concepts
Understanding Objects
Objects represent real-world entities in programming:
- They serve as containers encapsulating properties and methods
- They aggregate data collections and functional sets
- They form unordered property collections
Object-Oriented Programming
This paradigm abstracts complex real-world relationships into individual objects, enabling simulation through object collaboration.
Core OOP Principles
Encapsulation, inheritance, and polymorphism form the foundation of object-oriented design.
Object Creation Patterns
Literal Notation
const textbook = {
cost: 30,
title: "JavaScript",
educate: function() {
console.log(this.title + " imparts knowledge")
}
}
console.log(textbook.cost) // 30
textbook.educate() // JavaScript imparts knowledge
Constructor Pattern with new
const vehicle = new Object()
vehicle.model = "BYD"
vehicle.park = function() {
console.log(this.model + ' can park!')
}
console.log(vehicle) // {model: 'BYD', park: ƒ}
vehicle.park() // BYD can park!
Factory Pattern
const buildVehicle = function (color, model, parkingFunc) {
const veh = new Object()
veh.color = color
veh.model = model
veh.park = parkingFunc
return veh // Must return the object
}
const v1 = buildVehicle("black", "Audi", function () {
console.log(this.model + " can park downstairs")
})
console.log(v1) // {model: 'Audi', color: 'black', park: ƒ}
v1.park() // Audi can park downstairs
Constructor Functions
function Human(name, years) {
this.name = name
this.years = years
this.learn = function() {
console.log(this.name + " enjoys learning")
}
}
const person1 = new Human("Xiaohua", 10)
console.log(person1) // Human {name: 'Xiaohua', years: 10, learn: ƒ}
person1.learn() // Xiaohua enjoys learning
Constructor-Instance Relationships
Instance Creation Proceess
Constructor functions create new instances through the new operator:
- Creates a fresh object
- Sets
thiscontext to the new object - Executes constructor code
- Returns the new object
const Vessel = function (manufacturer) {
this.manufacturer = manufacturer
}
const glass = new Vessel("Lucky")
console.log(glass) // Vessel {manufacturer: 'Lucky'}
console.log(glass.constructor)
Constructor Property
Every object possesses a constructor property pointing back to its creating function.
JavaScript includes various object types: custom objects, DOM elements, BOM components, and built-in objects.
// Custom object
const auto = new Object()
console.log(auto.constructor) // ƒ Object() { [native code] }
// DOM element
const paragraph = document.getElementById('text')
console.log(paragraph.constructor) // ƒ HTMLParagraphElement()
// Browser history
console.log(window.history.constructor) // ƒ History() { [native code] }
// Date object
console.log(new Date().constructor) // ƒ Date()
// Function object
function sample() {}
console.log(sample.constructor) // ƒ Function() { [native code] }
Object Type Detection
Instanceof Operator
The instanceof operator determines if a value is an object instance:
const vehicleObj = {}
const numberArray = []
const callback = function () {}
console.log(vehicleObj instanceof Object) // true
console.log(numberArray instanceof Object) // true
console.log(callback instanceof Object) // true
console.log(12.4 instanceof Object) // false
console.log('23.4' instanceof Object) // false
Memory Managemnet in Constructors
Memory Lifecycle
Memory management involves three phases:
- Allocation during variable declaration or function creation
- Usage during operations and method calls
- Deallocation through JavaScript's automatic garbage collection
Addressing Memory Inefficiency
Global Property Sharing
// Shared resources
const commonAge = 18
const sharedLearning = function () {
console.log(this.identifier + ' enjoys studying JS')
}
function Individual(identifier, age, gender, learningFunc) {
this.identifier = identifier
this.age = age
this.gender = gender
this.study = learningFunc
}
const ind1 = new Individual('Xiaohua', commonAge, 'female', sharedLearning)
const ind2 = new Individual('Xiaoming', commonAge, 'male', sharedLearning)
console.log(ind1) // Individual {identifier: 'Xiaohua', age: 18, gender: 'female', study: ƒ}
console.log(ind2) // Individual {identifier: 'Xiaoming', age: 18, gender: 'male', study: ƒ}
ind1.study() // Xiaohua enjoys studying JS
ind2.study() // Xiaoming enjoys studying JS
Prototype-Based Solutions
Prototypes provide two key benefits:
- Memory space optimization
- Data sharing capabilities
Prototype Relationships
Function Prototypes
All functions possess a prototype property, which is a object itself:
function sampleFunction() {}
console.log(sampleFunction.prototype instanceof Object) // true
console.log(typeof sampleFunction.prototype) // object
Constructor Prototypes
function Automobile(model) {
this.model = model
}
Automobile.prototype.hue = "white"
Automobile.prototype.playAudio = function () {
console.log("can play music")
}
const auto1 = new Automobile('BYD')
console.log(Automobile.prototype)
console.log(auto1.hue) // white
Prototype Chain Properties
- Instance objects have
constructorproperties pointing to their constructors - Prototype objects also have
constructorproperties pointing to constructors - All objects have
__proto__properties linking to their constructor's prototype
const Container = function (maker) {
this.maker = maker
}
const container = new Container("bbb")
console.log(container.constructor)
console.log(Container.prototype.constructor === Container) // true
console.log(container.__proto__ === Container.prototype) // true
Prototype Chains
Chain Resolution
When accessing object properties, JavaScript traverses the prototype chain:
- First checks the object itself
- Then searches up the
__proto__chain - Eventually reaches null at the end
Property Lookup Rule
The search order follows: instance → prototype chain → undefined
function Sample() { }
Sample.prototype.value = 1
const instanceB = new Sample()
Sample.prototype = {
value: 2,
metric: 3
}
const instanceC = new Sample()
console.log(instanceB.value) // 1
console.log(instanceB.metric) // undefined
console.log(instanceC.value) // 2
console.log(instanceC.metric) // 3
Prototype Chain Structure
function Bottle(brand, volume) {
this.brand = brand
this.volume = volume
}
const bottle = new Bottle('Monqing', '200ml')
console.log(bottle.volume) // 200ml
console.log(bottle.__proto__ === Bottle.prototype) // true
// Prototype objects also have __proto__ pointing to Object.prototype
console.log(Bottle.prototype.__proto__ === Object.prototype) // true
// Object.prototype's __proto__ points to null
console.log(Object.prototype.__proto__) // null
Context Binding Methods
Common Characteristics
These methods share similar functionality for context manipulation.
Call Method
const personName = 'Xiaohua'
function greet() {
console.log('I am a function')
}
greet() // I am a function
greet.call() // I am a function
const personA = {
personName: 'Xiaoming',
fetchName: function () {
console.log(this.personName)
}
}
personA.fetchName.call() // Xiaohua (when no argument, context is window)
const personB = {
personName: 'Xiaogang',
fetchName: function () {
console.log(this.personName)
}
}
personA.fetchName.call(personB) // Xiaogang
Apply Method
Similar to call() but accepts arguments as an array:
console.log(Math.max(30, 40, 50)) // 50
console.log(Math.max.apply(null, [30, 40, 50])) // 50
console.log(Math.max.apply(window, [30, 40, 50])) // 50
Bind Method
Creates a new function with bound context without immediate execution:
const studentName = "Xiaohua"
const boundFunction = function fn() {
console.log(this.studentName)
}.bind()
boundFunction() // Xiaohua
const studentB = {
studentName: 'Xiaogang',
getName: function () {
console.log(this.studentName)
}
}
const studentC = {
studentName: 'Xiaoli',
getName: function () {
console.log(this.studentName)
}.bind(studentB) // Xiaogang
}
This Context in Functions
When instances invoke methods, this refers to the instance. When prototype methods are called, this refers to the prototype context.
function Glass(name) {
this.name = name
this.use = function () {
console.log(this.name + " can be used for drinking")
}
}
Glass.prototype.name = "I am prototype"
const glass = new Glass("Xiaomi Glass")
glass.use() // this refers to Xiaomi Glass
console.log(Glass.prototype.name) // outputs I am prototype