UNPKG

js-102

Version:

JS-102 helps you learn JavaScript (the right way) so that you can confidently use higher-level libraries and frameworks. — Let’s reveal the magic!

191 lines (145 loc) 4.28 kB
/* * the devil is in the details * .--. __--__ (`-') .--. .----. .----. * | ,|/ _ / ( OO).->/_ | / .. \\_,-. | * |(_|\_..`--.(,------. | || / \ . .' .' * ,--. | |.-._) \`------' | |' \ / '.' /_ * | '-' /\ / | | \ `' /| | * `-----' `-----' `--' `---'' `------' * * This project is a part of the “Byte-Sized JavaScript” videocasts. * * You can watch “Byte-Sized JavaScript” at: https://bytesized.tv/ * * MIT Licensed — See LICENSE.md * * Send your comments, suggestions, and feedback to me@volkan.io */ const util = require( '../lib/util' ); const separator = util.separator; const log = console.log; // Remember just one thing, and you’ll be all set: // // `this` keyword is determined at “invocation time”, not at declaration time. { // Implicit binding separator(); function greet() { console.log( `Howdy, my name is ${this.name}; and I am a ${this.kind}.` ); } const harry = { name: 'Harry Potter', kind: 'lizard' }; harry.greet = greet; harry.greet(); const ron = { name: 'Ron Weasley', kind: 'weasel', // greet: function greet() { // console.log( `Howdy, my name is ${this.name}; and I am a ${this.kind}.` ); // } // greet: function() { // console.log( `Howdy, my name is ${this.name}; and I am a ${this.kind}.` ); // } greet() { log( `Howdy, my name is ${this.name}; and I am a ${this.kind}.` ); } }; ron.greet(); separator(); } { // Gotchas: function noStringsAttached() { log( 'noStringsAttached: `this === global` ?', this === global ); } noStringsAttached(); const hub = { add( fn ) { fn(); } }; function handler() { console.log( this.process.version ); }; // Structurally similar to // `elm.addEventListener( fn )` or `setTimeout( fn )`, or `setInterval( fn ) hub.add( handler ); hub.add( function() { console.log( this.process.version ); } ); separator(); const that = this; const fatArrow = () => log( this === that ); fatArrow(); hub.add( () => { console.log( this === that ); } ); const lexicalBound = () => { console.log( this === that ); }; hub.add( lexicalBound ); const API = { users: { get() { const lexical = () => { log( this === API.users ); }; lexical(); } } }; API.users.get(); separator(); } { // Explicit Binding function sayMyName() { log( this.name ); } sayMyName.call( { name: 'Harry' } ); const sayMyNameFat = () => log( this.name ); // Once a stiff, always a stiff: sayMyNameFat.call( { name: 'Harry' } ); sayMyName.apply( { name: 'Harry' } ); sayMyName.bind( { name: 'Harry' } )(); separator(); } { // Constructor Binding function Wizard( props ) { this.name = props.name; this.kind = props.kind; } const dumbeldore = new Wizard( { name: 'Wulfric Percivus Albus Bryan Dumbeldore', kind: 'Mage' } ); log( dumbeldore.kind ); function Khajit( props ) { return { name: props.name, kind: props.kind } }; const ahkari = new Khajit( { name: 'Ahkari', kind: 'Merchant' } ) log( ahkari.name ); } // ## Lessons to Learn // // In JavaScript, `this` might mean different things depending on when you call the function, // how you bind to the function, and whether you are using a fat arrow. // However, `this` is nothing to be afraid of. // // As long as you know the following key points, you’re all set: // // * Fat arrow functions are “always” lexically bound, // // * And `this` refers to the object that the function is attached to // at the time of invocation, // // * And you can dynamically bind a context to `this` using // * `Function.prototype.bind`, // * `Function.prototype.call`, // * and `Function.prototype.apply`