JavaScript is a programming language, like C, Java, Python, etc.
All programming language are basically ways to describe some behaviour to the computer: calculations it should do, things that should happen on screen, etc. Different programming languages have strengths and weaknesses.
The big strength of JavaScript is that it's built into the web browser already and can operate inside a web page.
Some kinds of behaviour
we will be able to have in a web page: respond to an event from the user (clicking, typing, etc); modify the current page (add/remove/change content).
Contrasting with HTML and CSS: both of these are languages
, but not programming languages
because their result isn't a program.
Our JavaScript code will run within a web page. Like with CSS, we start with an HTML page and add in some JavaScript.
The JavaScript code will go in a separate (text) file named something.js
.
To attach a JavaScript file to HTML, add a <script>
element in the <head>
like this:
<script src="first-code.js"></script>
We will always close the <script>
tag immediately: no contents.
Then in a file first-code.js
we can write JavaScript code. For now, we can try this:
alert('Hello world!')
If we reload the HTML page, we should see the alert box pop up.
alert('Hello world!')
When the HTML page is loaded, the JavaScript code is executed.
In this code, alert
is a function that is built into the language.
The stuff in the (…)
are the function's arguments (could be none for some functions).
alert('Hello world!')
This argument ('Hello world!'
) is a string: a sequence of characters in quotes.
Calling it like this will run it, and it does whatever it does.
This line of code is a statement: one instruction in the language
That code runs when the page loads: that isn't usually what we want. We want to respond to something the user did. In order to do that, we must…
event.
In our JavaScript file, we can turn that line of code into a function named say_hello
:
say_hello = function() { alert('Hello world!') }
This code doesn't do anything when the page loads, except define say_hello
, which we can use later.
Then we can modify an element to attach an event on that element, so the function is called when the user does something:
<p onclick="say_hello()">This is a paragraph.</p>
Result: clicking on that paragraph calls our say_hello
function, which itself calls alert. We will see another (more flexible) way to hook up events later.
The previous JavaScript code example started:
say_hello = …
A statement like this creates a variable named say_hello
. It is a variable assignment statement.
A variable in a program is a way to store some information.
In that code, what we're storing is a new function. It will be put in the computer's memory and can be referred to by name later.
The goal: store stuff that we need to work with later.
Variables can also store other kinds of information, like numbers.
another_example = function() { count = 54; count = count + 1; alert(count); }
This function will pop up and show the number 55. It sets count
to 54; changes it to 54+1 = 55, and then calls alert
with that value.
another_example = function() { count = 54; count = count + 1; alert(count); }
Things to note…
Variables can be assigned many times, and the value being stored changes (varies).
Variables can store different kinds of information. Here, another_example
is holding a function, count
contains a number.
another_example = function() { count = 54; count = count + 1; alert(count); }
Calling the variable by name uses its value. In the second statement, count + 1
uses count
's current value (54) where it is mentioned, so the calculation evaluates to 55.
Giving the variable to alert()
uses the value at that point in the execution (55).
When a variable is holding a function, we can call it by putting parentheses after its name, like:
another_example()
Or, using a built-in function,
alert('Hello world!')
(Call/​run/​execute all mean do the stuff in the function
.)
There are several different kinds of information that can be stored in JavaScript variables, or elsewhere in calculations.
Each is a type.
Numbers are numeric values that can be used in calculations. Each of these statements puts a number in a variable:
count = 17 higher_count = count + 1 double_count = count * 2 length = 7.32
Numbers can be integers or real numbers (technically floating point numbers, but close enough).
Basic arithmetic operations (+
, -
, *
, /
) work as you probably expect.
Strings are sequences of characters representing text. e.g. in the function call alert('Hello world!')
, the argument ('Hello world!'
) is a string.
Strings can be stored in variables:
message = 'Hello world!' course = "CMPT 165"
We can use a variable anywhere we need its value, like
message = 'Hello world!' alert(message)
A literal string can be wrapped in either single or double quotes in JavaScript. Strings can be joined with +
:
message = 'Hello' + ' ' + 'world!' alert(message)
Functions, like our say_hello
and another_example
, are stored in variables that hold the function definition.
We have seen the alert
function, which is pre-defined as part of the language.
In JavaScript, objects are a container for other things: numbers, strings, functions, and other objects.
We will get many kinds of objects given to us by the language. We will be using them a lot, but not directly creating them ourselves.
The .
operator is used to get something out of an object. If we have an object a
that contains b
, we can get it by asking for a.b
.
There are a few more types of values in JavaScript, but those will do for now.
What you can do with values (either in a variable or a literal value) depends on its type.
e.g. doing a - b
only really makes sense for numbers, and the alert
built-in function expects its argument to be a string.
We defined a function named say_hello
already:
say_hello = function() { alert('Hello world!') }
What this code does:
say_hello
: we're storing functions in variables just like any other type of value.say_hello = function() { alert('Hello world!') }
{…}
, what happens when we call it) contains one statment which is a call to alert
.As we go on, the body of the functions will expand, and we will learn how to write functions that take arguments.
As we start programming, we'll find some tasks that everybody has to solve with JavaScript and web pages. (The same thing happens with any language and problem domain.)
We shouldn't have every programmer solve all of the same common problems, but there is a limit to the number functions built into the language to help us.
The solution: identify the common problems, solve them once, and package up the code for others to use.
People have done this. The result is code libraries. These are generally collections of functions (any other stuff) that are useful for particular problems.
For any library, we could have written those functions ourselves, but probably didn't want to (or didn't yet know how).
Modern programming is full of libraries: many problems that have been solved so you don't have to. The tradeoff is figuring out how to use them.
We saw a similar concept in CSS with the reset stylesheet, and Normalize.css: these took some common CSS problems and solved them once in a way others could use.
The jQuery library is very common in JavaScript programming. We will be using it too.
First, load the library as part of the page, before your own JavaScript. After that, we can use it in our code.
<script src="https://cmpt165.csil.sfu.ca/js/jquery-3.4.1.js"></script> <script src="our-code.js"></script>
The jQuery library gives us a function jQuery
that we will use to access all of its functionality.
The jQuery
function always gives us back a jQuery object that contains a bunch of magic and lets us be much more expressive in our JavaScript code.
In particular, we won't have to modify the HTML (by adding onclick
etc) to connect our behaviour to the page. That way, we can keep ideas separated: content in HTML, behaviour in JavaScript.
We can easily select elements on the page with CSS-like selectors.
e.g. to refer to every <p>
on the page: jQuery('p')
.
The function call jQuery('p')
gives us back a jQuery object that (somehow) represents every <p>
on the page.
That jQuery object contains a click
function that we can use to say what should happen when they are clicked:
jQuery('p').click(say_hello)
That is: when the paragraph is clicked, call say_hello()
.
We have to get this line of code to run. We will wrap it in a function that will set everything up for us:
setup = function() { jQuery('p').click(say_hello) }
Finally, we can have jQuery call this function once the page is ready to have everything configured:
setup = function() { jQuery('p').click(say_hello) } jQuery(document).ready(setup)
By ready
, we mean the page is actually downloaded and drawn on the screen. Then jQuery calls setup()
to do the rest of the work.
This code: for all paragraphs, when one is clicked, call say_hello()
.
jQuery('p').click(say_hello)
This code: for the document overall, when it's ready
, call setup()
.
jQuery(document).ready(setup)
The document
variable is built-in and created automatically by the browser.
Our complete JavaScript file:
say_hello = function() { alert('Hello world!') } setup = function() { jQuery('p').click(say_hello) } jQuery(document).ready(setup)
And the HTML works with no changes (except loading the JavaScript):
<script src="https://cmpt165.csil.sfu.ca/js/jquery-3.4.1.js"></script> <script src="our-code.js"></script>
⋮
<p>This is a paragraph.</p>
You can find elements on the page with jQuery selectors. In the last example jQuery('p')
has the selector 'p'
.
The selector is just a JavaScript string, and it's the same as the CSS selector for all paragraphs.
jQuery selectors are designed to work like CSS selectors, since web developers already know them.
We can also do other CSS-selector things. Maybe most importantly, by id
:
jQuery('#clickme').…
We know id
values are unique, so this is a good way to target a specific element.
e.g. we can make a specific element change itself when clicked: (Complete .js
file.)
change_it = function() { jQuery('#changing').html('I have been clicked.') alert('change_it has been called') } setup = function() { jQuery('#changing').click(change_it) } jQuery(document).ready(setup)
We haven't seen .html()
: it changes the contents of the element(s) when called.
There is a lot of stuff happening in one jQuery call. It deserves to be unpacked.
Consider this statement:
jQuery('p').click(say_hello)
jQuery
: the main jQuery function that we got by importing the jQuery library.jQuery('p')
: a jQuery object representing every paragraph on the page.jQuery('p').click
: a function (click
) that lives in this (and every) jQuery object. It operates on everything in the jQuery object (all paragraphs)jQuery('p').click(say_hello)
: a call to that function, giving say_hello
as the argument. Causes say_hello()
to be called when a <p>
is clicked.A similar call to the jQuery library:
jQuery('ul>li').html('I was <em>changed</em>.')
This line will change the contents of every <li>
child of a <ul>
to the given HTML.
The .click
function sets up what will happen when the element(s) are clicked. The .html
function changes the contents now.
There are also functions in the jQuery objects to let us modify an element's contents.
For example, the .html()
function can change the HTML inside elements:
jQuery('ul>li').html('I was <em>changed</em>.')
If we call the .html
function with no arguments, it will give us back the HTML already in the element. e.g. if we call on an element <p>example</p>
, it will give the string 'example'
.
This can be used to interact with the page a little more directly…
more_content = function() { old_content = jQuery('#appending').html() new_content = old_content + ' This is new.' jQuery('#appending').html(new_content) }
id="appending"
element, as a string (old_content
).new_content
) with that and some more text appended to it.id="appending"
element with new_content
.Connect it so it will run:
jQuery('button#appender').click(more_content)
The result: every time we click, more words are added to the end of that element.
Another way to modify the page: change element(s) attributes.
The .attr()
function will let us get or change the attributes of an element.
We can set an attribute value by giving .attr()
two arguments: the attribute name and the new value it should have.
For example, we could change an image src
:
be_sad = function() { jQuery('img#face').attr('src', 'sad.png') }
and connect it to an event:
jQuery('img#face').click(be_sad)
Or we could change an element's class (so its style changes according to whatever CSS we have):
jQuery('#action').attr('class', 'after-click')
That might pair with HTML like this:
<blockquote id="action" class="before-click"> ⋮ </blockquote>
Another way to manipulate the page with jQuery: show or hide particular elements. This can be used to reveal or hide certain elements as part of the behaviour of the page.
To start invisible, parts of the page can have CSS applied: display: none
To hide or reveal parts of the page, we can use the jQuery .hide()
or .show()
functions:
make_invisible = function() { jQuery('#visibility').hide() } make_visible = function() { jQuery('#visibility').show() }
We might attach these to buttons in the setup
function:
jQuery('#invisible').click(make_invisible) jQuery('#visible').click(make_visible)
And with HTML like this, we can toggle the visibility of a piece of our page:
<button id="visible">Make visible</button> <button id="invisible">Make invisible</button> <p id="visibility">I might be visible.</p>
Or we can insert content somewhere on the page. There are a few ways to add content, but let's try .append()
:
insert_after = function() { jQuery('h2#expand').after('<p>New content</p>') }
That will insert a new paragraph directly after an <h2>
:
<h2 id="expand">Expanding Section</h2>
This might be a good moment to explore the browser's developer tools again.
If we view the page source (control-U or ⌥⌘U), we see the HTML and CSS originally sent to the browser.
In the developer tools (F12 or control-shift-I or ⌥⌘I), we see the page as it's currently displayed, with modifications done in JavaScript.
The .click()
function in jQuery objects has been used to connect a function we write to elements' click events. i.e. when the user clicks the element, our function runs.
There are also other events we can respond to. Let's look at a few…
The jQuery .mouseover()
and .mouseleave()
functions make functions we write run when the user moves the mouse cursor over an element, or when it leaves it.
For example, we can change our previous happy/​sad example to respond to mouse movements (no clicking required):
jQuery('#face').mouseover(be_sad) jQuery('#face').mouseleave(be_happy)
With corresponding logic like this, we can change an image source as the mouse moves over it:
be_sad = function() { jQuery('#face').attr('src', 'sad.png') } be_happy = function() { jQuery('#face').attr('src', 'happy.png') }
But note: the mouse movement events don't really make sense on touch devices. Be cautious with how you use them.
We can respond to a key being pressed, which probably makes the most sense to apply to the whole page (since it's not clear what pressing a key
means for just one part of an HTML page).
jQuery('body').keypress(be_sad)
We have already seen the .ready()
function to set up our behaviour when the page loads, i.e. on the ready
event:
jQuery(document).ready(setup)
The document
variable is automatically defined, and jQuery(document)
is a jQuery object representing the whole page.
The ready
event fires when the page has been fully loaded by the browser.
It's possible to use .ready()
for other elements, but we will only use the same way, it for the whole page.
The .click()
and .ready()
functions (and others) are actually just shortcuts.
These two are exactly equivalent:
jQuery('#x').click(go) jQuery('#x').on('click', go)
There are many other HTML events, The .on()
function can be used to connect a function to any of them.
For example, for a touch device (where “click” doesn't really make sense):
jQuery('#x').on('touchstart', go)
Solving problems with your code isn't always obvious. It takes some experience and skill.
There is a lifetime of learning implied here, but there are a few basics…
Step 1: Do you know what you want to do?
If you don't know what you're trying to do, there's no hope: stop writing code and think. What steps do you need the computer to take to get the results you want?
What will make those things happen? What are you going to do with the results?
Step 2: Figure out what's happening. If you have a plan, you have some hope of getting your code to work.
Have a look at your code and see where it's diverging from expectations.
The simplest way to see what's happening is to do something visible.
You can insert an alert()
to see what's in a variable, or even if/when a function is running.
e.g. Is your click event even calling the right function? Put an alert("I'm here")
at the start of that function so you can tell.
e.g. What is actually in the variable old_content
? Add a alert(old_content)
so you can see it (at that particular place in the code).
Even nicer, you can call the console.log
function.
It works a little like alert
, but sends the message to the debugging console. Bring up the dev tools (F12 or control-shift-I or ⌥⌘I) and select the Console
tab.
It's less intrusive, so you can use it many times without having to click through each popup.
Bonus: if you console.log
a jQuery object, you can explore the elements it found. Are they the ones you expected to find?
paragraphs = jQuery('p') console.log(paragraphs) paragraphs.attr('class', 'testing-class')
We can check the developer's console to see what was selected (and stored in paragraphs
) and try to diagnose what's happening with the surrounding code.
Better still, the developer tools Debugging
tab. Here, you can inspect the JavaScript code, see what events are connected to something, step through JavaScript code, etc.
It's a powerful tool, but probably more powerful than we need.