【退役生活】JavaScript 学习笔记

NCC79601

2020-02-08 21:19:04

Personal

# JavaScript 笔记 **请注意,JavaScript 和 Java 没有任何关系。** ## 基本语法 ### 结构 JavaScript 与 C / C++ 极为相似,甚至可以认为 JavaScript 就是 C++ 的简化版。JavaScript 没有特定的程序结构,因为 JavaScript 一般是被用于 **函数定义** 来辅助 HTML 页面,而不会像 C++ 程序一样被编译执行。 JavaScript 的每句话以分号结尾。 ### 插入 JavaScript 代码 在 HTML 中插入 JavaScript 代码时使用 `<script>` 标签。例如: ```html <script> alert("hello, world!"); </script> ``` JavaScript 还可以直接向 HTML 文档写入语句,例如: ```javascript document.write("<h1>标题</h1>"); document.write("<p>段落</p>"); ``` 如果在文档加载完毕后使用 `document.write()`,则会覆盖整个 HTML 文档。 在 HTML 文档中可以放入无限多个脚本。脚本可以位于 `<head>` 或者 `<body>` 部分,通常把 JavaScript 函数放入 `<head>` 部分或者页面底部。例如: ```html <!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>` 的属性中引入即可。例如: ```javascript function myFunction() { document.getElementById("demo").innerHTML = \ "Hello world!"; } ``` 把这段代码保存为 `myScript.js`,那么 HTML 文档中就可以写: ```html <script src="myScript.js"></script> ``` ### 输出 JavaScript 没有特定的输出函数。如果希望 JavaScript 显示数据,则有以下几种方法可选: |函数名|描述| |:-|:-| |`window.alert()`|弹出警告窗| |`document.write()`|写入 HTML 文档| |`.innerHTML`|写入 HTML 元素| |`console.log()`|写入浏览器控制台| ### 注释 JavaScript 注释和 C++ 一模一样。 ### 变量 JavaScript 的所有变量统一使用 `var` 声明。变量的类型可以 **动态变化**,也就是说可以实现: ```javascript var x = 1926; x = "frog"; ``` JavaScript 中可以 **重复声明** 同一个变量,其值不会丢失。如果声明一个变量后不赋初值,则由于变量类型没有定义,所以其值为 `undefined`。 使用 `typeof varName` 可以返回变量的类型。而 `===` 符号(即绝对相等)可以判断两个变量的 **值和类型** 是否都一致。如果希望声明一个变量的类型,则可以用 `new`,例如: ```javascript var x = new Number; ``` 则 `x` 就有了初值 0。但这样声明后,`x` 的类型就不再是 `Number` 而是 `Object`。 如果把值赋给尚未声明的变量,该变量将自动作为 `window` 的一个属性。非严格模式下,该变量可以被删除。 ### 局部变量 `let` 关键字可以用于声明局部变量,例如: ```javascript 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` 位表示下的字符串。例如: ```javascript var x = 4; str = x.toString(2); // str = "100" ``` `NaN` 是代表非数字值的数字值,而 `isNaN()` 函数可以用于判断一个值是否是数字。除此之外,JavaScript 还有 `Infinity` 常量,代表爆 `Number` 的临界值(有正负),不过 `Infinity` 进行运算后依然是 `Infinity`,非常贴心。 数字运算符和 C++ 一模一样,非常容易上手。 `Math` 对象包含很多数学运算函数,可以依需调用。 #### 字符串 字符串可以用单引号 `'...'` 或者双引号 `"..."` 标识。JavaScript 中的字符串还可以和数字直接相加,例如: ```javascript str = "ncc" + 79601; ``` 那么 `str` 就变为了 `"ncc79601"`。 在字符串内还可以用反斜杠 `\` 进行拆行,例如: ```javascript 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++ 略微不同,使用中括号 `[...]` 标识。例如: ```javascript a = [1, 2, 3]; ``` 或者: ```javascript a = new Array(); a[0] = 1; a[1] = 2; a[2] = 3; ``` 又或者: ```javascript a = new Array(1, 2, 3); ``` 数组下标默认从 0 开始,而 `indexOf()` 方法可以返回对应元素的下标。注意数组的类型也是 `object`。 遍历数组的方法: ```javascript 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 中字典的描述方法即可。例如: ```javascript obj = {firstName: "Max", lastName: "Tedder", age: 16}; ``` 或者使用构造函数,例如: ```javascript 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 中也被称为 **属性**。访问属性有两种方法: ```javascript obj.firstName = "Max"; // 1 obj["firstName"] = "Max"; // 2 ``` `.constructor` 可以返回对象的构造函数。 对象属性的遍历方法: ```javascript for (let i in obj) { console.log(i, ":", obj[i]); } ``` #### 原型对象 所有的 JavaScript 对象都会从一个 `prototype`(原型对象)中继承属性和方法。对于一个已经定义的对象构造器,是 **不能向其中添加新属性** 的,要添加一个新的属性需要在在构造器函数中添加(暴力修改);除此之外,也可以使用 `prototype` 属性。例如: ```javascript 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` 关键字指代的是对象自己。例如: ```javascript var obj = { firstName: "Max", lastName: "Tedder", fullName: function () { return this.firstName + " " + this.lastName; } } obj.fullName(); // 返回 "Max Tedder" ``` 函数也可以用于构造对象,例如: ```javascript function name(arg1, arg2) { this.firstName = arg1; this.lastName = arg2; } var person = new name("Max", "Tedder"); // 创建了一个对象 person ``` #### 预定义函数方法 `call()` 和 `apply()` 是预定义的函数方法,两个方法可用于调用函数,例如: ```javascript function mul(a, b) { return a * b; } x = mul.call(x, 3, 4); // 等价于: x = mul.apply(x, [3, 4]); // x = 12 ``` #### 函数表达式 函数可以通过一个表达式定义(类似 Python 中的 `lambda`,实际上此处也属于匿名函数),相当于 **把函数赋给了一个变量**,这个变量充当函数名。例如: ```javascript var mul = function(a, b) { return a * b }; var x = mul(3, 4); // x = 12 ``` ES6 版本引入了箭头函数,比函数表达式更加简洁,例如: ```javascript var mul = (a, b) => a * b; // 相当于 (a, b) => { return a * b }; var x = mul(3, 4); // x = 12 ``` #### 自调用函数 自调用函数可以理解为在声明的时候就完成调用的函数。例如: ```javascript var a = (function f1(x) { console.log("调用 f1"); return x; })(6); console.log(a); ``` 则会将 6 作为参数执行 `f1()` 函数,而后作为返回值赋给 `a`。 #### `this` 的使用 `this` 指代对象自己。既可以指代具体的一个对象(作为对象方法调用),又可以指代全体对象(纯粹函数调用)。[参考资料](http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html) #### 闭包 JavaScript 支持 **嵌套函数**,嵌套函数可以访问上一层的函数变量。由于函数内定义的变量无法在外部调用,因此为了实现这一功能,就有了 **闭包** 这个概念。 简单地说,闭包就是指用函数内部的函数来实现访问函数内变量的程序结构。例如,设 `f2()` 是 `f1()` 内部定义的一个函数,则外部可以通过 `f2()` 来访问 `f1()` 内部变量的值。在这个过程中,由于 `f1()` 内定义的变量被 `f2()` 引用,所以变量 **不会被垃圾回收机制回收**,也就是说这个变量会一直留在内存池中。 一个用函数内部变量实现全局变量功能的计数器: ```javascript 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 也支持对异常的捕捉。格式为: ```javascript try { // 异常抛出 } catch(err) { // 异常处理 } finally { // 异常清理 } ``` 使用 `throw` 可以抛出异常,抛出的异常可以为任意类型。例如: ```javascript try { throw "hello!"; } catch(err) { alert(err); } ``` ### 变量提升 JavaScript 中,函数及变量的声明都将被提升到函数的 **最顶部**。所以变量可以先使用再声明。 需要注意的是,带有初始化的变量声明不会被提升。例如: ```javascript var x; var y = 1; ``` 则 `x` 会被提升,而 `y` 不会。 ### 调试 `debugger` 语句可以用于替代设置断点,方便进行调试。一般在浏览器的“检查元素”处可以进行调试。 ### 严格模式 在 JavaScript 头部添加: ```javascript "use strict"; ``` 即可进入严格模式。严格模式可以使得 JavaScript 程序更加严谨,为未来的 JavaScript 铺路。 ## 面向 HTML ### 表单 在 HTML 中有 `<form>` 标签描述的表单,表单经提交后即可被 JavaScript 处理。 下面这个例子实现了判断 `myForm` 中的 `firstName` 是否合法。 ```html <!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 还可以用于判断普通的输入是否合法,例如: ```html <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 对象,便于作为文本在服务器和客户端之间传输。例如: ```json {"processor": [ {"name": "8700K", "gen": "8th"}, {"name": "8705G", "gen": "8th"}, {"name": "9700K", "gen": "9th"}, {"name": "1065G7", "gen": "10th"} ]} ``` ### 对象转 JSON ```javascript str = JSON.stringify(obj); ``` ### JSON 转对象 ```javascript obj = JSON.parse(str); ``` ## HTML DOM DOM 全名为 **文档对象模型**(Document Object Model),上文出现过的 `document` 对象就是一个 DOM。DOM 按照 HTML 标签的父子关系将整个 HTML 文档划分为一个树形结构。 ### 查找 HTML 元素 #### 通过 `id` 查找 使用 `getElementById` 方法,例如: ```javascript var x = document.getElementById("demo"); ``` 如果未找到,则会返回 `null`。 #### 通过标签名查找 使用 `getElementsByTagName` 方法,例如: ```javascript var x = getElementById("demo"); var y = getElementsByTagName("p"); // 查找 <main> 标签中的所有 <p> 标签(DOM Collection) ``` #### 通过类名查找 使用 `getElementByClassName` 方法,例如: ```javascript var x = getElementByClassName("studentInfor"); ``` ### 改变 HTML #### 改变输出流 在上文提到的 `document.write()` 方法就是改变 HTML 输出流的方法,其可以在 HTML 文档中直接写入内容。当然,绝对不能在 HTML 加载完毕之后使用这个方法,不然会使原来的文档被覆盖。 #### 改变内容 查找到元素后,修改 `innerHTML` 属性可以修改 HTML 元素的内容。例如: ```javascript document.getElementById("demo").innerHTML = "你好"; ``` #### 改变元素属性 查找到元素后,修改相应的属性即可。例如: ```javascript document.getElementById("image").src = "earth.jpg"; ``` ### 改变 CSS 查找到元素后,修改 `style.property` 即可改变相应的样式,例如: ```javascript document.getElementById("demo").style.color="#00ff00"; document.getElementById("demo").style.fontSize="larger"; ``` ### 使用事件 HTML 事件是发生在 HTML 元素上的事情。HTML 元素可以添加事件属性,例如: ```html <标签 事件名="JavaScript 代码()"> ``` 常见的 HTML 事件有: |事件名|描述| |:-|:-| |`onchange`|元素改变| |`onclick`|点击元素| |`onmouseover`|在元素上移动鼠标| |`onmouseout`|从元素上移出鼠标| |`onkeydown`|按下键盘| |`onload`|完成页面加载| |`onfocus`|输入框获得焦点| |`onblur`|输入框失去焦点| 例如: ```javascript document.getElementById("button").onclick = function () { document.getElementById("demo").innerHTML = Date(); } // 实用了匿名函数 ``` **注意**:传入事件名的应该是函数,如果是调用已定义的函数,则函数名后 **不应该加括号**。 `addEventListener()` 方法可以向元素添加事件句柄,这使得一个元素可以拥有多个事件句柄。新添加的事件句柄不会覆盖已有的事件句柄。可以向 **任何 DOM 对象** 添加事件监听,不仅仅是 HTML 元素。如:`window` 对象。 格式为: ```javascript element.addEventListener(event, function, useCapture); // 此处的事件名要去掉 "on" // useCapture 默认为 false ``` `useCapture` 指的是事件传递方式,它决定了事件触发的顺序。当属性为 `false`,传递方式为 **冒泡**(由内而外);当属性为 `true`,传递方式为 **捕获**(由外而内)。 例如: ```javascript document.getElementById("button").addEventListener("click", function () { alert("Hello World!"); }); ``` 如果需要传递参数,则使用匿名函数调用带参数的函数。 `removeEventListener()` 方法可以用于移除事件句柄,格式与 `addEventListener()` 一致(无 `useCapture` 参数)。 为了使 `EventListener` 稳定工作,可以把 `addEventListener` 写入 `window.onload` 事件,也就是: ```javascript window.onload = function () { var x = document.getElementById("button"); x.addEventListener("click", myFunction); }; ``` ### 新建元素 要创建新的 HTML 元素(节点)需要先创建一个元素,然后用 `appendChild()` 方法在已存在的元素中添加它。例如: ```html <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()` 方法则可以把节点添加到特定元素之前。在调用次方法时,必须传入参照节点的对象。例如: ```html <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()` 方法可以替换已存在的元素。例如: ```html <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 对象虽然支持数组的一些操作,但其 **不是数组**,而是特殊的一种对象。 下面这个例子修改所有段落的背景颜色: ```javascript var myCollection = document.getElementsByTagName("p"); for (let i = 0; i < myCollection.length; i++) { myCollection[i].style.backgroundColor = "red"; } ``` ### NodeList NodeList 不同于却类似于 HTML Collection 对象,是一个从文档中获取的节点列表。 例如将上一个例子改为用 NodeList 实现: ```javascript 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 记录客户端的用户信息。例如: ```javascript document.cookie="username=Max Tedder; userid=114514"; ``` 删除 Cookie 时,只需要把等号后的内容删除。例如: ```javascript document.cookie="username=; userid="; ``` 不过由于涉及 Cookie 的操作在现阶段用处不大,因此不做赘述。 --- 至此,JavaScript 的基本内容就讲解完毕了。