在简单学习了 HTML 和 CSS 之后,接下来是 JavaScript 的学习,学习的重点不是 JavaScript 作为一个脚本语言的语法内容,而是 JavaScript 对于网页的控制,参考教程:https://developer.mozilla.org

  • HTML 定义了网页的内容
  • CSS 描述了网页的布局
  • JavaScript 控制了网页的行为

1. 在 HTML 中使用 JS

在 HTML 和 CSS 一起组装成一个网页之后,浏览器的 JavaScript 引擎将执行 JavaScript 代码,这保证了当 JavaScript 开始运行之前,网页的结构和样式已经就位,然后 JS 可以更新这个网页的具体内容等。

对于浏览器,它的每一个标签页使用了一个独立的运行环境,不同标签页之间没有任何联系,JS 代码也相互独立运行,一定程度上保证了信息安全。

script 标签

在 HTML 的 head 或者 body 部分都可以使用,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>demo title</title>
</head>
<body>
<script>
console.log("使用JavaScript");
document.write("<h1>这是一个标题</h1>");
</script>
</body>
</html>

建议在 body 部分的最后使用(也就是</body>之前),否则加载时可能遇到 HTML 元素还没出现等错误,通常 JS 需要等待 HTML/CSS 加载完成后进行执行,对网页进行进一步的处理。

链接 JS 文件

导入外部的 js 文件,在 HTML 的 head 或者 body 部分都可以使用,例如:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>demo title</title>
</head>
<body>
<script src="abc.js"></script>
</body>
</html>

加载逻辑

对于外部脚本的加载执行,默认情况下,浏览器处理 HTML/CSS 生成页面时,遇到<script>元素时会中断页面的加载,立刻加载脚本并执行,然后加载页面的剩余部分。

可以使用 async 进行异步化加载,它告知浏览器:在遇到<script>元素时不要中断后续页面的加载,异步地进行脚本加载,等到 JS 脚本下载完成时中断页面的处理,执行脚本,执行完成后继续加载页面。使用 async 引入的脚本建议不要修改页面内容,并且不能依赖其他脚本,因为对于多个 async,加载的进度不可控,因此执行的顺序也不可控。

1
<script async src="abc.js"></script>

可以使用 defer 进行,它明确告知浏览器:遇到<script>元素时异步进行脚本加载,等到整个页面加载结束,才会执行脚本,脚本会在 DOMContentLoaded 事件触发之前执行完,并且对于多个脚本按照出现的顺序依次执行,例如

1
2
3
4
5
<script defer src="js/script1.js"></script>

<script defer src="js/script2.js"></script>

<script defer src="js/script3.js"></script>

2. JS 基础语法

作为脚本语言,JS 和 Python 非常类似,首先过一遍语法。

  • JS 的语句使用大括号划分语句块的结构层次等。
  • JS 对于大小写敏感!
  • JS 语句可以不使用结束符,但是建议使用分号作为语句的结束,没有分号的语句出现在行末总是默认语句结束了。
  • JS 支持注释,包括/**///都可以。

基本字面量

  • 数字 Number 包括整数和小数;(整数和小数根本不分开,特别注意)
  • 字符串 String 例如a="John",支持索引访问(从 0 开始),可以直接获取长度a.length
  • 布尔类型 Boolean 例如 true 和 false;
  • 数组 Array 例如[1,2,3]
  • 对象 Object 例如{name:"abc",length:20};(JSON 语法就是由此衍生的,最后一个不要加逗号)
  • 函数 Function 例如function fa(a,b){ return a*b; }

数字字符串可以与数字互相转换类型:

1
2
3
4
(123).toString(); // 得到 "123"
String(123); // 同上

Number("3.14"); // 得到数字3.14

变量

和 Python 一样,JS 变量是没有固定类型的,变量可以赋任何类型的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
var a, b; // 变量声明(创建了变量,但是没有值,未定义undefined)
a = 1;

var length = 16; // 创建变量并赋值
var length; // 重复的变量声明没有语法错误,并且不会丢失原有的值

length = undefined; // 可以对变量赋值nundefined或者null,会清空变量原有的值

// null更适合释放一个复杂对象
// undefined是所有变量未获得值时的状态

var name = "John";
document.getElementById("demo").innerHTML = name; // 把id为demo的元素内容换成了字符串John

可以使用 typeof 获取当前变量的类型,例如

1
2
3
var a = 1;

typeof a; // 返回number

不声明直接使用变量也是可以的,这时会自动视为 window 的一个属性,例如

1
2
3
a = "abc";
// 不使用var a 声明变量而直接使用
// 此后也可以通过window.a访问变量

