Jeremy Troy Suchanski
Web Frontend Development II
Gary James
April 20, 2022
L02 Reading Notes
Master Mobile UX (Notes)
“If you design for the smallest, least powerful device first,
then you will focus on the content, and your core functionality. That
leads to simple, beautiful apps. If you do it the other way around,
it’ll be like trying to put a marshmallow into a piggybank, which
is neither simple nor beautiful.” Joel Marsh – the Hipper
Element
Design paradigm was design for desktops (which reach its peak in 30
years in 2011)
- 1 maybe 2 available per household
- Replaced every 4 – 5 years
-
Sales have been declining since 2011 & resulting in availability
being way down (was 5 -7 to choose from & now 1 possibly 2)
2007 iPhone was introduced by Steve Jobs, saw a rise in 2 years, 2009
and the by 2011 mobile usage started to skyrocket & after 2011 it
exploded. This began a design paradigm shift with a huge range of
devices with different screen sizes and resolutions for the
design.
-
2 – 3 devices per person per household
- Replaced every 2 years or so
-
People in tech every 1 year or sooner
-
Mobile web traffic 2013 – 2014 went up 18.6% and passed the 50%
mark
-
Largest % of people walking around have their heads down in their
phone (not laptop)
“The simple guideline is whatever you are doing – do mobile
first,” Eric Schmidt, World Mobile Congress Keynote 2012
-
Start small & scale up: ensures your really concentrating on your
content & your
functionality + things tend to grow from small
to big really well
-
Mobile is not a fad, it’s here to stay. So, new paradigm design
= Mobile First
-
Problem is many people still aren’t listening to this.
-
Responsive doesn’t mean mobile first. Most people do
“Responsive Retrofitting”: taking what you already have
and making it work on mobile because (#1 it’s cheaper &
faster than a ground up rewrite #2 gives users a better experience
than desktop only site). However, it doesn’t address issues like
(#1 screen real estate issues #2 touch interaction issues)
-
Mobile First: full rebuild downsides (#1 time consuming #2
costly #3 like trying to shove a marshmallow into a piggybank)
upsides (#1 provides better experience across many devices #2
addresses constraints on mobile size/bandwidth #3 future friendly
& ready for growth)
“It’s really hard to design products by focus groups. A lot
of times, people don’t know what they want until you show it to
them.” Steve Jobs – Apple
-
Don’t listen to what they say, observe what they are doing
& find a way to fill their needs as simply as possible.
-
Be There: can’t do anything if it’s not there for the
customer.
-
Be Useful: only 9% of users will stay if it doesn’t satisfy their needs,
provide them what they came for as quickly as possible.
-
Be Quick: not just fast loading but functionality too, excessive steps cause
user frustration & abandonment. Make interactions smooth and
seamless so the user doesn’t even notice.
-
Reachability: how a user handles their device when using a mobile device (#1 -
75% rely on their thumbs #2 - 49% use a one-handed grip #3 meaning the
bottom of the screen is easiest to reach). Put key items in easiest to
reach places.
-
Speed Matters: it effects business (examples: #1 Google: ½ second delay =
20% drop in traffic #2 Bing: 2 second delay = 4% drop in revenue #3
Aol: fastest 10% of users stay 50% longer)
To ensure things are loading quickly for our users:
#1 reduce image use throughout our site & apps
#2 use SVG & Webfonts for images = lower bandwidth
#3 optimize and minimize CSS & JS files
#4 GZIP files to remove unnecessary data (compressing files reducing load
time)
-
Networks Matter: not everybody has the latest & greatest (example: #1 2013
global market penetration - 4G subscribers = 1.77% (126 million) #2
– 3G subscribers = 24.55% (1.7 billion)
“The trouble with software is . . . it sucks.” Stewart
Alsop – Venture Capitalist
-
To make things better for everyone:
#1 make sure the most commonly used menu items are located at the
bottom in easiest reachable area. Benefits: (#1 this creates a
perception of speed #2 improved engagement rates #3 increased user
satisfaction)
#2 perception matters make things as obvious as possible (example,
Hamburger menu 3 lines – link: with just word menu = -22.2% less
clicks; 3 line symbol with word menu in outlined box = +5.7% more
clicks; just word menu in outlined box = +20% more clicks)
“[The constraints of Mobile] push you toward more focused
simplified solutions. You can only fit so much on the screen . . .
Mobile is a great forcing function for simplicity.” Luke
Wroblewski – Co-Founder of Polar and Bagcheck
-
Mobile Inputs (Forms): reduce users cognitive load & make them think less (even if
it’s subconsciously)
#1 minimize inputs by only having required inputs/ reducing unnecessary
input lines
#2 break larger forms into sections with a progress indicator –
it’s less overwhelming
#3 enable autocomplete – Benefits (#1 greatly reduces time required
to fill in form #2 reduces errors #3 helps to increase
conversions)
#4 passwords – show passwords by default instead of masking (but
allow users to hide them easily if they need to do so) “Typically,
masking passwords doesn’t even increase security, but it does cost
you business due to log in failures.” -Nielson Norman Group
#5 credit card information – make it as simple & intuitive as
possible, auto advance user through the process & provide simple
visual indicators (space credit card numbers automatically) of
what’s being entered (example: 1 line entry field by Brad
Frost)
#6 keyboard – provide best one for input being entered (when taking
numbers, ensure the number keypad is used on Mobile)
#7 phone numbers – linking phone numbers on your website using an
<a> tag (example: <a href=tel:14035551234>403-555-1234</a>) makes it much easier for people to call
from mobile devices (don’t force a copy & paste)
“End users, not technologies, shape the market. [So] marketers
need to stay abreast not only of technological developments but also of
the way people respond to them.” Matt Haig – Author
-
Mobile Advertising: before you advertise, research
-
Late 90s: little advertising
-
Early 2000s: advertisers started seeing the benefits of marketing to web
users
-
2010 & on: more advertising than actual content on many pages
-
Mobile advertising market spending: 2013: under 25 billion - 2017: under 150 billion
-
Pop up: one of the most detested things on the web
-
Mobile Ad Do’s: #1 make them small and simple (it can go big after being clicked)
#2 video ads are huge today and generally result in higher conversion
rates #3 small window that shows the full add underneath as you
scroll
-
“The fallen state of our Internet is a direct, if unintentional,
consequence of choosing advertising as the default model to support
online content and services.” Ethan Zuckerman – Creator of
the Pop-up ad
-
Stop using Pop-ups and Pop-overs
-
Remember your visitors don’t visit your website to look at
ads: they came for content, so give them what they came for & use
your advertising sparingly
-
Keep ads simple & sleek: ask yourself “what would I personally think of this ad coming
up in an article that I was reading?” Upsettin the user will
surely bring lower conversions.
-
Make it as unobtrusive as possible: content first
Ch12: Object-Oriented Programming in JavaScript (Notes)
Object Oriented Programming (OOP): separating code into objects having
properties & methods
-
3 Main Concepts: #1 encapsulation (keeping all the programming logic inside an
object and making methods available to implement the functionality) #2
polymorphism (various objects sharing the same method, but also having
the ability to override shared methods with a more specific
implementation) #3 inheritance (taking an object that already exists
and inheriting all its properties and methods, plus adding new
properties and methods)
-
Prototype-based language: uses actual objects as the blueprint for creating more objects.
Even though ES6 now supports classes, it still uses this prototypal
inheritance model in the background.
-
Constructor function: The keyword this is used to represent the
object that will be returned by the constructor function. Then create
an instance of the object constructor function using the
new operator. Parenthesis are not required after the object name unless
any arguments need to be provided. It then becomes an
instanceof the object’s constructor
function.
-
Literal syntax: creating an object – (example: const literalObject =
{};)
-
Object constructor function syntax: creating an object – (example: constructedObject = new
Object();)
-
Arrays: it’s recommended to always use literals to create arrays
because if only 1 argument is given, it sets the array’s length
property instead of putting the number as the 1st entry,
and returns an array full of undefined.
-
New (ES6) class declaration syntax: does exactly the same thing as a constructor function. To create an
instance of the Dice class, the new operator
is again used. The ES6 class declarations are preferable to the
constructor function syntax because they are more succinct, easier to
read and all code in a class definition is implicitly in strict mode,
so doesn't need the 'use strict' statement.
Example of creating object with class declaration:
class Dice {
constructor(sides=6) {
this.sides = sides;
}
roll() {
return Math.floor(this.sides *
Math.random() + 1)
}
}
Example of creating an instance of that class declaration
object:
const blueDice = new Dice(20);
-
Constructor Property: returns the constructor function that created it. The constructor
property can be used to instantiate a copy of an object, without
having to reference the actual constructor function or class
declaration directly.
Example:
const greenDice = new redDice.constructor(10);
-
Static Methods: static keyword can be used in class declarations to create static
methods.
Example:
static description() {
return 'A way of choosing random
numbers'
}
Static methods are not available to instances of the class only to the
actual class name.
Example of the method being called:
Dice.description()
-
Prototypal Inheritance Model: So, any properties or methods of a class’s prototype can be
accessed by every object instantiated by that class.
-
The Prototype Property: All classes and constructor functions have a prototype property
that returns an object. Since the prototype is just an object, we can
add new properties & methods by assignment.
Example of new property through the prototype:
Turtle.prototype.weapon = 'Hands';
Example of new method through the prototype:
Turtle.prototype.attack = function(){
return `Feel the power of my ${this.weapon}!`;
}
-
Ways to find out the prototype: #1 via the constructor function’s prototype property
(example: raph.constructor.prototype;) #2 use the
Object.getPrototypeOf() method, which takes the object as a parameter
(example:
Object.getPrototypeOf(raph);) #3 use the non-standard __proto__
property. This is known as dunder proto, which is short for
'double underscore proto' (example: raph.__proto__) It is
not considered part of the official specification, and it’s
recommended that getPrototypeOf() is used instead. The __proto__
property can also be used to set the prototype of an object by
assignment, but its use has been deprecated in favor of the
setPrototypeOf() method. Also the isPrototypeOf() method that returns
a boolean to check if it’s the prototype of an instance.
-
Own Properties and Prototype Properties: Every object has a hasOwnProperty() method that can be used to
check if a method is its own property, or is inherited from the
prototype. The difference between an object's own properties and
prototype properties is prototype properties are shared by every
instance of the Turtle class and it will always be the same
value.
-
Overwriting a Prototype: It is not possible to overwrite the prototype by assigning it to a
new object literal if class declarations are used. It is possible to
do this if constructor functions are used. This is another reason why
it’s recommended to use class declarations instead of
constructor functions.
-
Overwriting Prototype Properties: An object instance can overwrite any properties or methods
inherited from its prototype by simply assigning a new value to them.
These properties will now become an 'own property' of the
instance object. Any own properties will take precedence over the same
prototype property when used in methods.
-
Prototype Should Be Used For: It should be used to define any properties that will remain the
same for every instance of the class. Methods are likely to be the
same for all instances of a constructor, so it's fine to add
methods to the prototype. Never use arrays or objects as a default
value in prototype. This is not a problem if arrays or objects are set
as default values from within the constructor function in the class
declaration.
Any extra methods and properties that need to be augmented to the
class declaration after it’s been defined can be added to the
prototype. These will be added to all instances, even those that
have already been created.
-
Public and Private Methods: (Public) By default, an object’s methods are public in
JavaScript. Methods and properties are said to be public because they
can be queried directly and changed by assignment. The dynamic nature
of the language means that an object’s properties and methods
can be changed after it has been created. Giving users or external
services too much access to properties and methods could be a recipe
for disaster. (Private) Variable scope can be used to keep some
properties and methods private inside of a class declaration. With a
getter & setter function things don't work much differently
than before, except functions are now being used to access and change
the private properties.
-
Inheritance: the prototype is just another object, so it also has its own
prototype, which in turn has its own prototype... and so on, creating
a chain of inheritance. The prototype of the Object constructor
function has a large number of methods that are inherited by all
objects. The reason why the prototype appears as an empty object
literal is because all of its methods are not enumerable.
-
Enumerable Properties: There is a method called propertyIsEnumerable() that every object
has that can be used to check if a property is enumerable. Properties
of objects in JavaScript are said to be enumerable or non-enumerable.
If they aren't enumerable, this means they will not show up when
a for-in loop is used to loop through an object’s properties and
methods. All properties and methods that are created by assignment are
enumerable. Good practice is for all built-in methods to be
non-enumerable, and any user-defined methods to be made enumerable so
user-defined methods are easy to find.
-
Inheritance Using extends: A class can inherit from another class using the extends keyword in
a class declaration. This creates a child class that can access any
properties and call any methods of the parent class through the
keyword super.
Example:
class NinjaTurtle extends Turtle {
constructor(name) {
super(name);
this.weapon = 'hands';
}
attack() { return `Feel the power of my ${this.weapon}!`
}
}
-
Polymorphism: The concept of polymorphism means that different objects can have
the same method, but implement it in different ways. The advantage of
this is that higher-level functions are able to call a single method,
even though it may be implemented in various ways.
-
Primitives (number, string, and boolean): are actually without their own methods. The primitive wrapper
objects Number, String, and Boolean are used in the background to
provide primitive values with methods.
-
Adding Methods to Built-in Objects: It is possible to add more methods to the prototype of
JavaScript’s built-in objects — this practice is known as
monkey-patching, but it’s mostly frowned upon in the JavaScript
community, despite it being an incredibly powerful technique. The
current consensus in the JS community is that this shouldn't be
done, so you should avoid monkey-patching any of the built-in object
constructor prototypes, unless you have a very good reason.
Example of adding a method:
Number.prototype.isEven = function() {
return this%2 === 0;
}
An alternative way to avoid causing problems is to use extends to
subclass a built class and create your own class. It has the advantage
of not interfering with the built-in array class at all. For example,
you could create your own array class by extending the built in array
class, like so:
class myArray extends Array {
constructor(...args){
super(...args);
}
delete(i) {
return this.splice(i,1);
}
}
-
Property Attributes and Descriptors: All object properties have the following attributes stored in a
property descriptor - #1 value (default = undefined) #2 writable
(default = false) #3 enumerable (default = false) #4 configurable
(default = false)
Object.getOwnPropertyDescriptor() method allows us to see the property descriptors
Object.defineProperty() method allows us to add properties to an object. Any attributes left
out will take the default values.
-
Getters and Setters: An object property descriptor can have get() and set() methods
instead of a value attribute. All objects must have one or the other,
they can't have both.
-
Creating Objects from Other Objects: It’s possible to avoid using classes altogether, and create
new objects based on another object that acts as a
'blueprint' or prototype instead. The Object() constructor
function has a method called create that can
be used to create a new object that is an exact copy of the object
that is provided as an argument. We can create an instance of the
object using the Object.create() method.
Example of creating an instance using Object.create() method:
const lois = Object.create(Human);
-
Object-Based Inheritance: One object can also act like a ‘super-class’, and
become the prototype of another object. This will have all the
properties and methods that the first object has, but with some
extras.
-
Object Prototype Chain: Creating objects from objects will create a prototype chain.
Every time a new object is created using the Object.create() method,
the new object inherits all the properties and methods from the parent
object, which becomes the new object’s prototype. (The instanceof
operator will not work when objects have been created this way. It only
works when using constructor functions to create objects.)
-
Mixins: A mixin is a way of adding properties and methods of some objects
to another object without using inheritance. It allows more complex
objects to be created by ‘mixing’ basic objects
together.
Object.assign() method provides the basic mixin functionality. This will assign to the
object provided as the first argument all of the properties from any
objects provided as further arguments. Issue = (If any of the properties
being mixed in are arrays or nested objects, only a shallow copy is
made.) To avoid a shallow copy, create your own mixin() function that
will assign all properties of an object to another object as a deep
copy:
function mixin(target,...objects) {
for (const object of objects) {
if(typeof object === 'object') {
for (const key of Object.keys(object))
{
if (typeof object[key] ===
'object') {
target[key] =
Array.isArray(object[key]) ? [] : {};
mixin(target[key],object[key]);
} else {
Object.assign(target,object);
}
}
}
}
return target;
}
-
Shallow copy: are copied by assignment, they are only copied by reference. This
means that another object is not actually created in memory; the new
reference will just point to the old object. Any changes that are made
to either objects will affect both of them.
-
Deep or Hard copy: creates a completely new object that has all the same properties as
the old object. So, when a hard copy is changed, the original remains
the same.
-
Using Mixins to Add Properties: add many properties to an object all at once.
-
Using Mixins to Create a copy() Function: it can be used to make an exact, deep copy of an object:
function copy(target) {
const object =
Object.create(Object.getPrototypeOf(target));
mixin(object,target);
return object;
}
-
Factory Functions: a function that can be used to return an object.
Example of factory function:
function createSuperhuman(...mixins) {
const object = copy(Superhuman);
return mixin(object,...mixins);
}
-
Using the Mixin Function to Add Modular Functionality: sometimes you just want to add properties and methods without
linking the two objects together. The mixin() function lets you
encapsulate properties and methods in an object, then add them to
other objects without the overhead of an inheritance chain being
created.
For inheritance from mixin objects the object has something verses is
something.
-
Chaining Functions: If a method returns this, its methods can be chained together to form a sequence of method
calls that are called one after the other. It helps to make code more
concise by keeping multiple method calls on the same line. (A big
drawback with this technique is that it can make code more difficult
to debug. If an error is reported as occurring on a particular line,
there is no way of knowing which method caused the error, since there
are multiple method calls on that line.)
-
Binding this: used when a function is nested inside another function the value of
this loses its scope, and points to the global
object inside a nested function. Solutions:
#1 Use that = this:
superman.findFriends = function(){
const that = this;
this.friends.forEach(function(friend) {
console.log(`${friend.name} is friends with
${that.name}`);
}
);
}
#2 Use bind(this). The bind() method is a method for all functions and
is used to set the value of this in the function:
superman.findFriends = function() {
this.friends.forEach(function(friend) {
console.log(`${friend.name} is friends with
${this.name}`);
}.bind(this);)
}
#3 Use for-of Instead Of forEach(). ES6 introduced the for-of syntax
for arrays and this does not require a nested function to be used thus
avoiding the problem.
superman.findFriends = function() {
for(const friend of this.friends) {
console.log(`${friend.name} is friends with
${this.name}`);
};
}
#4 Use Arrow Functions. Arrow functions were introduced in ES6, and one
of the advantages of using them is that they don't have their own
this context, so this remains bound to the original object making the
function call.
superman.findFriends = function() {
this.friends.forEach((friend) => {
console.log(`${friend.name} is friends with
${this.name}`);
}
);
}
-
Borrowing Methods from Prototypes: #1 This is done by making a reference to the function that you
want to borrow (that is, without parentheses so that it isn’t
invoked). Then that method can be called on by another object using
the call method. The call() method takes the
object that the function is to be applied to as its first argument,
then the usual arguments come afterwards.
Example of borrowing a method from a prototype:
const fly = superman.fly;
fly.call(batman)
#2 The method can also be borrowed directly from an array
literal.
Example:
[].slice.call(arguments, 1, 3)
#3 An array-like object can effectively be turned into an array using
the slice() method with no arguments. This will return the arguments
object as an array (since the slice() method returns an array):
Example:
const argumentsArray = Array.prototype.slice.call(arguments);
#4 From ES6 onwards the Array.from() method can be used to turn an
array-like object into an array.
Example:
const argumentsArray = Array.from(arguments);
#5 The spread operator can be used to easily turn an array-like object
into an array.
Example:
const argumentsArray = [...arguments];
-
Composition Over Inheritance: This approach advocates creating small objects that describe
single tasks or behaviors and using them as the building blocks for
more complex objects. It sees objects as building blocks that go
together to make other objects rather than classes that are
monolithic structures layered on top of each other. This design
pattern seeks to solve the following problems (The problem Joe
Armstrong describes is that if an object requires a banana() method
that belongs to the Gorilla class, you have to inherit the whole
class to gain access to that method. But as well as the method you
wanted, the object also inherits a lot of other properties and
methods that are not needed, causing it to become unnecessarily
bloated.)
Good practices: #1 If you do decide to use classes,
it’s recommended to make them 'skinny' ― meaning they
don't have too many properties and methods. #2
When creating classes is to keep inheritance chains short. A good rule
of thumb is to only inherit once, keeping the inheritance chain to just
two objects makes unpicking any issues far easier.
#3 If you want to use a particular method from a
class, but it has lots of properties and methods you don't need,
then it would be preferable to just 'borrow' the method
instead. #4 An even better approach would be to
move the banana() method into a separate object then add it as a mixin
to the Gorilla class, and any other objects that required
it.
Object methods, "this" (Notes)
Actions are represented in JavaScript by functions in properties. A
function that is a property of an object is called its method.
The value of this is the object “before dot”, the one used
to call the method. It can be used in any function, even if it’s
not a method of an object. Calling without an object: this == undefined.
In JavaScript this is “free”, its value is evaluated at
call-time and does not depend on where the method was declared, but
rather on what object is “before the dot”.
Arrow functions are special: they don’t have their
“own” this. If we reference this from such a function,
it’s taken from the outer “normal” function.
Ch15: Modern JavaScript (Notes)
-
Libraries: A JavaScript library is a piece of code that provides several
methods that make it easier to achieve common tasks.
A library will abstract functionality into easier-to-use functions
and methods.
-
jQuery: the most popular of all the JavaScript libraries used today. It has
a plugin system that makes it easy to extend and use to build common
web page elements. Query was released in 2006, originally as a DOM
manipulation library. A big advantage of using jQuery is its support
for older browsers, particularly Internet Explorer.
It has become so popular that many online tutorials assume
you’re using jQuery rather than just JavaScript.
The jQuery library uses the $ symbol as a
convenient alias for the the global jQuery object that contains all of
jQuery's methods.
-
Underscore & Lodash: very similar libraries to jQuery of functions that provide
additional functionality to the language. They both provide a large
number of utility functions under the namespace _. It’s worth
considering using one of these libraries in your projects as it will
give you access to a large number of well-tested utility functions
that are often required in projects.
Both of these libraries are very similar. In fact, Lodash started
life as a fork of Underscore.
-
Advantages of Libraries: #1 It will be used by lots of people and thoroughly tested meaning
you can be confident that your code will be as bullet-proof as
possible in many browsers. #2 there will usually be lots of online
documentation and a strong community ready to help out if you become
stuck.
-
Disadvantages of Libraries: #1 You need to include the code for the library as well as your own
code thus increasing the amount of code that needs to be downloaded by
a website, which in some cases can cause performance issues. #2 It
might fail to implement the functionality in the precise way that you
want it to perform. #3 Using a library can also make your code slower
than using plain vanilla JavaScript. (These speed differences can be
barely noticeable.)
-
When to Use a Library: #1 Question whether it’s worth the extra work. #2 Consider
that the popularity of a particular library can be 'here today,
gone tomorrow' #3 if you find that you’re not using
many of the methods a library offers, you should consider using a
lighter alternative that only focuses on solving one problem #4
if you’re only using a handful of methods, maybe avoid
using a library altogether and try using plain old JavaScript. #5 It
should be used to speed up JavaScript development by making it easier
to complete common tasks. #6 A library should not be used because of a
lack of understanding of JavaScript. (Reading a library’s source
code is a great way of learning some powerful JavaScript programming
techniques.)
-
Finding Libraries: There’s a large number of high-quality JavaScript libraries
in this list on Wikipedia
(https://en.wikipedia.org/wiki/List_of_JavaScript_libraries), while
MicroJS (http://microjs.com/) is a high-quality repository of small
JavaScript libraries that focus on specific tasks, and Just
(http://anguscroll.com/just/) is a library of functions that just do
one task without depending on any other functions or libraries.
-
Modular JavaScript: A module is a self-contained piece of code that provides functions
and methods that can then be used in other files and by other
modules.
The code in a module should have a single purpose, and group together
functions with distinct functionality.
Modules also allow a public API to be exposed, while keeping the
implementation hidden away inside the module. All code in modules is
always in strict mode. Variables created in the top-level of a module
can only be accessed within that module. Uses the keyword
export to specify any values or functions that
are to be made available from the module, meaning that not everything
in the module needs to be used. To use parts of a module the keyword
import is used to import into your main
JavaScript file.
(example: import { PI } from './pi.js';)
If there are lots of values and functions that need to be imported,
then everything in a module file can be imported using the wildcard
symbol *.
Default Exports: Refers to a single variable, function or class in a module that can
be imported without having to be explicitly named & is done with
keywords export default.
Having more than one default export will result in a syntax error. For
importing - the big difference with default exports is that you
don't need to use curly braces or make any mention of the value
that is being imported (example: import PI from './pi.js';)
The alias that is assigned to the imported module does not have to match
its name in the actual module, you can change it. (example: import
square function as sq)
Coupling: The coupling of code refers to how dependent certain elements or
modules of code are on each other.
Tightly coupled: If one relies on the other to run. This
often occurs if a piece of code makes hard-coded references to another
piece of code, requiring it to be used.
This will often mean that changes to one piece of code will necessitate
changes in the other.
Loosely coupled: If one piece of code can be easily substituted by another without
affecting the final outcome. This is often achieved by referring to
common methods that are shared by the alternative modules.
Good design: Keep code as loosely coupled as possible.
-
Node.js Modules: uses a slightly different notation called Common JS modules. The
module.exports method is used to make any
functions available to other files. (example: module.exports = x =>
x * x;) To use the module,
use the require() method. (example: const square =
require('./squareFunction');)
-
MVC Frameworks: MVC = Model-View-Controller. It is used in JavaScript code to make
it easier to organize large-scale web applications by separating an
application into three distinct, independent components that interact
with each other. #1 Models (objects that implement the functionality
for creating, reading, updating and deleting (known as CRUD tasks)
specific pieces of information about the application, as well as any
other associated logic and behavior.) #2 Views (provide a visual
representation of the model showing all the relevant information and
provide a way for users to interact with an application, usually via
forms. In a web application, this would be the HTML displayed on a web
page.) #3 Controllers (link models and views together by communicating
between them. They respond to events, which are usually inputs from a
user (entering some data into a form, for example), process the
information, then update the model and view accordingly.) Many
frameworks have emerged that take care of much of the setup code for
you. (examples: #1 Aurelia – a modern framework #2 Angular
– framework by Google #3 Ember – a framework to make
building large web applications easier)
MV*: It is quite common to see the acronym MV* used as a catch-all term to
describe JavaScript frameworks, rather than MVC.
This is because many JavaScript implementations do not strictly follow
the controller pattern. Sometimes controller code is mixed into the
views, and sometimes other patterns are used, such as
Model-View-Presenter (MVP), Model-View-ViewModel (MVVM), and AngularJS,
which calls itself a Model-View-Whatever (MVW) framework.
Persistence: Most web applications will need some form of persistence to save the
information held in the models in order to maintain state. (examples: #1
Web Storage API #2 send a JSON representation of the model to a back-end
database using Ajax whenever a model changes)
Data Binding: the process of linking the model and view together.
One-way data binding is when a change in the model will automatically result in the view
being updated. Two-way data binding is when a
change in the view automatically updates the model.
-
Templates: Many MVC frameworks use templating languages to insert dynamic
data into the page. Templates can be written in HTML or another
language, such as markdown, which compiles into HTML. They can be
whole web pages, but are often just partials — parts of a
page. (Templating languages allow HTML to be separated from the
JavaScript program, making maintenance easier because they’re
no longer tightly coupled.)
The templates are often stored in separate files or inside their
own script tags.
Mechanism for inserting dynamic data into the HTML: #1 placing dynamic code inside curly braces (the 'mustache'
symbol – example: <h1>Hello {{ name }}</h1>) #2
placing dynamic code inside the special <% %> tags (made popular
by Embedded Ruby “ERB” – example: <h1>Hello
<%= name %></h1>)
Popular templating languages: #1
Handlebars #2 Pug #3 EJS #4 Mustache #5 Nunjucks
Web Components: The Polymer Project (https://www.polymer-project.org/) is a JavaScript library that attempts to implement web
components.
‘View’ Libraries: They are worth considering if you find your user interface is
starting to become more complicated or has to react quickly to changes
in data. They deal with just the view layer of MVC.
They have the single goal of making it easier to update the user
interface while also keeping what is displayed synchronized with
underlying data that it’s representing. Most popular two view
libraries: #1 React (developed by Facebook) #2 Vue.js (developed by Evan
You after he worked on AngularJS at Google) Other popular alternatives
that achieve the single goal in a slightly different way: #1 Svelte #2
Inferno #3 Deku #4 Preact #5 Virtual-DOM #6 Moon
Virtual DOM: React and Vue.js both use the concept to speed up the process of
updating HTML pages. Instead of directly changing the DOM a virtual DOM
is updated in memory. Reconciliation: It makes rendering web pages extremely fast. The real DOM is only
updated when it needs to be & is done by comparing differences
between the virtual DOM and actual DOM & only updating those
elements that have actually changed.
Components: concept to represent visual elements. You can create multiple
components that can then be reused in other projects as well as being
combined to make larger components. Each component is entirely
self-contained, with all the HTML, CSS and JavaScript being defined
inside the component itself.
-
Package Managers: allow developers to download modules from a central repository.
They make it easy to install, upgrade and remove any packages that
are used in a project and can also help with dependency
management..
Package: is a directory with one or more files of code, as well as a
package.json file that contains information about the code in the
package.
-
npm: Node Package Manager was developed soon after Node.js was
introduced to allow JavaScript code to be shared by developers. It
has since grown into
the largest repository of code libraries available. It allows
you to install JavaScript packages onto your machine. Some packages
rely on other packages, so npm acts as a dependency manager (if you
use npm to install a package, it will also install all the packages
that the original package depends on as well). The npm repository is
huge – it contains almost
half a million different packages.
Searching for Packages: use the search command. (example: npm search test - returns a list of
packages) You can also search for a package on the npm website
(https://www.npmjs.com/).
npm init command: used when you start a project. It walks you through creating a
package.json file.
Installing Packages Locally: the install command is used. Adding the --save flag will ensure the
package.json file is updated with the relevant information about the
package.
Example: npm install --save lodash
devDependency: packages that aren't required by the application itself but are
used in development to complete tasks to do with the application
(example: running tests or transpiling the code). Any packages installed
as a devDependency will not be packaged in the final build of an
application that is deployed.
Example: npm install --save-dev jest
Installing a specific version: place the @ symbol after the package name, followed by the version
you require. (It is usually best to just install the latest version of a
package, although there may be times when you need to install a specific
version of a package so it’s compatible with other
packages.)
Semantic Versioning: the first number refers to the major version number, the second is
the minor version number, and the third number is for patches.
Example: npm install --save-dev jest@18.1.0
The package.json File: create a package.json file inside a directory by running the
npm init command. It manages any packages that
are installed locally. It keeps track on which packages are installed,
and what dependencies they rely on. It also allows you to specify
specific versions of packages to use. They require: #1
“name” (all in lowercase and containing no spaces) #2
“version” (uses semantic versioning of the form
major.minor.patch)
By-passing the questions on install of a package.json File: use the --yes or -y flag
Example: npm install –yes
Setting defaults: use npm set command:
Example: npm set init.author.email "daz@sitepoint.com"
npm set init.author.name "DAZ"
npm set init.license "MIT"
README: Most projects will have a file in the root directory called
'README'. This files serves as the application's
documentation and contains information about it. If you leave the
description field blank, then npm will use the first line of the README
file as the description.
Installing all the packages that are required to run the
application: the package.json file is that it contains all the information about a
project's dependencies. So, from inside the root directory of the
project simply entering the npm install command
will download and install all the necessary packages, as well as any
dependencies.
Installing Globally: There are some cases, when it makes sense to install a package
globally. This is usually when the package is to be used on a
system-wide basis, rather than just for a specific project. Then
they’re available system-wide from any directory on your machine.
(it isn't usually recommended, as the package files are not saved
with the project [they are installed in the system folders on your
machine] and there will be no reference to the package as a dependency
in the package.json file.)To install a package globally, the
global flag needs to be added to the install
command (example: npm install --global lodash)
Installing Globally & Locally: You might want it available on your system so you can have quick
access to the library when you’re experimenting with code in the
Node REPL, but you might also want it as a specific dependency in a web
application you build. There is nothing wrong with this, it just means
the files exist in two (or more) different places on your machine.
Permissions:
You need to be careful about permissions when installing packages
globally.
When you install globally you are sometimes required to install the
package into a system directory that you don't have permission to
access.
Three ways to fix this problem are explained on the npm website.
Listing Installed Packages: You can list all the packages that have been installed locally using
the list command. (example: npm list)
If you only want to see the packages that you have installed directly,
you can use the depth flag, with a value of 0. (example: npm list
--depth=0) You can find out which packages have been installed globally
by adding the --global or -g flag. (example: npm list
–global)
Updating A Package: You can find out if any of the packages you have installed have been
updated by running the command outdated. (examples: #1 locally - npm outdated #2 globally - npm outdated
-g)
This will display a list of any packages that are listed in
package.json and have a more recent version available than what’s
currently installed.
npm makes it easy to update a package to the latest version using the
update command. (examples: #1 jest package - npm
update jest #2 all packages - npm update #3 globally - npm update
--global)
Uninstalling Packages: You can use npm to uninstall a package using the
uninstall command (example: npm uninstall lodash)
To remove it from the dependencies in package.json, you will need to
use the save flag (example: npm uninstall --save
lodash)
If it was installed as a devDependency, you will need to add the --save-dev
flag to remove it from the package.json file (example: npm uninstall
--save-dev jest)
Global packages can be uninstalled by adding the --global or -g to the
uninstall command (example: npm uninstall
--global lodash)
npm Command Aliases: #1 install = i #2 uninstall = un #3 update = up #4 list = ls
-
Yarn: it has emerged recently as a popular alternative to npm.
Yarn generally installs packages much faster than npm due to the fact
that it caches packages. It has a slightly different set of commands,
but generally works in the same way as npm.
-
Content delivery networks (CDNs): systems of distributed servers that can deliver web resources, such
as JavaScript, CSS or image files to a user based on their geographic
location.
It will be cached, and can then be used again by other sites without
the need for another network request. (unpkg is a global content
delivery network or CDN)
-
Deploying JavaScript: combine all the scripts into a single minified and compressed
file.
This file is often named 'bundle.min.js' to signify that
it’s a number of files bundled together and has also been
minified.
The optimal position for the <script> tag is right at the end
of the page, just before the closing <body> tag.
-
Transpiling Code: A code transpiler allows you to write your code in the latest
version of ECMAScript, using all the latest features, then convert it
into an older variant of JavaScript that is compatible with most
browsers.
The most popular transpiler
for converting the most up-to-date version of ECMAScript into an
older flavor of JavaScript.: #1 Babel. Transpilers that allow you to
write in a different language like (#1 CoffeeScript #2 TypeScript #3
Dart) then compile it into JavaScript.
-
Minification: the process of removing any unnecessary characters from your code
to reduce the file size. This includes all comments, whitespace, and
other characters that are superfluous. They can also change variable
and function names to single letters (called obfuscation & employ
optimizations to make the code run faster. This can have a major
effect on the overall size of your files, making them download and run
faster. Popular minifier tools: #1 YUI Compressor #2 Google’s
Closure #3 UglifyJS
Good practice: use well-commented and descriptive code in development and minified
code in production.
-
File-compression tool: compress files for the server,
making them much quicker to download. (example: gzip)
-
Folder Structure: You can organize your files in any way you like, but there are some
conventions that are often used for directory names.
Root Files: index.html
is traditionally the page that a web browser will load by default. For
small projects
it is usually okay to put all the JavaScript into a single file in the
root directory. The file is usually called #1 ‘main.js’ #2
'index.js' #3 'app.js' #4 something similar.
As a project gets bigger,
you might want to move all of your JavaScript into a separate folder,
called #1 'js' #2 'scripts' #3 something similar. In
a similar way, it is customary to have a single CSS file in the root
directory or keep multiple CSS files saved in a folder called #1
'CSS' #2 'stylesheets' #3 something similar.
src folder: Code that needs to be transpiled is often placed inside a folder
called src (short for 'source'). The transpiler can then
compile the JavaScript code into a single file in a different location
(usually this is either the root directory or the 'dist'
folder).
dist folder: The output of any transpiled code from the src folder is usually
placed inside a folder called 'dist' (short for
'distribution').
Even though there might be many different files inside the src folder,
the result of transpilation means there is usually only a single
JavaScript file inside the 'dist' folder, usually called
budle.js or 'bundle.min.js' if it has also been
minified.
lib folder: Any modules are usually stored in a folder called lib (short for
'library') that is usually placed inside the src folder.
Third-party libraries are often placed inside a folder called vendor,
although they are sometimes also placed inside the lib folder.
node_modules: Any third-party code installed using npm will be installed into this
directory/folder.
Modules: For only a small number of modules, you can just keep them all in the
root of the lib directory, but as the size of
your application grows, you might need to start thinking about how to
organize the modules into separate folders.
Organization By Type: has folders for the different types of file that will be used in your
project such as Javascript, CSS, Images and Tests.
Example:
-
src
-
dist
-
package.json
-
node_modules
-
README
Modular Organization: groups files by feature, so all the files associated with a certain
feature together in a single folder. Advantages: #1 keeps all the code
related to that particular feature all in one place #2 modules can grow
to incorporate their own file structure and sub-directories as required
#3 allows developers to work on a specific feature without affecting
another feature (particularly useful when working in teams) #4 modular
nature of this approach makes it easy to switch one feature for another,
without affecting the rest of the project #5 each module is
self-contained, making them easy to test.
Example:
-
src
-
index.html
-
lib
-
app
-
app.js
-
app.css
-
app.test.js
-
moduleA.html
-
moduleA.js
-
moduleA.css
-
moduleA.test.js
-
moduleB.html
-
moduleB.js
-
moduleB.css
-
moduleB.test.js
-
dist
-
package.json
-
node_modules
-
README
Start Small: Start small with
just the root files: index.html, main.js and main.css. Then expand as
the project grows.
-
Webpack: a module bundler that takes all the JavaScript files used in your
project and bundles them altogether in one file.
Loaders: a concept Webpack uses, which allows you to perform tasks such as #1
Transpiling code #2 Minifying code #3 Linting code #4 Testing code #5
Compiling CSS preprocessor files (such as Sass, Less or Stylus) into
standard CSS files. #6 Compile multiple CSS and image files into a
single destination folder.
Webpack Example:
#1 create a new folder called “webpack-example”, then
navigate to that folder in the terminal and create a package.json file
with the command (npm init -y)
#2 use npm to install Webpack
as part of the development process with the command (npm install
--save-dev webpack)
#3 create a simple HTML file called webpack.html that includes the
following code:
<!doctype html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<title>Webpack Example</title>
</head>
<body>
<script
src='bundle.js'></script>
</body>
</html>
#4 create a JavaScript file called main.js that contains the following
code:
import _ from 'lodash';
console.log(_.now());
#5 On its own, this code won't work, but we can use Webpack to
sort out importing the Lodash library from the 'node_modules'
directory. To do this, we simply need to run the following command in
the terminal:
./node_modules/.bin/webpack main.js bundle.js
The first argument is the file that contains our code ('main.js),
and the second argument is the file that we want the output to be
written to (bundle.js).
#6 To make things simpler, going forward, we can create a webpack
configuration file called 'webpack.config.js'.
This is actually just a standard JavaScript file and should be saved
in the root of the directory
and contain the following code:
module.exports = {
entry: './main.js',
output: {
filename:
'bundle.js',
path: __dirname
}
};
#7 This can be run using the following line of code in the
terminal:
./node_modules/.bin/webpack
#8 use npm to simplify this process by updating the "scripts"
property in your package.json file to the following:
"scripts": {
"test": "echo \"Error: no test
specified\" && exit 1",
"build": "webpack"
}
#8 Now you can run Webpack using the following command:
npm run build