0 Introduction
Object literals
- when you create object literals, you treat each object as a unique set of properties
// object with literal notation
let uma = {
firstname: 'Uma',
lastname: 'Thurman',
birthdate: 'April 29, 1970',
age(){
let millisecs = (new Date() - new Date(this.birthdate));
return Math.floor( millisecs / (1000*60*60*24*365) );
}
}
In the object-oriented paradigm, objects have: state, behaviour and identity
- the state of the object uma is the value of the properties:
firstname,lastnameandbirthdate - the object uma has identity, because another object with same state is a different object
- the object uma has behaviour: the
agefunction
Classes of objects
- it is convenient to define a class of objects that shares certain properties
- instances of the class have their own properties and their class methods
- these own properties hold the state of the object
- these methods are defined by the class and shared by all the instances of the class
- for example, imagine a class named Employee that represents the employees that work for a company
JavaScript classes
- JavaScript classes use prototype-based inheritance
- objects belong to the same class if they inherit from the same prototype
How to define classes in JavaScript
- In ES5, objects are instances of the same class if they were created by the same constructor function
- In ES6, you can define classes by using a simplified syntax with
classkeyword
1 Classes and Factory Functions
How to define a class in JavaScript using a factory function:
- write an object to use as prototype and a factory function that create new objects that inherit from this prototype
- the factory function makes new objects and initializes them
- note: this is not the idiomatic way to define a class in JavaScript
Example: defining the createPerson factory function
// place common properties into prototype object
const personPrototype = {
age(){
let millisecs = (new Date() - new Date(this.birthdate));
return Math.floor( millisecs / (1000*60*60*24*365) );
}
}
// then set the [[Prototype]] slot in the factory function
function createPerson(firstname, lastname, birthdate) {
const result = { firstname, lastname, birthdate };
Object.setPrototypeOf(result, personPrototype);
return result;
}
Example: using the createPerson factory function
// create two instances of the Person class
const uma = createPerson('Uma', 'Thurman', 'April 29, 1970');
const john = createPerson('John', 'Malkovich', 'December 9, 1953');
// a person has only three properties
console.log(uma); // { firstname: 'Uma', lastname: 'Thurman', birthdate: 'April 29, 1970' }
console.log(john); // { firstname: 'John', lastname: 'Malkovich', birthdate: 'December 9, 1953' }
// the age method in the prototype object
console.log(Object.getPrototypeOf(uma)); // { age: [Function: age] }
// invoke the age method in the shared prototype object
console.log(`${john.firstname} ${john.lastname} is ${john.age()}`); // John Malkovich is 66
All instances of the Person class share the same prototype object
- the [[Prototype]] properties of uma and john objects points to the same
personPrototypeobject
2 Classes and Constructors
What is a constructor function?
- a constructor is a function designed for the initialization of newly created objects
- by convention, a constructor function has its name written in uppercase
- invoke a constructor using the
newkeyword: - for example:
const john = new Person() - the
newkeyword automatically creates a new object - the constructor only has to initialize the state of the new object
Setting prototype for new objects
- a constructor invocation automaticaly sets a prototype
- the
Person.prototypeproperty is used to set the[[Prototype]]property of the new object - objects created by the same constructor inherits from the same prototype and therefore are instances of the same class
- The prototype object of the constructor is stored as a property of the function object
- the constructor function is an object and therefore it can have properties
- the
Person.prototypeis a property of the Person function and you can add more functions to it - for example: you can add the
age()method toPerson.prototype
What happens when you call the Person constructor:
const uma = new Person('Uma', 'Thurman', 'April 29, 1970'); - the new keyword creates a new blank object
- the
Personfunction is invoked as method of new object - the
thisvalue is set to the new object - the body of the
Personfunction is executed to initialize the new object - the firstname, lastname, birthdate properties of the object are set to the constructor's arguments
- the
[[Prototype]]property of the new object is set to the prototype object of the Person constructor function - the newly constructed object is returned
Example: declaring the Person constructor function
// the Person constructor function
function Person(firstname, lastname, birthdate) {
this.firstname = firstname;
this.lastname = lastname;
this.birthdate = birthdate;
}
// Add methods to the prototype of the Person constructor function
Person.prototype.age = function() {
let millisecs = (new Date() - new Date(this.birthdate));
return Math.floor( millisecs / (1000*60*60*24*365) );
}
Example: using the Person constructor function
// construct two instances
const uma = new Person('Uma', 'Thurman', 'April 29, 1970');
const john = new Person('John', 'Malkovich', 'December 9, 1953');
// log the two instances of Person class
console.log(uma); // Person { firstname: 'Uma', lastname: 'Thurman', birthdate: 'April 29, 1970' }
console.log(john); // Person { firstname: 'John', lastname: 'Malkovich', birthdate: 'December 9, 1953' }
// invoke age method from Person.prototype
console.log(`${john.firstname} ${john.lastname} is ${john.age()}`); // John Malkovich is 66
// invoke toString method from Object.Prototype
console.log(john.toString()); // [object Object]
// the prototype is an object with a single property, the age function
console.log(Person.prototype); // Person { age: [Function] }
In the image below, two objects were created by using the Person constructor function.
-
umaandjohninstances share the same prototype -
Person.prototypehas a[[Prototype]]property that points toObject.prototype
Compare and contrast createPerson factory function and Person constructor function
- constructor functions use capital letters whereas regular functions and methods begin with lowercase letters
- the constructor is invoked with the new keyword, whereas the factory function without the new keyword
- the constructors does not have to return the new object, whereas the factory function does
- in the factory function, the prototype was arbitrary named
personPrototype, whereas, in the constructor function, the prototype is namedPerson.prototypeand this name is mandatory
Classes and arrow functions
- both factory and constructor examples use ordinary functions, not arrow functions to define constructor; arrow functions do not have a prototype property and cannot be used as constructors
- both the two examples use ordinary functions, not arrow functions, to define methods.
Methods use
thisto refer to the object on which they are invoked. Ordinary functions set thethisvalue based on the objects which they are invoked on, whereas arrow functions inheritthisfrom the context where they are defined.
Prototypes as Class identity
- the prototype object, not the constructor, is fundamental to the identity of a class
- if two constructors have prototype properties that point to the same prototype object, then both the two constructors can be used to create instances of the same class.
Constructors as Class face
- the constructor function represents the face of a class
- the name of the constructor is adopted as the name of the class
- we say that the Employee constructor creates Employee objects
How to test objects for membership in a class
- use the constructor with the
instanceofoperator for testing objects for membership in a class - the
obj instanceof Constructorexpression evaluates to true if obj inherits fromConstructor.prototype
let john = new Person(); john instanceof Person // -> true: john inherits from Person.prototype
obj instanceof Constructor expression does not check whether obj is initialized by the Constructor function.
If you create a People constructor function that sets the prototype to the same Person.prototype,
then the instanceof operator will find objects created by People as instances to the same Person classTesting for the prototype without using constructor function
- the
Object.prototype.isPrototypeOf()method allows to test the prototype chain without using the constructor - this method is useful if you defined a class using a factory function not a constructor function
-
proto.isPrototypeOf(obj)returns true ifprotois in the prototype chain ofobj - example:
personPrototype.isPrototypeOf(person);
The constructor property
- Any regular JavaScript function can be used as constructor
- every regular JavaScript function has a
prototypeproperty, which points to the prototype object - the prototype object has a single property: the
constructorproperty, which references to the function object:
The constructor property for class instances
- All the functions has their predefined prototype objects that has its constructor property
- every class instance inherits the constructor property that refers to its constructor function
- the constructor serves as face of a class, the constructor property gives the class of the object
const john = new Person(); john.constructor === Person; // true

No comments:
Post a Comment