对于var a等变量声明语句,JS 解析时采用了声明提升的规则,也就是会自动把变量声明语句(不含初值)移动到语句块的最前方。

函数

见下例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 无参数
function myfunc_1() {
return 1;
}

// 含参数
// 可以定义变量
function myfunc_2(a, b) {
var x = a + b; // 这里默认是局部变量,函数退出后自动销毁
return x;
}

// 不一定需要返回值,可以无值返回,还可以混合
function myfunc_3(a, b) {
if (a > b) {
return;
}
return a;
}

对象

对象的定义以及属性的获取见下例,格式就是 JSON 那样:

1
2
3
4
5
6
7
var a = {
name: "abc",
length: 12,
};

a.length; //返回12
a["length"]; //返回12 注意需要加双引号

对象除了属性,还可以定义方法,也就是对象可调用的函数,例如

1
2
3
4
5
6
7
8
9
var a={
name: "abc"
f: function(){
return this.name;
}
}

a.f() // 调用方法,返回的是"abc"
a.f // 返回的是一个函数

流程控制

条件语句,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if (a > 0) {
// ...
}

if (a != 0) {
// ...
} else if (a > 0) {
// ...
} else {
// ...
}

switch (n) {
case 1:
// ...
break;
case 2:
// ...
break;
default:
// ...
}

循环语句,基本上也和 c 风格一样,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// c风格的for循环
for (var i = 0; i < s.length; i++) {
a += i;
}

// 遍历对象的所有属性
for (x in person) {
a = a + person[x];
}

while (i < 5) {
// ...
}

do {
// ...
} while (a > 0);

也支持 break 和 continue 跳出循环。

严格模式

JS 的语法较为宽松,但是可以在脚本或函数的开头使用下面一行代码开启严格模式,

1
"use strict";

严格模式会用更严格的标准来检查语法:

  • 不允许使用未声明的变量;
  • 不允许使用delete a;删除变量或对象或函数;
  • 不允许函数重名等。
  • ...

3. JS 脚本如何执行

JS 脚本在网页中何时会被执行?主要有两类:

  • 网页加载时,或者网页加载完成时;
  • 特定的事件触发,例如点击按钮,在文本框输入内容,关闭页面等,主要是通过调用函数来执行。

加载时执行

例一,加载页面时 demo 元素会被 JS 修改内容,变成"段落已修改。"

1
2
3
4
5
<p id="demo">我的第一个段落</p>

<script>
document.getElementById("demo").innerHTML = "段落已修改。";
</script>

效果为:

我的第一个段落

例二,加载页面时直接在页面中添加内容,注意不要在文档加载完成之后使用document.write(),这会覆盖该文档。

1
2
3
<script>
document.write(Date());
</script>

效果为:

例三,加载页面时会自动触发弹窗,还会向浏览器控制台写入信息(未使用)

1
2
3
4
<script>
window.alert("hello,world");
console.log("hello");
</script>

由事件触发

例一,点击按钮会把<p>元素的内容设置为当前时间,因为把按钮的 onclick 绑定到了 JS 的 myFunction 函数,会触发执行 myFunction 函数。

1
2
3
4
5
6
7
8
9
10
<p>
当前时间:<span id="nowdate"></span>
<button onclick="myFunction()">刷新时间</button>
</p>
<script>
function myFunction() {
document.getElementById("nowdate").innerHTML = Date();
}
myFunction(); // 第一次在加载时会执行
</script>

效果为:

当前时间:

除了在 HTML 元素中绑定,也可以在 JS 脚本中对元素的特定事件绑定相应函数。例如下面通过 JS 脚本对文本绑定了很多函数,对应行为会分别触发相应函数。

源代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<p id="d0">与这段文字交互</p>

<script>
function whenclick() {
document.getElementById("d0").innerHTML = "你点击了这段文字";
}
function whenclickright() {
document.getElementById("d0").innerHTML = "你右键点击了这段文字";
}
function whenmouseover() {
document.getElementById("d0").style.color = "green";
}
function whenmouseout() {
document.getElementById("d0").style.color = "blue";
document.getElementById("d0").innerHTML = "与这段文字交互";
}

document.getElementById("d0").onclick = whenclick;
document.getElementById("d0").oncontextmenu = whenclickright;
document.getElementById("d0").onmouseover = whenmouseover;
document.getElementById("d0").onmouseout = whenmouseout;
</script>

效果为:

与这段文字交互

