JavaScript 笔记
请注意,JavaScript 和 Java 没有任何关系。
基本语法
结构
JavaScript 与 C / C++ 极为相似,甚至可以认为 JavaScript 就是 C++ 的简化版。JavaScript 没有特定的程序结构,因为 JavaScript 一般是被用于 函数定义 来辅助 HTML 页面,而不会像 C++ 程序一样被编译执行。
JavaScript 的每句话以分号结尾。
插入 JavaScript 代码
在 HTML 中插入 JavaScript 代码时使用 <script>
标签。例如:
<script>
alert("hello, world!");
</script>
JavaScript 还可以直接向 HTML 文档写入语句,例如:
document.write("<h1>标题</h1>");
document.write("<p>段落</p>");
如果在文档加载完毕后使用 document.write()
,则会覆盖整个 HTML 文档。
在 HTML 文档中可以放入无限多个脚本。脚本可以位于 <head>
或者 <body>
部分,通常把 JavaScript 函数放入 <head>
部分或者页面底部。例如:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>
test
</title>
<script>
function myFunction() {
document.getElementById("demo").innerHTML =
"Hello world!";
}
</script>
</head>
<body>
<p id="demo">
JavaScript
</p>
<button type="button" onclick="myFunction()">
点击查看效果
</button>
</body>
</html>
在这个例子中,按钮被按下后就会执行 <head>
中定义的函数 myFunction()
,把段落文字变为 Hello World!
。
除此之外,JavaScript 代码还可以置于外部,在 <script>
的属性中引入即可。例如:
function myFunction() {
document.getElementById("demo").innerHTML = \
"Hello world!";
}
把这段代码保存为 myScript.js
,那么 HTML 文档中就可以写:
<script src="myScript.js"></script>
输出
JavaScript 没有特定的输出函数。如果希望 JavaScript 显示数据,则有以下几种方法可选:
函数名 | 描述 |
---|---|
window.alert() |
弹出警告窗 |
document.write() |
写入 HTML 文档 |
.innerHTML |
写入 HTML 元素 |
console.log() |
写入浏览器控制台 |
注释
JavaScript 注释和 C++ 一模一样。
变量
JavaScript 的所有变量统一使用 var
声明。变量的类型可以 动态变化,也就是说可以实现:
var x = 1926;
x = "frog";
JavaScript 中可以 重复声明 同一个变量,其值不会丢失。如果声明一个变量后不赋初值,则由于变量类型没有定义,所以其值为 undefined
。
使用 typeof varName
可以返回变量的类型。而 ===
符号(即绝对相等)可以判断两个变量的 值和类型 是否都一致。如果希望声明一个变量的类型,则可以用 new
,例如:
var x = new Number;
则 x
就有了初值 0。但这样声明后,x
的类型就不再是 Number
而是 Object
。
如果把值赋给尚未声明的变量,该变量将自动作为 window
的一个属性。非严格模式下,该变量可以被删除。
局部变量
let
关键字可以用于声明局部变量,例如:
var x = 10;
// 此处 x = 10
{
let x = 2;
// 此处 x = 2
}
// 此处 x = 10
所以在 for
循环中的定义就可以使用 let
,防止出现混乱。
常量
const
关键字用于声明常量,和 C++ 中的 const int
类似。
数据类型
JavaScript 中的数据类型非常简洁,常用的只有数字、字符串、数组、对象这四种。
数字
JavaScript 中所有数字都属于同一种数据类型,也就是说 不用区分整型和浮点型,实在是太爽了。所有数字都是 64 位,等同于 C++ 中的 long long
。不过既然不搞 OI 了,上限是多少又如何呢?
num.toString(bit)
可以把数字转换为 bit
位表示下的字符串。例如:
var x = 4;
str = x.toString(2);
// str = "100"
NaN
是代表非数字值的数字值,而 isNaN()
函数可以用于判断一个值是否是数字。除此之外,JavaScript 还有 Infinity
常量,代表爆 Number
的临界值(有正负),不过 Infinity
进行运算后依然是 Infinity
,非常贴心。
数字运算符和 C++ 一模一样,非常容易上手。
Math
对象包含很多数学运算函数,可以依需调用。
字符串
字符串可以用单引号 '...'
或者双引号 "..."
标识。JavaScript 中的字符串还可以和数字直接相加,例如:
str = "ncc" + 79601;
那么 str
就变为了 "ncc79601"
。
在字符串内还可以用反斜杠 \
进行拆行,例如:
var str = "today is \
a good day";
则 str
为 "today is a good day"
。
和数组类似,str[i]
可以访问单个字符;str.length
属性可计算字符串长度。
方法 | 描述 |
---|---|
indexOf() |
查找一个子串首次出现的位置。如果未找到,则返回 -1 |
lastIndexOf() |
查找一个子串最后出现的位置 |
match() |
查找是否出现字符串。若找到则返回原字符串;否则返回 null |
toUpperCase() |
全部转换为大写 |
toLowerCase() |
全部转换为小写 |
split() |
转换为数组,参数为分隔符 |
数组
数组和 C++ 略微不同,使用中括号 [...]
标识。例如:
a = [1, 2, 3];
或者:
a = new Array();
a[0] = 1;
a[1] = 2;
a[2] = 3;
又或者:
a = new Array(1, 2, 3);
数组下标默认从 0 开始,而 indexOf()
方法可以返回对应元素的下标。注意数组的类型也是 object
。
遍历数组的方法:
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
for (let i in arr) {
console.log(arr[i]);
}
for (let i of arr) {
console.log(i);
// 注意和上一种的区别
}
方法 | 描述 |
---|---|
concat() |
合并数组(参数不定) |
join() |
用数组元素组合为字符串 |
pop() |
弹出最后一个元素 |
push() |
在末尾压入一个元素 |
reverse() |
翻转数组 |
shift() |
弹出第一个元素 |
unshift() |
在开头添加元素 |
splice() |
在第二位置插入元素 |
slice() |
截取子数组(左闭右开) |
sort() |
排序 |
toString |
转换到字符串 |
对象
JavaScript 面向对象,并且 JavaScript 中的所有事物都是对象。
创建对象
JavaScript 创建对象非常简单,利用类似 Python 中字典的描述方法即可。例如:
obj = {firstName: "Max", lastName: "Tedder", age: 16};
或者使用构造函数,例如:
function person(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
// 属性
function changeAge(newAge) {
this.age = newAge;
} // 方法
}
// 创建一个对象实例:
var obj = new person("max", "tedder", 16);
访问属性
键值对在 JavaScript 中也被称为 属性。访问属性有两种方法:
obj.firstName = "Max"; // 1
obj["firstName"] = "Max"; // 2
.constructor
可以返回对象的构造函数。
对象属性的遍历方法:
for (let i in obj) {
console.log(i, ":", obj[i]);
}
原型对象
所有的 JavaScript 对象都会从一个 prototype
(原型对象)中继承属性和方法。对于一个已经定义的对象构造器,是 不能向其中添加新属性 的,要添加一个新的属性需要在在构造器函数中添加(暴力修改);除此之外,也可以使用 prototype
属性。例如:
function person(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
person.prototype.nationality = "China";
// 所有 person 类的 nationality 属性都为 "China"
person.prototype.changeAge = function (newAge) {
this.age = newAge;
} // 方法
程序结构
循环与判断
与 C++ 完全一致,不做赘述。
函数
function
关键字用于声明函数。剩余的与 C++ 和 Python 类似,可以使用 return
语句结束函数并返回一个值。arguments.length
属性可以返回函数调用的参数个数。
对于 void()
关键字,将运行括号内的语句,而无返回值。例如 void(0)
就是什么也不做。
同时,声明函数时可以不带有函数名(匿名函数)。
参数
ES6 版本支持默认参数,和 Python 相同。
JavaScript 函数有个内置的对象 arguments
,其包含了函数调用的参数数组。
对象函数
函数可以作为对象方法调用,其中 this
关键字指代的是对象自己。例如:
var obj = {
firstName: "Max",
lastName: "Tedder",
fullName: function () {
return this.firstName + " " + this.lastName;
}
}
obj.fullName(); // 返回 "Max Tedder"
函数也可以用于构造对象,例如:
function name(arg1, arg2) {
this.firstName = arg1;
this.lastName = arg2;
}
var person = new name("Max", "Tedder");
// 创建了一个对象 person
预定义函数方法
call()
和 apply()
是预定义的函数方法,两个方法可用于调用函数,例如:
function mul(a, b) {
return a * b;
}
x = mul.call(x, 3, 4);
// 等价于:
x = mul.apply(x, [3, 4]);
// x = 12
函数表达式
函数可以通过一个表达式定义(类似 Python 中的 lambda
,实际上此处也属于匿名函数),相当于 把函数赋给了一个变量,这个变量充当函数名。例如:
var mul = function(a, b) { return a * b };
var x = mul(3, 4); // x = 12
ES6 版本引入了箭头函数,比函数表达式更加简洁,例如:
var mul = (a, b) => a * b;
// 相当于 (a, b) => { return a * b };
var x = mul(3, 4); // x = 12
自调用函数
自调用函数可以理解为在声明的时候就完成调用的函数。例如:
var a = (function f1(x) {
console.log("调用 f1");
return x;
})(6);
console.log(a);
则会将 6 作为参数执行 f1()
函数,而后作为返回值赋给 a
。
this
的使用
this
指代对象自己。既可以指代具体的一个对象(作为对象方法调用),又可以指代全体对象(纯粹函数调用)。参考资料
闭包
JavaScript 支持 嵌套函数,嵌套函数可以访问上一层的函数变量。由于函数内定义的变量无法在外部调用,因此为了实现这一功能,就有了 闭包 这个概念。
简单地说,闭包就是指用函数内部的函数来实现访问函数内变量的程序结构。例如,设 f2()
是 f1()
内部定义的一个函数,则外部可以通过 f2()
来访问 f1()
内部变量的值。在这个过程中,由于 f1()
内定义的变量被 f2()
引用,所以变量 不会被垃圾回收机制回收,也就是说这个变量会一直留在内存池中。
一个用函数内部变量实现全局变量功能的计数器:
var add = (function (base) {
// 自调用函数
var counter = base;
console.log("defined counter");
console.log(counter);
return function () {
// 匿名函数
counter++;
console.log("add counter");
return counter;
}
})(1);
// 相当于把内层函数赋给了 add
console.log(add());
console.log(add());
console.log(add());
输出为:
defined counter
1
add counter
2
add counter
3
add counter
4
异常捕捉
与 Python 类似,JavaScript 也支持对异常的捕捉。格式为:
try {
// 异常抛出
} catch(err) {
// 异常处理
} finally {
// 异常清理
}
使用 throw
可以抛出异常,抛出的异常可以为任意类型。例如:
try {
throw "hello!";
} catch(err) {
alert(err);
}
变量提升
JavaScript 中,函数及变量的声明都将被提升到函数的 最顶部。所以变量可以先使用再声明。
需要注意的是,带有初始化的变量声明不会被提升。例如:
var x;
var y = 1;
则 x
会被提升,而 y
不会。
调试
debugger
语句可以用于替代设置断点,方便进行调试。一般在浏览器的“检查元素”处可以进行调试。
严格模式
在 JavaScript 头部添加:
"use strict";
即可进入严格模式。严格模式可以使得 JavaScript 程序更加严谨,为未来的 JavaScript 铺路。
面向 HTML
表单
在 HTML 中有 <form>
标签描述的表单,表单经提交后即可被 JavaScript 处理。
下面这个例子实现了判断 myForm
中的 firstName
是否合法。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>
test
</title>
<script>
function judge() {
var x, text;
x = document.forms["myForm"]["firstName"].value;
// 从 document 对象读取表单
if (x == null || x == "") {
alert("输入不合法");
return false;
}
alert("提交成功")
return true;
}
</script>
</head>
<body>
<form name="myForm" action="form_action.php" onsubmit="judge()">
<input type="text" name="firstName" value="First Name">
<input type="submit" value="提交">
<input type="reset" value="重置">
</form>
</body>
</html>
同样,JavaScript 还可以用于判断普通的输入是否合法,例如:
<script>
function judge() {
var x = document.getElementById("inputBox").value;
var text;
if (isNaN(x) || x <= 0) {
text = "输入错误";
} else {
text = "输入正确";
}
document.getElementById("infor").innerHTML = text;
}
</script>
<input id="inputBox" value="输入一个正数">
<button onclick="judge()">check</button>
<p id="infor"></p>
JSON
JSON 是用于存储和传输数据的格式。一般一个 JSON 文件描述了一个 JavaScript 对象,便于作为文本在服务器和客户端之间传输。例如:
{"processor": [
{"name": "8700K", "gen": "8th"},
{"name": "8705G", "gen": "8th"},
{"name": "9700K", "gen": "9th"},
{"name": "1065G7", "gen": "10th"}
]}
对象转 JSON
str = JSON.stringify(obj);
JSON 转对象
obj = JSON.parse(str);
HTML DOM
DOM 全名为 文档对象模型(Document Object Model),上文出现过的 document
对象就是一个 DOM。DOM 按照 HTML 标签的父子关系将整个 HTML 文档划分为一个树形结构。
查找 HTML 元素
通过 id
查找
使用 getElementById
方法,例如:
var x = document.getElementById("demo");
如果未找到,则会返回 null
。
通过标签名查找
使用 getElementsByTagName
方法,例如:
var x = getElementById("demo");
var y = getElementsByTagName("p");
// 查找 <main> 标签中的所有 <p> 标签(DOM Collection)
通过类名查找
使用 getElementByClassName
方法,例如:
var x = getElementByClassName("studentInfor");
改变 HTML
改变输出流
在上文提到的 document.write()
方法就是改变 HTML 输出流的方法,其可以在 HTML 文档中直接写入内容。当然,绝对不能在 HTML 加载完毕之后使用这个方法,不然会使原来的文档被覆盖。
改变内容
查找到元素后,修改 innerHTML
属性可以修改 HTML 元素的内容。例如:
document.getElementById("demo").innerHTML = "你好";
改变元素属性
查找到元素后,修改相应的属性即可。例如:
document.getElementById("image").src = "earth.jpg";
改变 CSS
查找到元素后,修改 style.property
即可改变相应的样式,例如:
document.getElementById("demo").style.color="#00ff00";
document.getElementById("demo").style.fontSize="larger";
使用事件
HTML 事件是发生在 HTML 元素上的事情。HTML 元素可以添加事件属性,例如:
<标签 事件名="JavaScript 代码()">
常见的 HTML 事件有:
事件名 | 描述 |
---|---|
onchange |
元素改变 |
onclick |
点击元素 |
onmouseover |
在元素上移动鼠标 |
onmouseout |
从元素上移出鼠标 |
onkeydown |
按下键盘 |
onload |
完成页面加载 |
onfocus |
输入框获得焦点 |
onblur |
输入框失去焦点 |
例如:
document.getElementById("button").onclick = function () {
document.getElementById("demo").innerHTML = Date();
} // 实用了匿名函数
注意:传入事件名的应该是函数,如果是调用已定义的函数,则函数名后 不应该加括号。
addEventListener()
方法可以向元素添加事件句柄,这使得一个元素可以拥有多个事件句柄。新添加的事件句柄不会覆盖已有的事件句柄。可以向 任何 DOM 对象 添加事件监听,不仅仅是 HTML 元素。如:window
对象。
格式为:
element.addEventListener(event, function, useCapture);
// 此处的事件名要去掉 "on"
// useCapture 默认为 false
useCapture
指的是事件传递方式,它决定了事件触发的顺序。当属性为 false
,传递方式为 冒泡(由内而外);当属性为 true
,传递方式为 捕获(由外而内)。
例如:
document.getElementById("button").addEventListener("click", function () {
alert("Hello World!");
});
如果需要传递参数,则使用匿名函数调用带参数的函数。
removeEventListener()
方法可以用于移除事件句柄,格式与 addEventListener()
一致(无 useCapture
参数)。
为了使 EventListener
稳定工作,可以把 addEventListener
写入 window.onload
事件,也就是:
window.onload = function () {
var x = document.getElementById("button");
x.addEventListener("click", myFunction);
};
新建元素
要创建新的 HTML 元素(节点)需要先创建一个元素,然后用 appendChild()
方法在已存在的元素中添加它。例如:
<div id="div1">
<p>第一段</p>
<!--新的一段会出现在这里-->
</div>
<script>
var newPara = document.createElement("p");
var newNode = document.createTextNode("第二段");
newPara.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
</script>
appendChild()
方法可以把节点添加到元素末尾,而 insertBefore()
方法则可以把节点添加到特定元素之前。在调用次方法时,必须传入参照节点的对象。例如:
<div id="div1">
<!--新的一段会出现在这里-->
<p id="p1">第一段</p>
</div>
<script>
var newPara = document.createElement("p");
var newNode = document.createTextNode("第二段");
newPara.appendChild(node);
var element = document.getElementById("div1");
var child = document.getElementById("p1");
element.insertBefore(newPara, child);
// 注意两者函数参数的区别
</script>
removeChild()
方法可以移除已存在的元素。其使用方法和 appendChild()
相同。需要注意的是,使用 removeChild()
方法时 必须知道目标元素的父元素。
replaceChild()
方法可以替换已存在的元素。例如:
<div id="div1">
<p id="p1">第一段</p>
<p id="p2">第二段</p>
</div>
<script>
var newPara = document.createElement("p");
var newNode = document.createTextNode("第三段");
newPara.appendChild(node);
var element = document.getElementById("div1");
var child = document.getElementById("p2");
element.replaceChild(newPara, child);
</script>
HTML Collection
getElementsByTagName()
方法返回 HTML Collection 对象,包含对应标签名的所有元素。HTML Collection 对象虽然支持数组的一些操作,但其 不是数组,而是特殊的一种对象。
下面这个例子修改所有段落的背景颜色:
var myCollection = document.getElementsByTagName("p");
for (let i = 0; i < myCollection.length; i++) {
myCollection[i].style.backgroundColor = "red";
}
NodeList
NodeList 不同于却类似于 HTML Collection 对象,是一个从文档中获取的节点列表。
例如将上一个例子改为用 NodeList 实现:
var myNodeList = document.querySelectorAll("p");
// 获取 <p> 元素的集合
for (let i = 0; i < myNodeList.length; i++) {
myNodeList[i].style.backgroundColor = "red";
}
JavaScript Window
浏览器对象模型(BOM)使 JavaScript 有能力与浏览器交流。window
对象就是一个 BOM。HTML DOM 的 document
也是 window
对象的属性(window.document
),不过在代码中可以将 window
省略。
Window 尺寸
属性 | 描述 |
---|---|
window.innerHeight |
内部高度(包括滚动条) |
window.innerWidth |
内部宽度(包括滚动条) |
screen.availHright |
可用屏幕高度 |
screen.availWidth |
可用屏幕宽度 |
Window 地址
属性 / 方法 | 描述 |
---|---|
location.hostname |
主机域名 |
location.pathname |
当前页面路径 |
location.port |
主机端口 |
location.protocol |
web 协议 |
location.href |
当前页面 url |
location.assign(url) |
加载新文档 |
Window Navigator
navigator
包含访问者浏览器的相关信息。
弹窗
方法 | 描述 |
---|---|
alert() |
警告框 |
confirm() |
确认框 |
prompt() |
提示框 |
计时事件
方法 | 描述 |
---|---|
setInterval(function, ms) |
间隔指定毫秒数循环执行指定代码 |
clearInterval() |
停止执行 setInterval() 方法 |
setTimeout(function, ms) |
在指定毫秒数后执行指定代码 |
clearTimeout() |
停止执行 setTimeout() 方法 |
Cookie
Cookie 用于存储 web 页面的用户信息。在连接关闭后,服务端不会记录用户的信息,此时就需要 Cookie 记录客户端的用户信息。例如:
document.cookie="username=Max Tedder; userid=114514";
删除 Cookie 时,只需要把等号后的内容删除。例如:
document.cookie="username=; userid=";
不过由于涉及 Cookie 的操作在现阶段用处不大,因此不做赘述。
至此,JavaScript 的基本内容就讲解完毕了。