Skip to content

Commit f0bc903

Browse files
committed
implicit, explicit, new, lexical and window Binding
1 parent a46a579 commit f0bc903

File tree

1 file changed

+166
-2
lines changed

1 file changed

+166
-2
lines changed

ObjectOrientedProgramming.md

Lines changed: 166 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,12 @@ Objects of the same type are created by calling the constructor function with th
7777

7878
In JavaScript, the thing called `this` is the object that "owns" the code. The value of `this`, when used in an object, is the object itself. This is because the execution context changes after an object is created. In a constructor function `this` does not have a value. It is a substitute for the new object. The value of `this` will become the new object when a new object is created.
7979

80-
<i>Note that this is not a variable. It is a keyword. You cannot change the value of this.</i>
80+
<i>Note that `this` is not a variable. It is a keyword. You cannot change the value of `this`.</i>
8181

8282
As a rule all constructor functions should start with a capital letter to let other programmers know that you need to call this function using the `new` keyword.
8383

84+
To add properties to a constructor function you must prepend them with `this`.
85+
8486
```javascript
8587
function Elf(name, weapon) {
8688
this.name = name;
@@ -105,4 +107,166 @@ Peter doesn't have `attack` as it's own method but when `Peter.attack()` gets ca
105107

106108
This is efficient because `attack` now exists in the same location in memory and we now no longer have to copy it multiple times in order to use it.
107109

108-
<i>Note: Remember, we can't use arrow functions in constructors because arrow functions are lexically scoped and will point the value of `this` back to the function itself where it was written.</i>
110+
<i>Note: Remember, we can't use arrow functions in constructors because arrow functions are lexically scoped and will point the value of `this` back to the function itself where it was written.</i>
111+
112+
#### Using ES6 Classes
113+
114+
Constructor functions inside classes get run every time we instantiate the class.
115+
116+
```javascript
117+
class Elf {
118+
constructor(name, weapon) {
119+
this.name = name;
120+
this.weapon = weapon;
121+
}
122+
attack() {
123+
return 'attack with ' + this.weapon
124+
}
125+
}
126+
127+
const peter = new Elf('Peter', 'stones')
128+
peter.attack() // -> attack with stones
129+
130+
console.log(peter instanceof Elf) // -> true
131+
```
132+
133+
<i>Note: In JavaScript ES6 classes are syntactic sugar. Under the hood they are still technically using prototypal inheritance. JavaScript classes are still technically objects.</i>
134+
135+
---
136+
<br>
137+
138+
## More of `this`
139+
140+
#### Implicit Binding
141+
142+
```javascript
143+
const person = {
144+
name: 'Corey',
145+
age: 26,
146+
hi() {
147+
console.log('Hi ' + this.name)
148+
}
149+
}
150+
151+
person.hi() // -> Hi Corey
152+
```
153+
154+
#### Explicit Binding: with `call()`
155+
156+
We know that in order to tell what the this keyword is referencing we first have to look at where the function is being invoked. Now, this brings up the question, how can we invoke greet but have it be invoked with the `this` keyword referencing the person object. We can’t just do person.greet() like we did before because person doesn’t have a greet method. In JavaScript, every function contains a method which allows you to do exactly this and that method is named `call()`. `call()` is a method on every function that allows you to invoke the function specifying in what context the function will be invoked.
157+
158+
Again, `call()` is a property on every function and the first argument you pass to it will be the context (or the focal object) in which the function is invoked. In other words, the first argument you pass to call will be what the `this` keyword inside that function is referencing.
159+
160+
```javascript
161+
function greet(lang1, lang2, lang3) {
162+
console.log(`Hello, my name is ${this.name} and I know ${lang1}, ${lang2} & ${lang3}.`)
163+
}
164+
165+
const person = {
166+
name: 'Corey',
167+
age: 26
168+
}
169+
170+
greet.call(person, 'JavaScript', 'PHP', 'Ruby')
171+
// -> Hello, my name is Corey and I know JavaScript, PHP & Ruby.
172+
```
173+
174+
#### Explicit Binding: with `apply()`
175+
176+
`apply()` is the exact same thing as `call()`, but instead of passing in arguments one by one, you can pass in a single array and it will spread each element in the array out for you as arguments to the function.
177+
178+
```javascript
179+
function greet(lang1, lang2, lang3) {
180+
console.log(`Hello, my name is ${this.name} and I know ${lang1}, ${lang2} & ${lang3}.`)
181+
}
182+
183+
const person = {
184+
name: 'Corey',
185+
age: 26
186+
}
187+
188+
const languages = ['JavaScript', 'PHP', 'Ruby']
189+
190+
greet.apply(person, languages)
191+
// -> Hello, my name is Corey and I know JavaScript, PHP & Ruby.
192+
```
193+
194+
#### Explicit Binding: with `bind()`
195+
196+
`bind()` is the exact same as `call()` but instead of immediately invoking the function, it’ll return a new function that you can invoke at a later time. Therefore we should save it to a variable.
197+
198+
```javascript
199+
function greet(lang1, lang2, lang3) {
200+
console.log(`Hello, my name is ${this.name} and I know ${lang1}, ${lang2} & ${lang3}.`)
201+
}
202+
203+
const person = {
204+
name: 'Corey',
205+
age: 26
206+
}
207+
208+
const greeting = greet.bind(person, 'JavaScript', 'PHP', 'Ruby')
209+
210+
greeting() // -> Hello, my name is Corey and I know JavaScript, PHP & Ruby.
211+
```
212+
213+
#### `new` Binding
214+
215+
The third rule for figuring out what the this keyword is referencing is called the `new` binding. Whenever you invoke a function with the `new` keyword, under the hood, the JavaScript interpreter will create a brand new object for you and call it `this`. So, naturally, if a function was called with `new`, the `this` keyword is referencing that new object that the interpreter created.
216+
217+
```javascript
218+
function Person(name, age) {
219+
/*
220+
Under the hood, JavaScript creates a new object called `this`
221+
which delegates to the Person's prototype on failed lookups. If a
222+
function is called with the new keyword, then it's this new object
223+
that the interpreter created that the this keyword is referencing.
224+
*/
225+
226+
this.name = name
227+
this.age = age
228+
}
229+
230+
const me = new Person('Corey', 26)
231+
```
232+
233+
#### Lexical Binding
234+
235+
With arrow functions, `this` is determined “lexically”. Arrow functions don’t have their own `this`. Instead, just like with variable lookups, the JavaScript interpreter will look to the enclosing (parent) scope to determine what `this` is referencing.
236+
237+
```javascript
238+
const person = {
239+
name: 'Corey',
240+
age: 26,
241+
languages: ['JavaScript', 'PHP', 'Ruby'],
242+
243+
greet() {
244+
const hello = `Hello, my name is ${this.name} and I know `
245+
246+
const langs = this.languages.reduce((str, lang, i) => {
247+
if (i === this.languages.length - 1) {
248+
return `${str} and ${lang}.`
249+
}
250+
return `${str} ${lang},`
251+
})
252+
253+
console.log(hello + langs)
254+
}
255+
}
256+
257+
person.greet() // -> Hello, my name is Corey and I know JavaScript PHP, and Ruby.
258+
```
259+
260+
#### window Binding
261+
262+
When we’re not using `call`, `apply`, `bind`, or the `new` keyword, by default `this` will reference the `window` object. What that means is if we add an age property to the `window` object, then when we invoke our sayAge function, `this.age` will be whatever the age property is on the `window` object.
263+
264+
```javascript
265+
age = 26
266+
267+
function sayAge() {
268+
console.log(`My age is ${this.age}`)
269+
}
270+
271+
sayAge() // -> my age is 26
272+
```

0 commit comments

Comments
 (0)