This is a very brief introduction to programming for the web, focused on the “front end”. We’ll talk about
First, some resources to go more in depth after this primer.
You don’t need much to start
http-server
(installed with npm
)python3 -m http.server
For more serious work, you’ll need
node
the stand-alone JavaScript runtimenpm
the package manager included with node.jsA website is separated into 3 parts:
The HTML/CSS are used to create the DOM, while JavaScript interacts with it.
We can inspect the DOM using Developer tools in any browser, by menu, or right-click > inspect.
Things to notice:
document
)offsetHeight
)HyperText Markup Language
<tag-name attribute="value">innerHTML</tag-name>
<tag-name attribute="value" />
<!-- comments -->
Things to note in this document:
<head>
contains metadata about the page, including
<body>
contains the actual pagesection
in body
, and h1
in section
and text in h1
like the DOMh1
is a headingp
is a paragraphul
is an unordered list with li
elements inside of ita
is an “anchor” (a link, or a marker in the current document)nav
is a navigation bar/menuclass
or id
red-box
<div class="hidden slide">
<nav id='main-nav'></nav>
href
, alt
, or anything elseWriting raw HTML with all the opening and closing tags can be be quite tedious.
so a lot of developers use Markdown to write content. The text in .md
format can be passed through a parser and compiled into HTML. This can be done with most markup languages.
Even with the content written in a nicer language, the boiler-plate and layout is often repetitive, so templating languages like mustache are popular.
Cascading style sheets describe the appearance of elements.
“Cascading” refers to the way rules/declarations are applied:
Syntax:
selector { property: value; ... }
The whole statement is a “rule”. Each property: value;
pair is a “declaration”.
Describe the elements in the DOM. There are,
a
, div
, p
, section
, asdf
, ….class-name
, a.class1.class2
#
#main-nav
, #start-button
Selectors can also be combined to describe where an element falls in the DOM hierarchy.
>
is an immediate descendent+
~
div.red-box
vs. div .red-box
)I read these from right to left: the selected element matches the rightmost selector, the rest describes its place in the DOM Example:
section > p + h1 {
color: blue;
}
Selects the top-level heading directly adjacent to a paragraph which is the child of a section.
[attr]
has the attribute attr
,[attr=val]
has the attribute attr
with the value val
,[attr~=val]
has the attribute attr
containing val
in a space-separated list.div:hover
affects a div if the mouse is hovering over ith1:first-child
only selects h1
if it is the first child tooh1:first-of-type
selects the first h1
of its siblingsp:nth-of-type(2n+1)
selects all odd paragraphs::
[href^=http]::after { content: '⤴'; }
property: value;
)These describe the way an element is drawn. Different elements can have their own special properties, but no error will be given if a property doesn’t apply.
Common properties include:
color
: values can be like red
, #f00
, #fa0000
, rgba(255, 0, 0, .5)
background
: as abovedisplay
: block
, inline
, block-inline
, flex
, etc.margin-top
: a length 0em
, 0.3rem
, 4px
, 1%
visible
You’ll have to look up a reference for all the possibilities.
It’s worth mentioning the box model for element sizing/spacing.
margin
’s are the spaces between objectsborder
’s are the size of the drawn borderpadding
is the space between the border and the contentwidth
and height
describe the size of the element
box-sizing: content-box
is default where width/height does not include margins, borders or padding.box-sizing: border-box
makes width/height include padding and borders (easier math in many cases)Sites with more complicated layout will often use
* { box-sizing: content-box; }
,
to make the sizes consistent regardless of borders and padding.
CSS lacks some features that can be very useful/convenient, like
This is good for browser performance, but a pain for developers. There are lots of pre-processors for CSS that add all these features and more
JavaScript is the scripting language supported by modern browsers. It’s specified as ECMAScript, the latest standard being ECMAScript 2015 (aka ES6). All modern browsers support ES5.1, and most of ES6
JavaScript is a scripting language with
ES6 adds
"""
in Python, but with ${expressions}
)let
instead of var
There are primitive types:
Then there are notably,
Variables can be declared with var
or let
. You’ll probably use var
most.
var x = 1;
var s = 'hello world';
var u; // undefined
var f = function() {
console.log('function f called');
};
var o = {name: 'some object', callMe: f, 1: 'one'}
let
is for block-scope which is good for loop variables.
for (let i=0; i<10; i++) {
console.log(i)
}
console.log(i) // error
Can be anonymous:
(function() {console.log('hello world')})()
Named throughout current scope (“hoisted”):
foo() // logs "bar"
function foo() {
console.log('bar');
}
Attached to a variable:
bar() // error
var bar = function () {
console.log('foo')
}
bar() // logs "foo"
The scope describes what variables are accessible and their names. In JavaScript, the scope of a variable defined with var
is the current function. JS also has a lexical scope, so functions inherit the scope of their parents.
// example of isolating scope with a function
var x = 10;
(function () {
var x = document.createElement('section');
x.innerHTML = '<h1>From Demo</h1>';
x.className = 'slide shown';
document.getElementById('content').appendChild(x);
})()
console.log(x);
Variables can become private.
// Example of a closure
var counter = (function() {
var i = 0;
return function () {
return i++;
};
})();
console.log(counter())
console.log(counter())
We can make factories
// Bigger example of a closure
var countBy = function(inc) {
var count = -inc;
return function() {
count += inc;
return count;
}
};
c = countBy(6);
d = countBy(2);
console.log(c())
console.log(d())
console.log(c())
console.log(d())
Object properties can be accessed with either .
or []
.
o.name;
o['callMe']();
o[1]
And properties can always be added/reassigned
f.name = 'asdf';
f.obj = o;
Object properties that are methods have a special variable this
added to scope.
var f = function (arg1, arg2) {
arg2 = arg2 || 'earth';
console.log(`called by ${this.name}`)
console.log('object', this);
console.log('arg1', arg1);
console.log('arg2', arg2);
}
var foo = {name: 'bar', method: f}
The following are equivalent
foo.method('hi');
f.bind(foo)('hi');
f.apply(foo, ['hi');
f.call(foo, 'hi');
The if/else if/else statement is same as in C
if (condition) {
codeBlock;
}
else if (condition2)
statement;
else {
codeBlock;
}
There is also switch..case
, which we’ll see in this app’s code.
There are two equalities in JavaScript
==
or !=
perform casting when comparing values so 12 == true
is true
===
or !==
don’t cast, so 1 === true
is `falseCasting also happens for <
, <=
, etc.
A logical “not” is the operator !
, which does cast to booleans. So you can do !!undefined
to get true
.
There are while
, do...while
, and for
loops. All follow classic C syntax, but there are special forms of for
loops
var shoppingList = ['banana', 'apple', 'bread'];
shoppingList.title = 'My Groceries';
/* This will print the object's properties */
for (let i in shoppingList)
console.log(i);
/* and this prints the elements in the _iterable_ object */
for (let x of shoppingList)
console.log(x);
/* for arrays you could still do */
for (let i=0; i<shoppingList.length; i++) {
console.log(shoppingList[i]);
}
The for...of
syntax behaves most like Python’s for...in
loop.
Go over the code for this “app”.
Note:
Element.getElementById
and .getElementsByClassName
classList.add/remove()
JavaScript is prototype-based. This is different from class-based, but has similar functionality.
var obj = new MyClass();
MyClass.prototype = {foo: function() { return 'foo';}, bar: 'bar'}
ownProperty
function MyClass() { this.asdf = function() {return this.bar;}
obj.toString()
would go to Object.prototype.toString.apply(obj)
function A() {
this.varA = 'a';
}
function B() {
A.call(this);
this.varB = 'b';
}
A.prototype = { foo: 1, bar: function(x) { return this.foo + 1;}};
B.prototype = Object.create(A.prototype);
B.prototype.foo = 3;
a = new A();
b = new B();
a.bar(1);
b.bar(1);
B.prototype.foo = -1;
b.bar(1);
Just a syntactic wrapping of what we covered before.
class C extends B {
constructor(c) {
super();
this.foo = -1;
this.varC = c;
};
get foo() {
return this._foo;
};
set foo(b) {
this._foo = b;
};
}
The current state of modules is a bit complicated because of many players coming up with many solutions. See AMD, CommonJS, RequireJS, Browserify, or home-spun versions.
I won’t be covering those here, because it is so complicated.
However, after all of that, a module is often accessible as an object with the supplied functions as properties. (e.g. marked
and hljs
in the current site).
Many libraries can be installed with npm
.