Security Theater
SecTheater is an online teaching community that targets the IT department. We do our best to produce for you high quality and well-edited screen casts about web development.
A deep dive into JavaScript OOP
How to create an object?
let user = {
credentials: [
'ahmedosama',
'ahmedosama@sectheater.io',
'123456789',
],
signout() {
/* Some business logic */
},
updateProfile() {
// Some business logic
},
}
How to create an object?
let user = Object.create({})
user.credentials = []
user.credentials.push(
'ahmedosama',
'ahmedosama@sectheater.io',
'123456789',
)
user.register = function () {}
user.login = function () {}
user.logout = function () {}
console.log(user)
How to create an object?
let user = {...}
function createUser(username, email, password) {
let user = {
credentials: [],
}
user.credentials.push(username, email, password)
user.register = function () {}
user.login = function () {}
user.logout = function () {}
return user
}
let user = createUser(
'ahmedosama',
'ahmedosama@sectheater.io',
'123456789',
)
console.log(user)
Prototypes
Prototypes
let user = {
credentials: [
'ahmedosama',
'ahmedosama@sectheater.io',
'123456789',
],
signout() {
/* Some business logic */
},
updateProfile() {
// Some business logic
},
}
Prototypes
function createUser(username, email, password) {
let user = Object.create(userFunctions)
user.credentials = []
user.credentials.push(username, email, password)
return user
}
const userFunctions = {
login() {},
logout() {},
register() {},
}
const user1 = createUser(
'ahmedosama',
'ahmedosama@sectheater.io',
'123456789',
)
const user2 = createUser(
'mohamedosama',
'mohamedosama@sectheater.io',
'creative_password',
)
New keyword
function UserFactory(username, email, password) {
this.username = username
this.email = email
this.password = password
}
let user = new UserFactory(
'ahmedosama',
'ahmedosama@sectheater.io',
'123456789',
)
console.log(user)
Prototypes
function double(x) {
return x * 2
}
double.y = 3
double(3) // 6
double.y // 3
double.prototype // {}
New keyword
function UserFactory(username, email, password) {...}
let user = new UserFactory(...)
new UserFactory()
Thread of execution
Local Memory
Return value
New keyword
function UserFactory(username, email, password) {...}
let user = new UserFactory(
"ahmedosama",
"ahmedosama@sectheater.io",
"1234567890"
)
new UserFactory()
Thread of execution
Local Memory
Return value
username: 'ahmedosama'
email: 'ahmedosama@sectheater.io'
password: '123456789'
this: {}
New keyword
function UserFactory(username, email, password) {
this.username = username
this.email = email
this.password = password
}
let user = new UserFactory(
"ahmedosama",
"ahmedosama@sectheater.io",
"1234567890"
)
new UserFactory()
Thread of execution
Local Memory
Return value
username: 'ahmedosama'
email: 'ahmedosama@sectheater.io'
password: '123456789'
this: {
username: 'ahmedosama',
email: 'ahmedosama@sectheater.io',
password: '123456789',
}
Global Memory
UserFactory: => f() =>
+
{
prototype: {}
}
user:
New keyword
function UserFactory(username, email, password) {
this.username = username
this.email = email
this.password = password
}
UserFactory.prototype.register = function () {}
UserFactory.prototype.login = function () {}
UserFactory.prototype.logout = function () {}
let user = new UserFactory(
"ahmedosama",
"ahmedosama@sectheater.io",
"1234567890"
)
new UserFactory()
Thread of execution
Local Memory
Return value
username: 'ahmedosama'
email: 'ahmedosama@sectheater.io'
password: '123456789'
this: {
username: 'ahmedosama',
email: 'ahmedosama@sectheater.io',
password: '123456789',
__proto__: UserFactory
}
Global Memory
UserFactory: => f() =>
+
{
prototype: {
register: => f() =>
login: => f() =>
logout: => f() =>
}
}
user:
New keyword
new UserFactory()
Thread of execution
Local Memory
Return value
username: 'ahmedosama'
email: 'ahmedosama@sectheater.io'
password: '123456789'
this: {
username: 'ahmedosama',
email: 'ahmedosama@sectheater.io',
password: '123456789',
__proto__: UserFactory
}
function UserFactory(username, email, password) {
this.username = username
this.email = email
this.password = password
}
UserFactory.prototype.register = function () {}
UserFactory.prototype.login = function () {}
UserFactory.prototype.logout = function () {}
let user = new UserFactory(
"ahmedosama",
"ahmedosama@sectheater.io",
"1234567890"
)
Global Memory
UserFactory: => f() =>
+
{
prototype: {
register: => f() =>
login: => f() =>
logout: => f() =>
}
}
user: {
username: 'ahmedosama',
email: 'ahmedosama@sectheater.io',
password: '123456789',
__proto__: UserFactory
}
New keyword
new UserFactory()
Thread of execution
Local Memory
Return value
username: 'ahmedosama'
email: 'ahmedosama@sectheater.io'
password: '123456789'
this: {
username: 'ahmedosama',
email: 'ahmedosama@sectheater.io',
password: '123456789',
__proto__: UserFactory
}
function UserFactory(username, email, password) {
this.username = username
this.email = email
this.password = password
}
UserFactory.prototype.register = function () {}
UserFactory.prototype.login = function () {}
UserFactory.prototype.logout = function () {}
let user = new UserFactory(
"ahmedosama",
"ahmedosama@sectheater.io",
"1234567890"
)
Global Memory
UserFactory: => f() =>
+
{
prototype: {
register: => f() =>
login: => f() =>
logout: => f() =>
}
}
user: {
username: 'ahmedosama',
email: 'ahmedosama@sectheater.io',
password: '123456789',
__proto__: UserFactory
}
Object default proto
const obj = {
num: 3,
getNum: function () {
return this.num
},
}
console.log(obj.getNum()) // 3
console.log(obj.hasOwnProperty('num')) // true
This keyword
function UserFactory(username, email, password) {
this.username = username
this.email = email
this.password = password
}
UserFactory.prototype.register = function () {}
UserFactory.prototype.login = function () {}
UserFactory.prototype.logout = function () {}
let user = new UserFactory(
"ahmedosama",
"ahmedosama@sectheater.io",
"1234567890"
)
This keyword
function UserFactory(username, email, password) {
this.username = username
this.email = email
this.password = password
}
...
What is `this`?
What isn't `this`?
Self referencing fn
Fn's lexical scope
This keyword
function UserFactory(username, email, password) {
this.username = username
this.email = email
this.password = password
}
...
What is `this`?
Self referencing fn
Contextual binding
This keyword
function getName() {
console.log(this.first_name)
}
var first_name = "ahmed"
getName() // ahmed
What is `this`?
Self referencing fn
Default binding
This keyword
function getName() {
console.log(this.first_name)
}
let user = {
first_name: 'ahmed',
last_name: 'osama',
getName,
}
user.getName() // ahmed
What is `this`?
Self referencing fn
Implicit binding
This keyword
function getName() {
console.log(this.first_name)
}
let user = {
first_name: 'ahmed',
last_name: 'osama',
getName,
}
let anotherUser = {
first_name: 'mahmoud',
last_name: 'khaled',
getName,
}
user.getName() // ahmed
anotherUser.getName() // mahmoud
What is `this`?
Self referencing fn
Implicit binding
This keyword
function getName() {
console.log(this.first_name)
}
let user = {
first_name: 'ahmed',
last_name: 'osama',
getName,
}
let anotherUser = {
first_name: 'mahmoud',
last_name: 'khaled',
getName,
}
setTimeout(user.getName, 1000) // undefined
anotherUser.getName() // mahmoud
What is `this`?
Self referencing fn
Losing implicit context
This keyword
const getName = () => console.log(this.first_name)
let user = {
first_name: 'ahmed',
last_name: 'osama',
getName,
}
let anotherUser = {
first_name: 'mahmoud',
last_name: 'khaled',
getName,
}
setTimeout(user.getName, 1000) // undefined
anotherUser.getName() // undefined
What is `this`?
Self referencing fn
Losing implicit context
This keyword
function getName() {
console.log(this.first_name)
}
let user = {
first_name: 'ahmed',
last_name: 'osama',
}
let anotherUser = {
first_name: 'mahmoud',
last_name: 'khaled',
}
getName.call(user) // ahmed
getName.apply(anotherUser) // mahmoud
What is `this`?
Self referencing fn
Explicit binding
This keyword
function getName() {
console.log(this.first_name)
}
let user = {
first_name: 'ahmed',
last_name: 'osama',
}
let anotherUser = {
first_name: 'mahmoud',
last_name: 'khaled',
}
const getUserName = getName.bind(user)
const getAnotherUserName = getName.bind(anotherUser)
getUserName() // ahmed
getAnotherUserName() // mahmoud
What is `this`?
Self referencing fn
Hard binding
This keyword
function getName() {
console.log(this.first_name)
}
let user = {
first_name: 'ahmed',
last_name: 'osama',
}
let anotherUser = {
first_name: 'mahmoud',
last_name: 'khaled',
}
const getUserName = getName.bind(user)
const getAnotherUserName = getName.bind(anotherUser)
setTimeout(getUserName, 1000) // ahmed
getAnotherUserName() // mahmoud
What is `this`?
Self referencing fn
Hard binding
This keyword
function User(first_name, last_name) {
this.first_name = first_name
this.last_name = last_name
}
User.prototype.getName = function () {
return `${this.first_name} ${this.last_name}`
}
let firstUser = new User('ahmed', 'osama')
let secondUser = new User('mahmoud', 'khaled')
console.log(firstUser.getName()) // ahmed osama
console.log(secondUser.getName()) // mahmoud khaled
What is `this`?
Self referencing fn
New binding
This keyword
let user = {
first_name: 'ahmed',
last_name: 'osama',
getName: function getName() {
console.log(`${this.first_name} ${this.last_name}`)
},
}
let anotherUser = {
first_name: 'mahmoud',
last_name: 'khaled',
}
new (user.getName.bind(anotherUser))() // getName instance
user.getName() // ahmed osama
user.getName.bind(anotherUser)() // mahmoud khaled
user.getName.call(anotherUser) // mahmoud khaled
Binding precedence
Self referencing fn
New binding
This keyword
let user = {
first_name: 'ahmed',
last_name: 'osama',
getName: function getName() {
console.log(`${this.first_name} ${this.last_name}`)
},
}
let anotherUser = {
first_name: 'mahmoud',
last_name: 'khaled',
}
new (user.getName.bind(anotherUser))() // undefined undefined
user.getName() // ahmed osama
user.getName.bind(anotherUser)() // mahmoud khaled
user.getName.call(anotherUser) // mahmoud khaled
Self referencing fn
Binding precedence
This keyword
let workshop = {
instructor: 'ahmed osama',
course: 'OOP, the hard way',
students: ['mahmoud khaled', 'ismael mostafa', 'amira hany'],
printStudents: function () {
this.students.forEach(function (student) {
console.log(
`${student} is taking "${this.course}" with [${this.instructor}]`,
)
})
},
}
workshop.printStudents() // mahmoud khaled is taking "undefined" with [undefined]
Self referencing fn
Lexical this
This keyword
let workshop = {
instructor: 'ahmed osama',
course: 'OOP, the hard way',
students: [
'mahmoud khaled',
'ismael mostafa',
'amira hany',
],
printStudents: function () {
this.students.forEach(
function (student) {
console.log(
`${student} is taking "${this.course}" with [${this.instructor}]`,
)
}.bind(this),
)
},
}
workshop.printStudents()
Self referencing fn
Lexical this
This keyword
let workshop = {
instructor: 'ahmed osama',
course: 'OOP, the hard way',
students: [
'mahmoud khaled',
'ismael mostafa',
'amira hany',
],
printStudents: function () {
this.students.forEach((student) =>
console.log(
`${student} takes "${this.course}" with [${this.instructor}]`,
),
)
},
}
workshop.printStudents()
Self referencing fn
Lexical this
Inheritance/Sub classing
UserFactory
PremiumUserFactory
DiamondUserFactory
Inheritance/Sub classing
function UserFactory(username, email, password) {
let newUser = Object.create(userFunctions)
newUser.email = email
newUser.username = username
newUser.password = password
return newUser
}
const userFunctions = {
login: function () {},
logout: function () {},
register: function () {},
}
Inheritance/Sub classing
function PremiumUserFactory(
username,
email,
password,
balance,
) {
let newPremiumUser = Object.create(premiumUserFunctions)
newPremiumUser.email = email
newPremiumUser.username = username
newPremiumUser.password = password
newPremiumUser.balance = balance
return newPremiumUser
}
const premiumUserFunctions = {
accessCourses: function () {},
addToBookmark: function () {},
}
Object.setPrototypeOf(premiumUserFunctions, userFunctions)
Inheritance/Sub classing
function PremiumUserFactory(
username,
email,
password,
balance,
) {
let newPremiumUser = userFactory(
username,
email,
password,
)
Object.setPrototypeOf(
newPremiumUser,
premiumUserFunctions,
)
newPremiumUser.balance = balance
return newPremiumUser
}
const premiumUserFunctions = {
accessCourses: function () {},
addToBookmark: function () {},
}
Object.setPrototypeOf(premiumUserFunctions, userFunctions)
Inheritance/Sub classing
function UserFactory(username, email, password) {
this.username = username
this.email = email
this.password = password
}
UserFactory.prototype.login = function () {}
UserFactory.prototype.logout = function () {}
UserFactory.prototype.register = function () {}
Inheritance/Sub classing
function PremiumUserFactory(
username,
email,
password,
balance,
) {
UserFactory.call(this, username, email, password)
// UserFactory.apply(this, [username, email, password])
this.balance = balance
}
PremiumUserFactory.prototype = Object.create(UserFactory.prototype)
PremiumUserFactory.prototype.accessCourses = function () {}
Inheritance/Sub classing
class UserFactory {
constructor(username, email, password) {
this.username = username
this.email = email
this.password = password
}
register() {}
login() {}
logout() {}
}
Inheritance/Sub classing
class UserFactory {
constructor(username, email, password) {
this.username = username
this.email = email
this.password = password
}
register() {}
login() {}
logout() {}
}
class PremiumUserFactory extends UserFactory {
constructor(username, email, password, balance) {
super(username, email, password)
this.balance = balance
}
accessCourses() {}
}
Raise up your techinal skills
By Security Theater
The slides used in our course for exploring the deep concepts of using OOP in JavaScript.
SecTheater is an online teaching community that targets the IT department. We do our best to produce for you high quality and well-edited screen casts about web development.