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!
189 lines (148 loc) • 7.17 kB
JavaScript
/*
* 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 check = util.check;
const checkInverse = util.checkInverse;
const separator = util.separator;
const log = console.log;
const getPrototypeOf = Object.getPrototypeOf;
separator();
const Tool = require( './tool' );
const Hammer = require( './hammer' );
const Nail = require( './nail' );
/**
* This is kind-of equivalent to…
*
* 1. run the constructor function `Hammer`.
* 2. And exec `hammer.__proto__ = Hammer.prototype`
*
* It logs “A sledgehammer is hitting Nine Inch Nails, 10 times!”.
*/
const hammer = new Hammer( 'sledge' );
const nail = new Nail( 'Nine Inch' );
log( 'hammer.hit(10, nail);' );
hammer.hit( 10, nail );
/*
┌───────────────────┐
│ null │
└───────────────────┘
▲
│
{{PROTOTYPE}}
│
┌──────────────────┐
┌─────────▶│ Object.prototype │◀─┐
│ ├──────────────────┤ │
│ │ Object │ │
│ └──────────────────┘ │
│ │ │
{{PROTOTYPE}} │ │
│ │ │
┌──────────────────┐ │ {{PROTOTYPE}}
┌──▶│ Tool.prototype │ │ │
│ ├──────────────────┤ {{PROTOTYPE}} │
│ │ Tool │ │ │
│ └──────────────────┘ │ │
│ │ │
{{PROTOTYPE}} │ │
│ ▼ │
┌───────────────────┐ ┌──────────────────┐ │
│ new Tool() │ ┌─▶│Function.prototype│──┘
└───────────────────┘ │ ├──────────────────┤
▲ │ │ Function │
║ │ └──────────────────┘
┌──────────────────┐ │ │
┌──▶│ Hammer.prototype │ {{PROTOTYPE}} │
│ ├──────────────────┤ └────────────┘
│ │ Hammer │
│ └──────────────────┘
│
{{PROTOTYPE}}
│
┌───────────────────────┐
│ new Hammer('sledge') │
└───────────────────────┘
*/
separator();
log( 'Calling functions of hammer:' );
hammer.protoFunction();
hammer.memberFunction();
separator();
log( 'Calling functions of nail:' );
// __proto__
nail.protoFunction();
nail.memberFunction();
separator();
checkInverse(
getPrototypeOf( hammer ).hasOwnProperty( 'protoFunction' ),
'`hammer`’s immediate {{PROTOTYPE}} does not have a `protoFunction`.'
);
check(
getPrototypeOf( getPrototypeOf( hammer ) ).hasOwnProperty( 'protoFunction' ),
'`hammer`’s second-level {{PROTOTYPE}} has a `protoFunction`.'
);
check(
getPrototypeOf( getPrototypeOf( hammer ) ) === Tool.prototype,
'… and that {{PROTOTYPE}} is `Tool.prototype`.'
);
check( hammer instanceof Hammer, '`hammer` is a `Hammer`.' );
check( hammer instanceof Tool, '`hammer` is a `Tool`.' );
check( hammer instanceof Object, '`hammer` is an `Object`.' );
separator();
log( 'Everything is an object' );
log( false.toString() );
log( [1, 2, 3].toString() );
function bazinga() {}
bazinga.bar = 42;
log( bazinga.bar );
log( ( 2 ).toString() );
const hash = {};
log( hash );
const anotherHash = { top: 44, left: 22, zIndex: 100, name: 'kittens', origin: 399, '124': 25 };
log( anotherHash['124'] );
const collection = [ 1, 'alabama' ];
// The keys of an array are of type “string”.
for ( let key in collection ) {
log( collection[ key ], key, typeof key );
}
separator();
// Same is true for objects.
for ( let key in anotherHash ) {
log( anotherHash[ key ], key, typeof key );
}
separator();
// You can use the `delete` operator to remove properties from a hash.
delete anotherHash.top;
log( anotherHash );
separator();
// ## Lessons to Learn
//
// First things first: JavaScript is NOT Java.
//
// Although inheritance looks cool from the outside, there are much better
// constructs in JavaScript that you can replace with inheritance.
//
// Consider using “modules” and “composition” instead of “classes” and “inheritance”.
//
// That is, prefer functional composition over inheritance whenever you can.
//
// This does not mean inheritance is useless. It is just don’t try to put a classical inheritance
// model on top of a runtime that is designed for prototypal inheritance.
//
// When you find yourself thinking in object hierarchies and subclasses, think again and
// more often than not you can come up with a simpler solution that uses functional composition.