this
possibly the most misunderstood keyword in javascript
No accepted answers 😢
//in global scope
console.log(this);
function foo(){
console.log(this);
}
foo();
const foo = {
bar: function(){
console.log(this)
}
};
foo.bar();
const clickHandler = function(evt) {
console.log(this);
};
document
.querySelector('#element')
.addEventListener('click', clickHandler);
const that = this;
const clickHandler = function(evt) {
console.log(that);
};
document
.querySelector('#element')
.addEventListener('click', clickHandler);
let clickHandler = function(evt) {
console.log(that);
};
clickHandler = clickHandler.bind(this)
document
.querySelector('#element')
.addEventListener('click', clickHandler);
const person = {
greet: function(){
console.log(this);
}
}
const mygreet = person.greet;
mygreet();
function baz(){
console.log(this);
}
const foo = {
bar: function(){
baz();
}
}
foo.bar();
const clickHandler = (evt) => {
console.log(that); // window
};
document
.querySelector('#element')
.addEventListener('click', clickHandler);
Arrow Function
this differences
An arrow function does not create its own this context, so this has its original meaning from the enclosing context.
-https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Classes define "patterns" or "templates" which are not instanciated
No classes, only actual objects and instanciated things
Different types of inheritance: single, multi-level, multiple, hybrid
Children only inherit from their prototype object
Both are a system for sharing/reusing functionality/behavior
There are several global objects in every JavaScript environment. They are actual objects.
These are the fundamental, basic objects upon which all other objects are based. This includes objects that represent general objects, functions, and errors.
Object.freeze()
Object.create()
Object.keys()
Object.prototype.toString()
Object.prototype.valueOf()
const person = { name: 'Bob' };
person.toString() // [object Object]
person
- name
- prototype
- __proto__
Object
- keys
- ...
- prototype
- __proto__
- ...
- toString
Cat
- name
- prototype
- __proto__
Object
- keys
- prototype
- toString
- __proto__
Animal
- Genus
- prototype
- speak
-__proto__
Cat
- name
- prototype
- __proto__
Object
- keys
- prototype
- toString
- __proto__
Animal
- Genus
- prototype
- speak
- toString
-__proto__
Overriding prototype methods
const Person = function({name, age}) {
this.name = name;
this.age = age;
this.greet = function() { return "hey"; }
}
const Bob = new Person({name: 'Bob', age: 35});
const Person = function({name, age}) {
this.name = name;
this.age = age;
this.greet = function(){ return "hey"; }
}
const Bob = new Person({name: 'Bob', age: 35});
const Person = function({name, age}) {
this.name = name;
this.age = age;
}
Person.prototype.doWork = function(){ }
const Bob = new Person({name: 'Bob', age: 35});
Bob.doWork()
const Person = function({name, age}) {
this.name = name;
this.age = age;
}
Person.prototype.doWork = function(){ }
const Bob = new Person({name: 'Bob', age: 35});
Bob.doWork()
Bob
- name
- age
- prototype
- __proto__
Person
- prototype
- doWork
JavaScript classes introduced in ECMAScript 2015 are syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax is not introducing a new object-oriented inheritance model to JavaScript. JavaScript classes provide a much simpler and clearer syntax to create objects and deal with inheritance.
-https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
class Person{
constructor({name, age}){
this.name = name;
this.age = age;
}
}
const Bob = new Person({name: "Bob", age: 35});
const Person = function({name, age}) {
this.name = name;
this.age = age;
}
const Bob = new Person({name: "Bob", age: 35});
Equivalent
class Person{
constructor({name, age}){
this.name = name;
this.age = age;
}
}
const Bob = new Person({name: "Bob", age: 35});
class keyword
opening and closing curly brace
constructor method
Must use new keyword
class Person{
constructor({name, age}){
this.name = name;
this.age = age;
}
}
const Bob = new Person({name: "Bob", age: 35});
class Animal{
constructor({name}){
this.name = name;
}
}
class Cat extends Animal{
constructor({name, color}){
super({name});
this.color = color;
}
}
Animal extends Cat & passes Cat's constructor some properties
class Animal{
constructor({name}){
this.name = name;
}
}
class Cat extends Animal{
constructor({name, color}){
super({name});
this.color = color;
}
}
Cat
- color
- prototype
- __proto__
Object
- ...
- prototype
- __proto__
- ...
Animal
- name
- prototype
-__proto__
class Cat extends Animal{
constructor({name, color}){
super({name});
this.color = color;
}
speak(){
return "🐱 Meow."
}
}
const Spot = new Cat({name: "Spot", color: "#d89400"});
Spot.speak(); //"🐱 Meow."
Classes can contain "methods". In reality, a method is just a function attached to the object prototype
class Cat extends Animal{
constructor({name, color}){
super({name});
this.color = color;
}
speak(){
return `${this.name} says "Meow" 🐱`;
}
}
const Spot = new Cat({name: "Spot", color: "#d89400"});
Spot.speak(); // 'Spot says "Meow" 🐱';
Since we are using this in a function, it refers to the object which called it -- Spot in this case. this.name is resolved by following the prototype chain up to Animal
class ButtonWidget{
constructor({alertValue}){
this.alertValue=alertValue;
}
clickHandler(){
console.log(this.alertValue);
}
render(){
const btn = document.createElement('button');
btn.textContent = "Click Me!";
btn.addEventListener('click', this.clickHandler);
return btn;
}
}
Spot the bug:
class ButtonWidget{
constructor({alertValue}){
this.alertValue=alertValue;
this.clickHandler = this.clickHandler.bind(this);
}
clickHandler(){
console.log(this.alertValue);
}
render(){
const btn = document.createElement('button');
btn.textContent = "Click Me!";
btn.addEventListener('click', this.clickHandler);
return btn;
}
}
Now clickHandler works as expected
class SimpleButton extends React.Component{
constructor(props){
super(props);
this.clickHandler = this.clickHandler.bind(this)
}
clickHandler(evt){
// "this" is now properly bound
// to the context of the class
}
render(){
return(
<div>
<button onClick={this.clickHandler}> Click Me! </button>
</div>
)
}
}
class SimpleButton extends React.Component{
constructor(props){
super(props);
}
clickHandler = (evt) => {
// using an arrow function, `this` doesn't get
// assigned to it's callers context (button)
}
render(){
return(
<div>
<button onClick={this.clickHandler}> Click Me! </button>
</div>
)
}
}
Arrow functions as class properties are a proposal for ES7 that is likely to be adopted. This syntax is supported in the React Starter Kit
You're great, too :)