「学习笔记」Web 开发基础

HTML 入门

<head>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<head>
<meta charset="utf-8" />

<meta name="author" content="Chris Mills" />
<meta
name="description"
content="The MDN Web Docs site
provides information about Open Web technologies
including HTML, CSS, and APIs for both Web sites and
progressive web apps." />

<title>MDN Web Docs</title>

<link rel="icon" href="favicon.ico" type="image/x-icon" />
<link rel="stylesheet" href="my-css-file.css" />
<script src="my-js-file.js" defer></script>
</head>

效果:

效果

其中 <script> 里的 defer 是让浏览器加载完全部的 HTML 后再运行该脚本。

<ol> 和 <ul>

1
2
3
4
5
<ol>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ol>

输入

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
<input type="text" placeholder="请输入" />
<input type="password" placeholder="请输入密码" />
<input type="checkbox" />
<input type="submit" value="提交" />
<input type="reset" value="重置" />
<input type="button" value="按钮" />
<input type="file" />
<input type="hidden" />
<input type="image" />
<input type="color" />
<input type="date" />

<button onclick="displayHi()">按钮文字</button>

/*
类型:
* onclick
* onchange
* onload
* onkeydown
* onmouseover
* onmouseout
*/


CSS 入门

清除性模板

1
2
3
4
5
6
7
* {
text-decoration: none;
color: black;
box-sizing: border-box;
margin: 0;
padding: 0;
}

盒模型

标准盒:

替代盒(常用):

1
2
3
* {
box-sizing: border-box;
}

标准盒的 width 等于内容宽度,替代盒的 width 等于内容宽度、边框宽度和 padding 宽度的总和。

定位

  • position: static:默认跟随文档流
  • position: relative:相对于自身位置移动一点点,但是会占位
  • position: absolute:相对最近的非 static 祖先元素定位,不占位
  • position: fixed:相对视窗定位
  • position: sticky:正常显示时为 static,但如果滚动到相对容器的特定位置则变为 fixed(由 top, left, right, bottom 指定)

选择器速查表

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
26
27
a[attr^="value"] /* 以 value 开头 */
a[attr$="value"] /* 以 value 结尾 */
a[attr*="value"] /* 包含 value */


a:link /* 链接没有被访问过 */
a:visited /* 链接已被访问过 */
a:hover /* 鼠标移动到链接上 */
a:focus /* 鼠标点击链接时 */
a:active /* 链接正在被点击 */

input:required /* 必须填写 */
input:checked /* 选中 */
input:disabled /* 禁用 */

a:first-child /* 第一个 */
a:last-child /* 最后一个 */
a:nth-child(an + b | even | odd) /* 为父元素的第 an + b (n >= 0) 个,奇数个或偶数个儿子 */

a:first-of-type /* 同上,但是只计数 <a> */
a:last-of-type
a:nth-of-type(an + b | even | odd)

p::before /* 前面 */
p::after /* 后面 */
p::first-letter /* 第一个字 */
p::first-line /* 第一行 */

背景

1
2
3
4
5
6
7
8
.a {
background-color: #f0f0f0; /* 背景颜色 */
background-image: url("front.png"), url("bg.png"); /* 背景图片,前面的图片会放在后面的图片上 */
background-repeat: no-repeat | repeat-x | repeat-y | repeat; /* 背景图片重复,默认 repeat */
background-position: left top | 50% 50% | 0 0 | cover | contain; /* 背景图片位置,默认 0 0 */
background-size: 100px 100px | 50% 50% | cover | contain; /* 背景图片大小,默认 auto; cover 按 max(img_width, img_height) 放缩,contain 按 min(img_width, img_height) 放缩 */
background-attachment: scroll | fixed; /* 背景图片是否随滚动,默认 scroll */
}

颜色

1
2
3
4
5
6
7
#f0e1a6
rgb(2 35 125)
rgb(2 35 125 / .6)
hsl(120 100% 50%)
hsl(350 100% 50% / .6)
linear-gradient(90deg, rgb(119 0 255 / 39%), rgb(0 212 255 / 100%)) /* 从左到右,左边是第一个颜色,右边是第二个颜色;90deg 是逆时针旋转 */
linear-gradient(0deg, rgb(119 0 255 / 39%), rgb(0 212 255 / 100%)) /* 从上到下,上边是第一个颜色,下边是第二个颜色 */

媒体查询

1

min-width 和 max-width

用于响应式设计。min-width 属性表示最小宽度,限制 width 必定不小于 min-width

长度单位

  • px
  • em:本元素的 font-size
  • rem<html>font-size
  • vh / vw
    • vmin / vmax
  • %:相对父元素的大小

Javascript 入门

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
"use strict";


let a = "ab";
let b = {first: "John", last: "Doe", number: 584};
let c = [3, 7, , , 5]; // 中间是 undefined

