2025-03-29 14:35:49 +08:00

1234 lines
30 KiB
Markdown
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 1-js
JavaScript 的组成:
* ECMAScript: 核心, 语言规范
* DOM: 文档对象模型
* BOM: 浏览器对象模型
## 数据类型
* 基本数据类型: string number Boolean null undefined symble bigInt
* 复杂数据类型: array object function date regexp set map Promise
null 和 undefined
* null 表示一个值被定义了,定义为"空值"
* undefined 表示根本不存在定义
### 基本数据类型是按值传递
> 传递的是===副本===, 不会修改原始数据
```js
function modifyValue(x) {
x = 10; // 修改副本
console.log(x); // 10
}
let a = 5;
modifyValue(a);
console.log(a); // 5原始值未改变
```
* 函数中不会修改传递进来的基本类型
* 需要修改, 要么全局变量
* 函数返回修改后值, 调用函数重新赋值
* 用对象/数组包装
### 复杂数据类型是按共享传递
> 传递的是内存地址的===副本===
> 如果是修改对象的属性, 会影响原始数据
> 如果是赋值, 不会影响原始数据
* 修改属性
```js
function modifyProperty(obj) {
obj.value = 10; // 修改对象的属性
console.log(obj.value); // 10
}
let myObj = { value: 5 };
modifyProperty(myObj);
console.log(myObj.value); // 10原始对象被修改
```
* 重新赋值
```js
function reassignReference(obj) {
obj = { value: 10 }; // 重新赋值引用副本
console.log(obj.value); // 10
}
let myObj = { value: 5 };
reassignReference(myObj);
console.log(myObj.value); // 5原始对象未被修改
```
## 栈, 堆
**栈**stack中主要存放一些**基本类型的变量和对象的引用**, 其优势是存取速度比堆要快,但缺点是存在栈中的数据大小与生存期必须是确定的,缺乏灵活性,**后进先出**, 就像盘子
**堆**heap )多用于复杂数据类型(**引用类型**分配空间例如数组对象、object 对象;它是运行时动态分配内存的,因此存取速度较慢。就像仓库, 需要索引
<img src="https://img.081024.xyz/20230321033721.png" alt="image-20200713144353620" />
## 分支语法
### if else
### switch-case
```js
switch (expression) {
case value1:
// 当 expression 的结果与 value1 匹配时,执行此处语句
[break;]
case value2:
// 当 expression 的结果与 value2 匹配时,执行此处语句
[break;]
...
case valueN:
// 当 expression 的结果与 valueN 匹配时,执行此处语句
[break;]
[default:
// 如果 expression 与上面的 value 值都不匹配,执行此处语句
[break;]]
}
```
* break 作用:结束该 switch 语句,所以一般情况下要加上,如果不加上则会发生穿透
* 穿透:从上一个 case 代码快执行到下一个 case 代码快
* 使用场景: 多中值执行同个代码块, 例如:
```js
case 1:
case 2:
console.log("1或2都打印")
break
```
### 三元表达式
```js
// 如果表达式成立则执行代码1否则执行代码2
表达式?代码1:代码2
```
* 一元运算符:只能操作一个值 `++` `--` `!`
* 二元运算符:操作两个值 `1 + 1` `1 > 0`
* 三元运算符:操作三个值
## 循环语法
### for
```js
for(i; i<10; i++){
}
```
### while
```js
while(条件 true/false){
循环体/需要重复执行的代码;
}
```
### do-while
```js
do{
循环体
}while(条件)
```
* do-while 和 while 实现的循环其实是一样的只有一个不同点do-while 循环不管怎样先执行一次循环体代码,然后再判断条件
## 创建对象的三种方式
### 字面量
> 直接赋值
```js
const obj = {name:"悟空",height:100,age:5000}
```
* 简单粗暴
* 不适合创建多个同样类型的对象的场景
### 工厂函数
> 函数返回
```js
function createPerson(name, age, height) {
return {
name: name,
age: age,
height: height
}
}
```
1. 容易理解
2. 失去`血缘关系`,无法简单分辨对象的特征
### 构造函数
> new
```markdown
构造函数的工作原理:
1. 开辟内存空间(堆)
2. 产生内部对象this
3. 初始化属性(执行构造函数)
4. 返回对象的内存地址
```
```js
// 1 声明函数
function CreateStudent(name, age) {
// 2 通过 this 赋值
this.name = name;
this.age = age;
}
// 3 通过 new 来创建对象
const obj = new CreateStudent("悟能", 83);
console.log(obj);
```
优点:
1. 可以方便的创建对象
2. 拥有血缘关系
3. 还有后续更多的优势
缺点:
1. 可能会浪费内存空间:在构造函数中给属性增加方法,会导致每个对象都会保存一份方法
解决: 将方法单独存储一份,让对象中的属性指向方法
```js
// 但造成了污染全局变量的问题
function myLog(){
console.log(1)
}
function Test(){
this.log= myLog
}
```
构造函数的本质就是函数, 但与普通函数不同:
1. 构造函数名字是大驼峰法(**首字母大写**
2. 会在函数体中直接使用thisthis就代表对象自己
3. 构造函数通常不需要给返回值:默认有返回值,是一个对象
## 定义函数的三种方式
### 声明式
> function 函数名 (){}
```js
fn()
function fn(参数..){
console.log("这是函数声明")
return 返回值
}
```
* ==函数声明可以先调用,再声明==
### 表达式
> const 函数名=function (){}
```js
const fn = function() {
console.log("这是函数表达式")
}
fn()
```
* ==函数表达式必须先声明,再调用==
### 构造函数
> new Function ()
```js
// Function是系统内置的一个构造函数
// 创建函数new Function(动态参数,都需要使用引号,最后一个参数代表函数体)
```
```js
const fn1 = new Function("a1", "a2", "alert(a1+a2)")
fn1(1,2)
```
## 高阶函数
### arguments 关键字
> 在函数内部使用, 获取所有的实参
```js
fucntion add(){
let sum = 0
for (let i = 0; i < arguments.length; i++){
let value = arguments[i]
if(isNaN(value)){
return false
}
sum += Number(value)
}
return sum
}
```
## 原型 prototype
> 当函数定义完毕,系统就会自动创建原型
* 原型本质是一个对象,理解为 `定义构造函数` 的时候, `JavaScript` 自动帮我们添加的
* 所有构造函数的实例,共享一个原型
* 原型上一般用来挂载函数
### 实例的`__proto__`属性
* 实例的 `__proto__` 属性 等于 构造函数的 `prototype`
* 实例的 `__proto__` 是非标准属性, 只是为了方便我们开发的时候查看数据
实际用来获取原型的方法
```js
const obj = {}
const proto = Object.getPrototypeOf(obj)
```
### 原型链
* ==所有的构造函数都是Function的实例==
* Object的顶端是 null `console.log(Object.prototype.__proto__ === null)`
* student 实例的 constructor 属性是从它的原型继承来的
![image-20201107122039097|655x801](https://img.081024.xyz/20230321055400.png)
### 使用
把属性或者方法挂到构造函数的原型上, 使得所有实例都能共享该属性或方法
```js
function CreateStu(name,age){
this.name=name
this.age=age
}
const stu1 = new CreateStu('张三', 18)
Object.getPrototypeOf(stu1).say = function(){
console.log('hello')
}
/**
//或者
stu1.__proro__.say = function(){
console.log('hello')
}
// 或者
stu1.constructor.prototype.say = function(){
console.log('hello')
}
*/
const stu2 = new CreateStu('李四', 20)
stu2.say()
```
## 作用域
> 作用域有三种: 全局作用域global, 局部作用域local, 块级作用域block
* 全局作用域: 函数外部的作用域
* 全局变量: 可以在任意地方使用, 如果页面不关闭,那么变量所占用的内存就不会释放,就会占空间,消耗内存
* 局部作用域: 函数内部的作用域
* 局部变量:在函数内部使用
* 块级作用域: 使用一对大括号包裹的一段代码
* es6中新增 let const
* ==var声明的变量会产生变量提升,没有块的概念, 可以跨块访问, 不能跨函数访问==
* let 和 const定义的变量是有块级作用域的只能在当前块作用域访问
## 函数的四种调用模式与this
> 根据函数内部this的指向不同可以将函数的调用模式分成4种
1. 函数调用模式
2. 方法调用模式
3. 构造函数调用模式
4. 上下文调用模式(借用方法模式)
### 函数调用模式
如果一个函数不是一个对象的属性时就是被当做一个函数来进行调用的。此时this指向了window
```js
function fn(){
console.log(this) // 指向window
}
fn()
```
### 方法调用模式
当一个函数被保存为对象的一个属性时我们称之为一个方法。当一个方法被调用时this被绑定到当前对象
```js
const obj = {
sayHi:function(){
console.log(this) //在方法调用模式中this指向调用当前方法的对象。
}
}
obj.sayHi()
```
* 简写
```js
const obj = {
sayHi(){
console.log(this)
}
}
obj.sayHi()
```
### 构造函数调用模式
如果函数是通过new关键字进行调用的此时this被绑定到创建出来的新对象上
```js
function Person(){
console.log(this)
}
Person() //this指向window
let p = new Person() //this指向Person
```
### 方法借用模式/上下文模式
> apply, bind, call, 可以改变this
```js
/** apply 、bind、call 这三个函数的第一个参数都是 this 的指向对象,第二个参数差别就来了:
** apply 所有参数都必须放在一个数组里
** bind 参数用逗号隔开,返回是函数需要执行
** call 参数用逗号分隔
apply call 立刻调用, bind 返回函数可以延迟执行
**/
```
```js
const name = '小王', age=17
const obj = {
name: '小张',
objAge: this.age,
myFun: function(fm, t){
console.log(this.name + '年龄' + this.age, "来自" + fm + "去往" + t)
}
}
const db = {
name = '德玛',
age: 99
}
obj.myFun.apply(db,['成都','上海']); // 德玛 年龄 99 来自 成都去往上海
obj.myFun.bind(db,'成都','上海')(); // 德玛 年龄 99 来自 成都去往上海, bind返回的是个函数
obj.myFun.call(db,'成都','上海')    // 德玛 年龄 99 来自 成都去往上海
```
## this
* 单独使用,`this` 指向全局对象
```js
console.log(this) // window
```
* 在函数内部,`this` 的指向在函数定义的时候是不能确定的,**只有函数执行的时候才能确定**
* 谁调用它, 就指向谁
```js
function show(){
console.log(this) // window
}
show()
```
```js
const a = 18
const obj = {
a: 19,
b: {
a: 20,
c: function () {
console.log(this.a)
}
}
}
obj.b.c() // 20
```
* 在方法中,`this` 指代该调用方法的对象
```js
const obj ={
name:"小白",
say:function(){
console.log(this)
}
}
obj.say() // {name:"小白",say:f}
```
* 箭头函数: 箭头函数自己没有this, this向上级找
```js
//箭头函数没有funtion关键字, 所以里面没有this关键字
//浏览器断点调试,可以发现this是undefined
//箭头函数中非要用this, this向上级找
let obj = {
fn1: function () {
console.log('我是function函数输出的this: ', this)
},
fn2: () => console.log('我是箭头函数输出的this: ', this)
}
obj.fn1() //输出obj, function函数中, 谁调用函数, this指的就是谁
obj.fn2() //输出windows, 箭头函数不会产生this, 向上找, obj是个对象, 再向上就是window
```
* 借调函数不能改变箭头函数里面的this
* 要改变this, 可以通过改变它的上级
## 判断对象属于哪个构造函数
> instanceof, constructor, typeof
```js
let arr = [1, 2, 3]
console.log(arr instanceof Array) //true
```
```js
console.log(arr.constructor === Array) //true
//arr没有constructor, 就向上到它的原型找 arr.__proto__.constructor
```
```js
//typeof 可以找到基础数据类型, 数组,对象, 函数都不准确, 输出object
console.log(typeof (a)); //number
console.log(typeof (arr)); //object
```
## 对象的键使用变量
```js
//在键使用中括号的时候, 可以设为变量
const key = test
const obj = {[key]: 'a'}
console.log(obj) // {test: 'a'}
```
## 内置对象的方法
### Array
```js
let c = a.concat(b) // 连接两个或多个数组
let b = [1, 2, 3].join() // 拼接成字符串
a.shift() // 删除第一个元素, 返回第一个元素的值
a.unshift('the', 'start') // 往头部插入一个或多个, 返回新的长度
a.pop() // 删除最后一个元素, 返回被删除元素的值
a.push('the','end') // 往最后插入一个或多个, 返回新的长度
a.splice(index, howmany , item1 , ..... , itemX) // 删除或添加元素.
// 第一个参数是开始的位置
// 删除的数量, 不写则删除index到结尾, 可以是0
// 后面的是要插入的元素
// 如果删除了元素, 则返回的是含有被删除元素的数组
let b = a.slice(start, end) // 切片, 截取一部分, 浅拷贝
let value = a.find((value, index) => return value > 18) // 返回第一个满足条件的元素, 没有符合的返回undefined
let index = a.findIndex((value, index) => return value > 18) // 返回第应该满足条件的元素的下标, 没有符合的返回-1
let index = a.indexOf('test', 0) // 从头开始找, 是否能找到该元素, 找到返回第一次出现的下标, 没有返回-1. 第二个参数是开始找的位置, 默认是下标0可以不写
let index = a.lastIndexOf('test', a.length - 1) // 从结尾往前找, 是否能找到该元素, 找到返回第一次出现的下标, 没有返回-1. 第二个参数是开始找的位置, 默认是数组的长度减1可以不写
let boolean = a.some((value, index) => value > 18) // 满足条件返回true
a.sort() // 排序, 小到大
a.sort((a, b) => a - b) // 小到大
a.sort((a, b) => b - a) // 大到小
a.reverse() // 颠倒顺序
// 遍历
a.forEach((value, index) => {
console.log(`下标${index}, 值为${value}`)
})
// 过滤
let b = a.filter((value, index)=>{
return value > 0
})
// 映射
let b = a.map((value, index)=>{
return value + 1
})
```
### string 方法
```js
let len = str.length()
let newStr = str.replace('a', 'b') // 字符替换替换
let uStr = str.toUpperCase() // 全大写
let lStr = str.toLowerCase() // 全小写
let index = str.indexOf('a') // 某个字符首次出现的位置, 没有找到返回 -1
let arr = "a,b,c,d,e".split(","); // 转数组, 按逗号分隔
str.trim() // 移除两端空格
let str2 = str.substring(indexStart [, indexEnd]) // 截取部分
```
### math 方法
```js
Math.ceil(数字) // 向上取整
Math.floor(数字) // 向下取整
Math.max(数字1,数字2,...) // 求最大值
Math.min(数字1,数字2,...) // 求最小值
Math.random() // 返回 (0,1) 之间的小数
Math.abs(数字) // 绝对值
```
### regexp 方法
```js
// 创建
let re = new RegExp("\\w+");
let re = /\w+/;
let str="Is this all there is?";
let patt1=/is/gi; // 修饰符, g全局, i忽略大小写
part1.test(str) // test方法, 满足时返回true
```
## 编码解码
```js
encodeURI(URI) // 对整个 URI 进行编码, 不会编码 URI 中的保留字符(如 :、/、?、&、= 等)
decodeURI(encoded)
const uri = 'https://example.com/path?name=John Doe';
const encodedURI = encodeURI(uri);
console.log(encodedURI); // 输出: https://example.com/path?name=John%20Doe
```
```js
encodeURIComponent(str) // 对 URI 的组件(如查询参数)进行编码
decodeURIComponent(encodedURI)
const param = 'name=John Doe';
const encodedParam = encodeURIComponent(param);
console.log(encodedParam); // 输出: name%3DJohn%20Doe
```
## 闭包
> 函数能够记住并访问它被创建时的作用域,即使这个函数在作用域之外执行
```js
function outer() {
let x = 10; // outer 函数的局部变量
function inner() {
console.log(x); // inner 函数访问 outer 函数的局部变量
}
return inner;
}
const closureFunc = outer(); // outer 函数执行完毕,但 x 仍然被 inner 函数记住
closureFunc(); // 输出: 10
```
1. **函数**:闭包的核心是一个函数(如 `inner`)。
2. **作用域**:这个函数能够访问它被创建时的作用域(如 `outer` 函数中的 `x`)。
3. **记忆**:即使外部函数(如 `outer`)已经执行完毕,闭包仍然可以访问它的作用域。
闭包可以用于:
* 创建私有变量。
* 实现函数柯里化Currying
* 柯里化: 一个函数 f(a, b, c) 转换为 f(a)(b)(c) 的形式
* 在异步编程中保留上下文。
缺点:
* 可能带来内存泄漏
* 额外的内存开销和性能损耗
解决:
* 及时释放 = null
使用:
* 防抖
* 下载任务
## reduce
会循环当前的数组, 侧重于 "滚雪球"
```js
// 语法
数组.reduce((val, item)=>{return ...}, 初始值)
// 把每次 函数体的结果, 返回到val里, 参与下次滚雪球
// 始始值只在第一次时使用
const arr = [1, 2, 3, 4, 5]
const total = arr.reduce((val, item)=>{return val + item}, 0)
console.log(total)
```
## DOM
### script 标签进阶
#### type=importmap 导入映射
```js
<script type="importmap">
{
"imports": {
"shapes": "./shapes/square.js",
"shapes/square": "./modules/shapes/square.js",
"https://example.com/shapes/square.js": "./shapes/square.js",
"https://example.com/shapes/": "/shapes/square/",
"../shapes/square": "./shapes/square.js"
}
}
</script>
```
* **`<script type="importmap">`**:定义了一个 import map类型为 `importmap`。浏览器会解析这个 JSON 对象,并在后续的模块导入过程中使用这些映射。
* **`"imports"`**:这是 import map 的主要部分,用于定义模块的映射关系。
兼容性: chrome >= 89, firefox >=108, safari >=16.4
#### type=module
ES Module 格式
```html
<script type="module" src="main.js"></script>
```
```js
<script type="module">
import { greet } from './greet.js';
greet('World');
</script>
```
* 模块脚本默认是延迟执行的,类似于 `<script defer>`。它们会在 HTML 文档解析完成后按顺序执行,不会阻塞页面渲染。
* 如果需要动态加载模块,可以使用 import () 函数。它返回一个 Promise可以在运行时加载模块。
```js
// 动态加载模块
if (condition) {
import('./greet.js').then((module) => {
module.greet('World');
});
}
```
### getElementBy与querySelector
`getElementBy` 方法返回的结果是 `HTMLCollection`,是动态的, 以后每一次在Javascript函数中使用这个变量的时候都会再去访问一下这个变量对应的html元素, 性能比较好
`querySelector` 方法返回的结果是 `NodeList`, 选出来的元素及元素数组是静态的,不会随着文档操作而改变, 使用比较方便
### 设置带-的样式
用 js 设置样式时, 如果样式的属性有 `-`, 则应该转换成大驼峰
### attribute 标签的属性
> 用 . 语法更加简单, 但无法删除属性名
* 获取属性:元素.getAttribute ( "id" )
* 设置属性:元素.setAttribute('属性名',属性值)
* 删除属性:元素.removeAttribute('属性名')
无法获取的属性:
* 行外属性
* 不属性标签标准属性的自定义属性
### 节点和元素
> **节点** 是 DOM 树中的基本单位,代表 DOM 中的任何对象, 可以是元素、文本、注释、属性等
> **元素** 是节点的一种特定类型,表示 HTML 或 XML 文档中的标签
* 节点
```js
.childNodes 子节点
.firstChild 第一个子节点
.lastChild 最后一个子节点
.nextSibling 下一个节点
.previousSibling 上一个节点
.parentNode 元素的父节点, 一定是一个元素, 只有元素才有子节点
```
* 元素
```js
.children 子元素, 是动态的 HTMLCollection
.firstElementChild 第一个子元素
.lastElementChild 最后一个子元素
.previousElementSibling 上一个兄弟元素
.nextElementSibling 下一个兄弟元素
```
#### 增删改
| 语法 | 示例 | 描述 |
| ------------------------ | ---------------------------- | ------------- |
| document.createElement() | document.createElement('li') | 创建空标签元素 |
| 父元素.appendChild(子元素) | ul.appendChild(li) | 添加子元素 |
| 父元素.insertBefore(子元素) | ul.insertBefore(元素A元素B) | 将元素A插入到元素B的前面 |
| 父元素.replaceChild(子元素) | ul.replaceChild(元素A元素B) | 元素A替换元素B |
| 父元素.removeChild(子元素) | ul.removeChild(li) | 移除子元素 |
#### 克隆
```js
元素.cloneNode(布尔)
false默认浅克隆
true深克隆
```
### 事件的注册
事件的三要数: 事件源, 事件类型, 处理函数
```js
box.onclick = function () {
alert('单击事件')
};
```
常见的事件: onclick, dblclick, onmouseover, onmouseout
### 事件监听
| 特性 | 事件注册(`on` 属性) | 事件监听(`addEventListener` |
| ------ | ------------------- | --------------------------- |
| 绑定方式 | 直接为 `on` 属性赋值 | 使用 `addEventListener` 方法 |
| 多个处理函数 | 不支持,后赋值的函数会覆盖之前的函数 | 支持,可以为同一个事件绑定多个处理函数 |
| 事件阶段 | 仅支持冒泡阶段 | 支持捕获和冒泡阶段(通过第三个参数控制) |
| 移除事件 | 将 `on` 属性赋值为 `null` | 使用 `removeEventListener` 方法 |
* 注册事件
```js
element.addEventListerner(type, fn [, option])
// 第三个参数如果是布尔值: 默认false, 冒泡阶段进行true 捕获阶段进行
// 如果是对象
// `capture`(布尔值):是否在捕获阶段执行事件处理函数(默认 `false`)。
// `once`(布尔值):事件处理函数是否只执行一次(默认 `false`)。
// `passive`(布尔值):是否忽略事件处理函数中的 `preventDefault()`(默认 `false`)。改善滚屏性能
// `signal``AbortSignal`):用于移除事件监听器的信号。
```
冒泡: 从里往外传递, 直到 windows
* 当一个元素接收到事件的时候会把他接收到的事件传给父级一直传到window (注意这里传递的仅仅是事件并不传递所绑定的事件函数。所以如果父级没有绑定事件函数,就算传递了事件也不会有什么表现但事件确实传递了。)
* 利用: 事件委托, 在外层监听, 减少数量; 通过e.target拿到触发事件的元素
捕获: 从外往里传递
* 移除事件
```js
element.removeEventListener()
```
* 手动触发事件
```js
element.dispatchEvent(event)
```
* 阻止事件的默认行为/传播
```js
event.preventDefault(); // 阻止默认行为
event.stopPropagation(); // 阻止事件传播
```
### offset 获取真实高宽和位置
```js
/* offsetWidth与offsetHeight获取的是元素的实际宽高 = width + border + padding
1.可以获取行内及内嵌的宽高
2.获取到的值是一个number类型不带单位
3.获取的宽高包含border和padding
4.只能读取,不能设置
*/
element.offsetWidth
element.offsetHeight
```
```js
/* offsetParent:获取最近的定位父元素 (自己定位参照的父元素)
1.如果元素自身是固定定位则定位父级是null
2.如果元素自身是非固定定位,并且所有的父元素都没有定位那么他的定位父级是body
3.body的定位父级是null
*/
element.offsetParent
```
```js
/*
offsetLeft: 元素的 border 左边最外一条边 到其 最近定位父元素的 padding 左边一条边 的距离
offsetTop: 元素的 border 上边最外一条边 到其 最近定位父元素的 padding 上边一条边 的距离
*/
element.offsetLeft
element.offsetTop
```
![|400x293](https://img.081024.xyz/1-js-1741942324566.png)
![|401x293](https://img.081024.xyz/1-js-1741942361708.png)
![|426x439](https://img.081024.xyz/1-js-1741942415121.png)
### requestAnimationFrame
> 1. 屏幕刷新时(通常是60hz)更新动画, 优化性能
> 2. 运行在后台或者 `<iframe>` 会停止工作
```js
requestAnimationFrame(callback)
```
```js
// 使用 setTimeout 实现动画
function animateTimeout() {
// 动画逻辑
setTimeout(animateTimeout, 1000 / 60); // 手动设置帧率
}
animateTimeout();
// 使用 requestAnimationFrame 实现动画
function animateRAF() {
// 动画逻辑
requestAnimationFrame(animateRAF); // 自动优化帧率
}
animateRAF();
```
## BOM
### window 窗口对象
> 指当前浏览器窗口, js 中的顶级对象
* 常用方法
```js
// window可以省略
window.alert()
window.open()
window.close()
```
* 事件
```js
window.onload = fn // 界面上的内容加载完毕触发
window.onbeforeunload = fn // 界面关闭前触发
window.onunload = fn // 关闭的那一瞬间触发
```
### location 地址栏
> 包含 url 信息
* 常用的方法
```js
location.assign('你要打开的新网页的url')
location.replace('要替换的网页url')
location.reload()
```
### history 历史记录
```js
history.forward()
history.backup()
```
### navigator 浏览器信息
```js
console.log ( navigator );//navigator对象
console.log ( navigator.appVersion ); //当前浏览器版本信息
console.log ( navigator.platform ); //当前浏览器的硬件平台
console.log ( navigator.userAgent ); //当前浏览器信息
```
### screen 屏幕信息
```js
screen.width // 屏幕宽度
screen.height // 屏幕高度
screen.availWidth // 可用宽度
screen.availHeight // 可用高读
```
如果要获取视口的宽高 `window.innerWidth` `window.innerHeight`
## web apis
### web storage api
#### localStorage
> 容量通常为 5 mb
> sessionStorage 也是 5 mb
> cookies 4 k
```js
localStorage.setItem(key, value)
localStorage.getItem(key)
locclStorage.removeItem(key)
locclStorage.clear()
```
#### sessionStorage
* 页面会话结束时被清除
* 每个标签页都有独立的 `sessionStorage`, 即使他们的 url 相同
### indexDB
> 空间
* 异步操作, 不会阻塞主线程
* 键值存储, 支持复杂数据类型
* 事务支持: 事务更新是指将多个数据库操作(如插入、更新、删除)组合成一个逻辑单元,确保这些操作要么全部成功,要么全部失败
* 大容量:
* Safari: 1 G
* firefox: 2 G
* chrome: 单域名 60% 磁盘空间, 总 80%
#### 打开数据库
```js
const request = indexedDB.open("MyDatabase", 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
// 创建对象存储空间(类似于表)
if (!db.objectStoreNames.contains("users")) {
db.createObjectStore("users", { keyPath: "id" });
}
};
request.onsuccess = (event) => {
const db = event.target.result;
console.log("数据库打开成功");
};
request.onerror = (event) => {
console.error("数据库打开失败", event.target.error);
};
```
#### 添加数据
* 通过事务向对象存储空间添加数据
```js
const transaction = db.transaction("users", "readwrite");
const store = transaction.objectStore("users");
const user = { id: 1, name: "John", age: 25 };
const request = store.add(user);
request.onsuccess = () => {
console.log("数据添加成功");
};
request.onerror = (event) => {
console.error("数据添加失败", event.target.error);
};
```
#### 读取数据
```js
const transaction = db.transaction("users", "readonly");
const store = transaction.objectStore("users");
const request = store.get(1); // 根据主键读取数据
request.onsuccess = () => {
const user = request.result;
console.log("读取数据成功", user);
};
request.onerror = (event) => {
console.error("读取数据失败", event.target.error);
};
```
### 更新数据
```js
const transaction = db.transaction("users", "readwrite");
const store = transaction.objectStore("users");
const user = { id: 1, name: "John", age: 30 }; // 更新 age
const request = store.put(user);
request.onsuccess = () => {
console.log("数据更新成功");
};
request.onerror = (event) => {
console.error("数据更新失败", event.target.error);
};
```
#### 删除数据
```js
const transaction = db.transaction("users", "readwrite");
const store = transaction.objectStore("users");
const request = store.delete(1); // 根据主键删除数据
request.onsuccess = () => {
console.log("数据删除成功");
};
request.onerror = (event) => {
console.error("数据删除失败", event.target.error);
};
```
### fetch api
### websocket api
另建笔记
### URLSearchParams
https://developer.mozilla.org/zh-CN/docs/Web/API/URLSearchParams
URLSearchParams 是处理 URL 上的参数串的,主要处理形如 AAA=BBB&CCC=DDD 这部分内容,看个简单用法:
```js
let searchParam=new URLSearchParams('aaa=bbb&ccc=ddd')
searchParam.get('aaa');//结果:bbb
```
配合 location 的用法,一般是先取出 location. searchlet searchParam=new URLSearchParams (location.search.substr (1))。
**主要用法**
has, get, getAll
```js
let searchParam=new URLSearchParams('aaa=bbb&ccc=ddd&aaa=kkk')searchParam.has('ccc');//truesearchParam.get('aaa');//bbbsearchParam.getAll('aaa');//[bbb,kkk]
```
toString, append, set, delete
```js
let searchParam=new URLSearchParams('aaa=bbb&ccc=ddd&aaa=kkk')searchParam.delete('aaa');//删除aaa的keysearchParam.toString();//ccc=dddsearchParam.append('eee','fff');//增加eee=fffsearchParam.toString();//ccc=ddd&eee=fffsearchParam.set('ccc','kkk');//设置ccc=kkksearchParam.toString();//ccc=kkk&eee=fff
```
entries, values, keys
```js
let searchParam=new URLSearchParams('aaa=bbb&ccc=ddd');[...searchParam.entries()];//[[aaa,bbb],[ccc,ddd]][...searchParam.values()];//[bbb,ddd][...searchParam.keys()];//[aaa,ccc]
```
## json的格式
除了对象格式, 还有数组格式, 布尔值, 数字, 字符串, null
```js
console.log(JSON.parse(JSON.stringify([1,2,3])))
console.log(JSON.parse(JSON.stringify(123)))
console.log(JSON.parse(JSON.stringify('abc')))
console.log(JSON.parse(JSON.stringify(null)))
```