常见的事件为:

  • 当前 HTML 元素被改变 onchange;
  • 当前 HTML 元素被单击(似乎左右键都行) onclick;
  • 当前 HTML 元素被右键点击 oncontextmenu;
  • 鼠标移动到 HTML 元素上 onmouseover;
  • 鼠标从 HTML 元素上移开 onmouseout;

4. JS 如何修改页面

接下来考虑:JS 脚本如何修改网页的内容,包括 HTML 元素的内容,属性和样式等。

接入 HTML 输入流

使用 document.write 在页面当前位置中添加内容,注意不要在文档加载完成之后使用 document.write(),这会覆盖该文档。

源代码如下(未使用)

1
2
3
<script>
document.write(Date());
</script>

改变元素内容

使用document.getElementById等方法可以获取元素,对元素的 innerHTML 属性赋值,就是直接修改元素的内容。

源代码如下

1
2
3
4
5
6
7
8
9
10
11
<ul>
<li><span id="p1">Hello World!</span></li>
<li><span name="p2">Hello World!</span></li>
<li><span class="p3">Hello World!</span></li>
</ul>

<script>
document.getElementById("p1").innerHTML = "新文本1 !";
document.getElementsByName("p2")[0].innerHTML = "新文本2 !"; // 注意是elements,得到的是数组
document.getElementsByClassName("p3")[0].innerHTML = "新文本3 !"; // 注意是elements,得到的是数组
</script>

效果如下:

  • Hello World!
  • Hello World!
  • Hello World!

改变元素属性/样式

使用document.getElementById等方法可以获取元素,对元素的 style 属性的子属性赋值,就是直接修改元素的样式。

源代码如下:

1
2
3
4
5
6
7
8
9
10
<ul>
<li><span id="q1">Hello World! 改蓝色</span></li>
<li><span id="q2">Hello World! 改字体</span></li>
<li><span id="q3">Hello World! 改字号</span></li>
</ul>
<script>
document.getElementById("q1").style.color = "blue";
document.getElementById("q2").style.fontFamily = "Arial";
document.getElementById("q3").style.fontSize = "larger";
</script>

效果如下:

  • Hello World! 改蓝色
  • Hello World! 改字体
  • Hello World! 改字号

直接弹窗

浏览器支持三种弹窗:警告框、确认框、提示框。

  • 警告框向用户弹出警告,用户只能关闭,
  • 确认框需要用户选择确认或取消,返回一个布尔值,
  • 提示框需要用户输入一个值(可以给默认值),然后点击确认或直接取消,如果取消返回值为 null,

可以分别点击按钮试一下,源代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<script>
function f1() {
alert("你好,我是一个警告框!");
}

function f2() {
var x;
var r = confirm("按下按钮!");
if (r == true) {
x = '你按下了"确定"按钮!';
} else {
x = '你按下了"取消"按钮!';
}
document.getElementById("append1").innerHTML = x;
}

function f3() {
var x;
var person = prompt("请输入你的名字", "Harry Potter");
if (person != null && person != "") {
x = "你好 " + person + "! 今天感觉如何?";
document.getElementById("append2").innerHTML = x;
}
}
</script>

计时事件

可以实现每秒获取时间,写入元素中: 也就是每秒钟运行一次代码,点击时间则可以停止这个计时事件。

源代码如下,似乎函数使用可以放在定义之前?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
// 接入变量myVar中,否则无法停止
var myVar = setInterval(function () {
myTimer();
}, 1000); // 间隔1000毫秒

function myTimer() {
var d = new Date();
var t = d.toLocaleTimeString();
document.getElementById("time1").innerHTML = t;
}

function myStopFunction() {
clearInterval(myVar); // 可以停止myVar这个计时事件
}
</script>

5. JS 表单

静态网页暂时用不到,以后有空再补吧。

6. Node.js 运行本地服务器

参考代码及注释如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//请求Node.js自带的http模块。
var http = require("http");

//http模块提供了createServer函数,这个函数会返回一个对象,我们将返回的对象赋值给server。
var server = http.createServer(function (req, res) {
//req:接收到的数据。 res:响应数据
res.setHeader("Content-Type", "text/html; charset=utf-8"); //设置响应的头部。 content-Type 响应数据内容的类型
res.writeHead(200, "ok"); //HTTP状态值
res.write("Hello Node!!"); //响应内容
res.end();
});

//这个对象有个叫做listen的方法,这个方法可以有个数值参数。
//指定这个HTTP服务器监听的端口号。
//当我们打开http://localhost:8080的时候,服务器就会接收数据,并且响应数据
server.listen(8080);
console.log("服务器已打开,可以运行 http://localhost:8080");

web 笔记完。