console.log(b.first); // John
console.log(b["first"]); // John


let a = "string";
a.length // 6
a.constructor // 返回 a 的构造函数


let b = 35.13;
b.toString() // "35.13"
b.toString(2) // "100011.0010001010001111010111000010100011110101110000101"
b.toFixed(4) // "35.1300"
b.toExponential(4) // "3.5130e+1"
b.toPrecision(5) // "35.130"


let a;
console.log(a); // undefined
a = null;
console.log(a); // null


typeof [1, 2, 3, 4] // object
typeof false // boolean



`I am ${name}.`



switch (x) {
case 1:
// do sth
break;
case 2:
// do sth
break;
default:
// do sth
}


for (const x in arr) {
if (x instanceof Number) {
console.log(`${x} is number\n`); // 自动换行
}
}



str.search(/Runoob/i)
str.replace(/Runoob/i, "Google")
/Runoob/i.test(str) // Boolean
/Runoob/i.exec(str) // Array / String



try {
// 可能会出错的代码
throw "出错信息";
} catch (error) {
// 出错时执行的代码
} finally {
// 无论如何都会执行的代码
}

debugger; // 断点

数据类型

  • 数据类型:String, Number, Boolean, Object, Function, Symbol
  • 对象类型:Object, Date, Array
  • 其他:null, undefined

大数精度问题

在 $[-2^{53} + 1, 2^{53} - 1]$ 之间的整数可以精确表示,但过大的整数 / 任意小数难以精确表示。

可以考虑:

  1. parseFloat(res.toFixed(12)),缺点是大数仍然会出错;
  2. 将小数转为整数再除以 $10^k$(如 $0.1 \times 0.2 = 1 \times 2 \div 100$),缺点是大数可溢出;
  3. 转为字符串模拟计算。

bignumber.js,decimal.js,以及 big.js 采用第三种方案。

null 和 undefined

在 JavaScript 中, null 用于对象, undefined 用于变量,属性和方法。

对象只有被定义才有可能为 null,否则为 undefined。

如果我们想测试对象是否存在,在对象还没定义时将会抛出一个错误。

错误的使用方式:

1
if (myObj !== null && typeof myObj !== "undefined") 

正确的方式是我们需要先使用 typeof 来检测对象是否已定义:

1
if (typeof myObj !== "undefined" && myObj !== null) 

显式函数绑定

在 JavaScript 中函数也是对象,对象则有方法,apply 和 call 就是函数对象的方法。这两个方法异常强大,他们允许切换函数执行的上下文环境(context),即 this 绑定的对象。

在下面实例中,当我们使用 person2 作为参数来调用 person1.fullName 方法时, this 将指向 person2, 即便它是 person1 的方法:

1
2
3
4
5
6
7
8
9
10
var person1 = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person2 = {
firstName:"John",
lastName: "Doe",
}
person1.fullName.call(person2); // 返回 "John Doe"

json

1
2
let obj = JSON.parse(json);
let json = JSON.stringify(obj);

javascript:void(0)

void(func) 会使用 js 计算 func,但返回的值固定为 undefined

1
2
<a href="javascript:void(0)">死链接</a>
<a href="javascript:void(alert('hi!'))">点了就会和你打招呼的链接</a>

arguments

相当于 python 里的 args。

1
2
3
4
5
6
function sumAll() {
var i, sum = 0;
for (i = 0; i < arguments.length; i++)
sum += arguments[i];
return sum;
}

正则表达式入门

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
26
27
28
29
30
\d{4} // 4 个数字
a{3,5} // 3 到 5 个 a

(first)-\1, (second)-\2 // \1 表示第一个括号匹配的内容,\2 表示第二个括号匹配的内容
(?:first), (second)-\1 // (?:) 表示不捕获,\1 实际上是 second

(c|r)at|dog

^string // 以 string 开头
string$ // 以 string 结尾

\w // 匹配字母、数字、下划线
\d // 匹配数字
\s // 匹配空白字符

[0-9]{1,2}(?=PM) // 后面必须带 PM,但 PM 不会被匹配进来
[0-9]{1,2}(?!PM) // 后面不能带 PM
(?<=\$)\d+ // 前面必须带 $
(?<!\$)\d+ // 前面不能带 $

/ ... /g // 表示可以多次匹配
/ ... /m // 表示多行匹配
/ ... /i // 表示忽略大小写

// 贪心匹配:默认尽可能多地匹配

.*? // 非贪心匹配
.*?r

\w+@[a-z|0-9]+\.[a-z]+

Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const a = new Promise((resolve, reject) => {
if (true) {
resolve("success");
} else {
reject("fail");
}
});

a.then((res) => {
console.log(res);
}).catch((err) => {
console.log(err);
}).finally(() => {
console.log("finished");
});

const b = new Promise((resolve, reject) => {
resolve(a);
})

注意:resolve, reject 不会暂停该 Promise 的运行,例如若 resolve(a); console.log("hi"); 则根本不会等待 a 变为 fulfilled 就直接输出 hi

闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const pack = (() => {
let val = 0;
let setVal;
let getVal;

setVal = (newVal) => {
val = newVal;
return {setVal: setVal, getVal: getVal};
};
getVal = () => val;
return {setVal: setVal, getVal: getVal};
})()

pack.setVal(7);
console.log(pack.getVal());

1
2
3
4
5
6
7
8
9
10
11
12
class ClassName {
constructor(...) { ... }
method1() { ... }
static method2() { ... }
}

class Dog extends Animal {
constructor(...) {
super(...);
...
}
};

apply, call 和 bind

  • call:正常传参
  • apply:传入参数数组
  • bind:返回一个新函数,可以生成回调函数
1
2
3
4
5
func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2]);

const newFunc = func.bind(obj);
newFunc();

DOM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let element = document.getElementById("id");
let elements = document.getElementsByTagName("p");
// elements 为 HTMLCollection 对象,严格来说不是数组,没有 valueOf(), pop() 等
let myNodeList = document.querySelectorAll("p");

element.style.color = "red";
element.addEventListener("click", () => { alert("hi!"); });
element.addEventListener("click", () => { alert("hi!"); }, false); // useCapture, default = false
element.removeEventListener("click", () => { alert("hi!"); });


parent.appendChild(child);
parent.insertBefore(node, referenceNode);
parent.replaceChild(newNode, oldNode);
parent.removeChild(child); // or child.parentNode.removeChild(child);

事件冒泡和事件捕获

冒泡:里面先触发。可以看作从里往外,气泡不断向上级冒出的过程。

捕获:外面先触发。可以看作从外往里捕捉的过程。

展开和解构语法

1
2
[...a]              // 展开
[x, y] = [y, x + y] // 解构

迭代器和生成器

function* func(...) { ... } 来创建一个生成器,在生成器里写 yield valueyield* [value1, value2, ...] 可以卡住生成器并暂时返回该值。

let it = func(...) 来创建一个迭代器(**注意没有 new**),it.next().valueit.next().done 判断是否结束。

也可以直接使用 for-in 循环、[...it] 等语法展开。

也可以在 Person[Symbol.iterator] = function* () { ... } 里定义迭代器,使得该 object 支持迭代。

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function* makeRangeIterator(start = 0, end = Infinity, step = 1) {
let iterationCount = 0;
for (let i = start; i < end; i += step) {
iterationCount++;
yield i;
}
return iterationCount;
}

let it = makeRangeIterator(1, 10, 2); // 注意没有 new!

let result = it.next();
while (!result.done) {
console.log(result.value); // 1 3 5 7 9
result = it.next();
}

console.log(`已迭代序列的大小:${result.value}`); // 5

高级应用:带参数的 next()

yield value 也有返回值,会返回 it.next(arg) 中的参数 arg(可选)。

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
function* fibonacci() {
let current = 0;
let next = 1;
while (true) {
const reset = yield current;
[current, next] = [next, next + current];
if (reset) {
current = 0;
next = 1;
}
}
}

const sequence = fibonacci();
console.log(sequence.next().value); // 0
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
console.log(sequence.next().value); // 3
console.log(sequence.next().value); // 5
console.log(sequence.next().value); // 8
console.log(sequence.next(true).value); // 0
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2

模块

1
2
export { name as newName, func, func2 };
export name from "./sub.js";
1
2
3
import { newName, draw as newDraw, reportPerimeter } from "./module.js";
import * as Module from "./module.js";
// Module.draw()

在 HTML 中:

1
<script type="module" src="main.js"></script>

动态加载

import(path) 返回一个 Promise 对象,其 resolve 的返回值为 Module 本身,可以用 then 来处理 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
squareBtn.addEventListener("click", () => {
import("/js-examples/modules/dynamic-module-imports/modules/square.js").then(
(Module) => {
let square1 = new Module.Square(
myCanvas.ctx,
myCanvas.listId,
50,
50,
100,
"blue",
);
square1.draw();
square1.reportArea();
square1.reportPerimeter();
},
);
});

Prototype

一些细项

  • id = setInterval(fn, delay, ...args), clearInterval(id)

基本数据类型

Number

  • Number.parseInt
  • Number.parseFloat

String

  • String.fromCharCode / String.charCodeAt

  • String.match

  • String.indexOf / String.lastIndexOf

  • String.toUpperCase / String.toLowerCase

  • String.split

  • String.substring(begin, end) (等价于特殊判断的 String[begin:end]

    • begin > end 时会交换,当 begin < 0 时会取 0,当 end > len 时会取 len
  • Array.slice(begin, end)(可取负值)