JavaScript Note

JavaScript Note

Falling_Sakura HaHa

Note 记录学习过程中遇到的一些问题,学到哪里便记到哪里,不适合作为系统学习的参考,持续更新。

Basic

变量和常量

var 为全局作用域,可以理解为所有的 var 相当于都出现在文件开头,在全局内都有效。

let 为块级作用域。

举个例子:

1
2
3
console.log(a ,b);
var a = 1
let b = 1

这段代码中,b 会报错,而 a 不会。

const 为常量,不可修改,需要在初始化时声明数值。。

对象

1
2
3
const ob = {
[key]: [value],
};

对象的 key 可以是字符串、非字符串(会转换为字符串),符号。

通常对象的键不可以是函数,我们可以把函数转化为相应的字符串,或者使用 Map 数据结构。

数组

以创建一个长度为 num 且初始化全部是 0 为例子。

fill

1
2
3
let num = 10; // 假设数组长度为 10
let arr = new Array(num).fill(0);
console.log(arr); // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

from

1
2
3
let num = 10; // 假设数组长度为 10
let arr = Array.from({ length: num }, () => 0);
console.log(arr); // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Array.from() 可以将一个类数组对象转化为数组,这个对象需要有 length 属性,否则数组长度将为 0

示例

1
2
3
let arr = {1: '1', 2: 'haha', 3: 3, 'length': 10};

const a = Array.from(arr);

for

朴素的 for 循环,这里就不献丑了。

function

简单声明

1
2
3
4
5
function 函数名(参数1, 参数2, ...) {
// 函数体
// 执行一些操作
return 返回值;
}

示例:

1
2
3
4
5
6
function greet(name) {
return "Hello, " + name + "!";
}

console.log(greet("Alice")); // 输出: Hello, Alice!

也可以赋值给一个变量:

1
2
3
4
const 函数名 = function(参数1, 参数2, ...) {
// 函数体
return 返回值;
};

示例:

1
2
3
4
5
const greet = function(name) {
return "Hello, " + name + "!";
};

console.log(greet("Bob")); // 输出: Hello, Bob!

也可以使用 ES6 引入的箭头函数

1
2
3
4
const 函数名 = (参数1, 参数2, ...) => {
// 函数体
return 返回值;
};

如果只有一个表达式,那么可以进一步简化(省略 return):

1
const 函数名 = (参数1, 参数2, ...) => 返回值;

箭头前是函数的形参,箭头后是函数体(返回值)。

示例:

1
2
3
4
5
6
7
8
const greet = (name) => {
return "Hello, " + name + "!";
};

// 简化形式
const greet = name => "Hello, " + name + "!";

console.log(greet("Charlie")); // 输出: Hello, Charlie!

箭头函数只能被赋值给一个变量,或者作为其它表达式的一部分。

高阶函数

接受一个/多个函数作为参数,或者返回一个函数的函数。

示例:

1
2
3
4
5
6
7
const createMultiplier = multiplier => number => number * multiplier;

const double = createMultiplier(2);
console.log(double(5)); // 输出: 10

const triple = createMultiplier(3);
console.log(triple(5)); // 输出: 15

解释

  • createMultiplier 是一个高阶函数,它接受一个参数 multiplier
  • 它返回一个新的箭头函数 number => number * multiplier
  • 返回的函数接收一个参数 number,并返回 numbermultiplier 的乘积。
  1. 接受函数作为参数
1
2
3
4
5
6
7
const numbers = [1, 2, 3, 4, 5];

const isEven = num => num % 2 === 0;

const evenNumbers = numbers.filter(isEven);

console.log(evenNumbers); // 输出: [2, 4]
  • filter 方法接受一个回调函数 isEven,该函数判断一个数是否为偶数。
  • filter 方法遍历 numbers 数组,并返回所有使回调函数返回 true 的元素组成的新数组。
  1. 一个简单的缓存函数

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const cacheFunction = fn => {
const cache = {};
return (...args) => {
const key = JSON.stringify(args);
if (!cache[key]) {
cache[key] = fn(...args);
}
return cache[key];
};
};

const add = (a, b) => a + b;
const cachedAdd = cacheFunction(add);
console.log(cachedAdd(1, 2)); // 输出: 3
console.log(cachedAdd(1, 2)); // 输出: 3(从缓存中获取)

详细解释一下这个缓存函数:

  • cacheFunction 是一个高阶函数,接受一个函数 fn 作为参数。
  • cache = {} 是用来初始化一个空对象,用于存储函数的计算结果。这个对象的键是函数参数的字符串表示(通过剩余参数将所有参数存入一个数组中,然后将这个数组转化为 JSON 字符串,作为 cache 对象的键),值是函数执行的结果。
  • 它返回一个新的函数,该函数使用一个对象 cache 来存储计算结果。
  • 当调用返回的函数时,它会先检查 cache 中是否有结果,如果没有则计算并存储结果。

剩余参数

1
...name

表示函数的可变参数,所有传入的参数收集到一个 name 数组中。

1
2
3
4
5
const exampleFunction = (...args) => {
console.log(args);
};

exampleFunction(1, 2, 3); // 输出: [1, 2, 3]

如本例中的 args 数组就是 [1, 2, 3]

函数提升

函数在声明之前可以被调用,但是函数表达式不可以。

1
2
3
4
5
6
7
8
9
10
11
console.log(sayHello()); // 输出: Hello, World!

function sayHello() {
return "Hello, World!";
}

console.log(sayHello()); // 报错: sayHello is not defined

var sayHello = function() {
return "Hello, World!";
};

可选参数

在对应参数名后面加上问号即可,所有可选参数需要放在尾部。

也可以通过设置默认值,这样可以写在头部。(不建议)

常用方法

map

1
const newArray = array.map(callback(currentValue[, index[, array]])[, thisArg])

该方法对数组中的每个元素调用一次函数,得到的返回值作为新的数组值,最后得到一个新数组。

  • callback:用于生成新数组元素的函数,接受三个参数:
    • currentValue:当前正在处理的元素。
    • index(可选):当前正在处理的元素的索引。
    • array(可选):map 方法被调用的数组。
  • thisArg(可选):执行回调时用作 this 值的对象。

示例:

1
2
3
4
5
6
const numbers = [1, 2, 3, 4, 5];

// 使用箭头函数作为回调函数
const doubled = numbers.map(num => num * 2);

console.log(doubled); // 输出: [2, 4, 6, 8, 10]
1
2
3
4
5
6
7
8
9
const users = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 },
{ name: "Charlie", age: 35 }
];

const userNames = users.map(user => user.name);

console.log(userNames); // 输出: ["Alice", "Bob", "Charlie"]

filter

用于数组,创建一个新数组。

1
const newArray = array.filter(callback(element[, index[, array]])[, thisArg])

新数组将包含通过 callback 测试的元素。

setTimeout

1
setTimeout(() => {}, [time]);

[time] 为毫秒级单位,第一个参数是要执行的函数,第二个参数是延迟执行的时间。

如果要停止它:

1
2
let fn = setTimeout(...);
clearTimeout(fn);

setInterval

按照一定时间间隔重复执行某个函数。

1
setInterval(callback, delay, ...args);

参数分别为:函数,时间间隔,传递给函数的附加参数(可选)。

如果要停止它:

1
2
let fn = setInterval(...);
clearInterval(fn);

splice

1
array.splice(index, x);

删除这个数组中从下标 index 开始的 x 项。

reduce

数组对象的一个方法,对数组中的每个元素依次执行回调函数,并将所有的结果以某种方式累积为一个值。

1
array.reduce(callback(accumulator, currentValue, currentIndex, array), initialValue)

accumulator 累积所有结果,currentValue 是当前正在处理的元素。

currentIndex(可选)是当前正在处理的元素的索引。

array(可选)是当前数组。

initialValue(可选) 是 accumulator 的初始值。若没有,则以数组第一个元素为初始值,从第二个元素开始执行回调函数。

示例:数组求和

1
2
3
4
5
6
7
const numbers = [1, 2, 3, 4, 5];

const sum = numbers.reduce((accumulator, currentValue) => {
return accumulator + currentValue;
}, 0);

console.log(sum); // 输出 15

split

将一个字符串分割为子字符串数组。

1
string.split(separator, limit)
  • separator:必选,分割符(可以是字符串或者正则表达式)。
  • limit:可选,最多返回几个字符。

join

用于将一个数组内的全部元素都转变为字符串并用指定分隔符将它们连接成一个字符串作为返回值。

1
array.join(separator)

常用属性

innerHTML

innerHTML 属性用于获取或设置元素的 HTML 内容。它会将元素内部的所有 HTML 标签和文本内容作为一个字符串返回或设置。这意味着你可以使用 innerHTML 动态地插入 HTML 结构。

innerText

innerText 属性用于获取或设置元素的文本内容。它会忽略任何 HTML 标签,只返回或设置纯文本。这意味着 innerText 只会处理可见的文本内容,而不会包含任何 HTML 标签或嵌套结构。

DOM

CSS 选择器的区别

  1. .container > .panel

    • 选择所有直接子元素 .panel,它们的父元素是 .container
    • 示例:
1
2
3
4
5
6
<div class="container">
<div class="panel">直接子元素</div>
<div>
<div class="panel">不是直接子元素</div>
</div>
</div>

仅选择第一个 div.panel,因为它是 div.container 的直接子元素。

  1. .container .panel

    • 选择所有后代元素 .panel,它们位于 .container 内部,无论层级如何。
    • 示例:
1
2
3
4
5
6
7
<div class="container">
<div class="panel">直接子元素</div>
<div>
<div class="panel">嵌套的子元素</div>
</div>
</div>

选择两个 div.panel,因为它们都是 div.container 的后代元素。

  1. .container.panel

    • 选择同时包含 containerpanel 类的所有元素。
    • 示例:
1
2
3
4
5
6
7
<div class="container panel">
同时拥有 container 和 panel 类的元素
</div>
<div class="container">
<div class="panel">单独拥有 panel 类的元素</div>
</div>

仅选择第一个 div,因为它同时拥有 containerpanel 类。

window 对象

window 对象是 JavaScript 在浏览器环境中的全局对象,表示浏览器的窗口或框架。它包含了许多有用的属性和方法,用于操作浏览器窗口和与用户交互。在浏览器中,所有全局变量、函数和对象都是 window 对象的属性和方法。

它的属性和属性值过多,这里不多列举。

Function

Selector

1
const elements = document.querySelector(selectors);

返回的是匹配的第一个元素。

1
const elements = document.querySelectorAll(selectors);

返回的是一个 NodeList,是一种类数组对象,表示文档中的一组节点,储存匹配选择器的所有元素。

不是数组,有 length 属性,可以通过索引访问其中的元素。

forEach

遍历数组或类数组对象,对数组中的每个元素执行一次提供(参数)的回调函数。

1
2
3
array.forEach(function(currentValue, index, array) {
// 执行某些操作
});
  • currentValue 必选,表示当前正在处理的元素。
  • index 可选,表示当前正在处理的元素的索引,从 0 开始。
  • array 可选,调用数组本身。

Listener

1
item.addEventListener('click', [function]);

向指定元素添加事件监听器,当事件(这里是点击)发生时,执行相应的回调函数。

常用的事件

  • DOMContentLoaded:文档内容加载完成
  • click
  • mouseover
  • keydown

classList

1
2
item.classList.add('[class]');
item.classList.remove('[class]');

为当前元素添加/删除 class

call

了解 call 方法之前,先来了解一下 this

在JavaScript中,this关键字总是指向一个对象,通常是指向调用函数的那个对象。this的值在函数被调用时才会确定,并且其值取决于函数是如何被调用的。

  1. 全局函数:在全局函数中,this指向全局对象(在浏览器中是window)。
1
2
3
4
5
6
// 全局函数
function sayGlobal() {
console.log(this);
}

sayGlobal(); // 在浏览器中,控制台将显示window对象
  1. 对象的方法:当一个函数作为某个对象的方法被调用时,this指向该对象。
1
2
3
4
5
6
7
8
9
// 创建一个对象
var person = {
name: 'Alice',
sayName: function() {
console.log(this.name); // 这里this指向person对象
}
};

person.sayName(); // 输出: Alice
  1. 构造函数:在构造函数中,this指向新创建的对象。
1
2
3
4
5
6
7
8
9
// 构造函数
function Car(make, model) {
this.make = make;
this.model = model;
}

var myCar = new Car('Toyota', 'Corolla');
console.log(myCar.make); // 输出: Toyota
// 在Car构造函数中,this指向新创建的myCar对象

new 用于新建一个对象,后面调用构造函数。

  1. 事件处理器:在事件处理器中,this指向触发事件的对象。
1
2
3
4
5
6
7
8
9
10
<!-- HTML -->
<button id="clickMe">Click me!</button>

<script>
// JavaScript
document.getElementById('clickMe').addEventListener('click', function() {
console.log(this); // 这里this指向被点击的button元素
alert('Button was clicked!');
});
</script>
  1. 箭头函数
1
2
3
4
5
6
7
8
9
10
var person = {
name: 'Bob',
greet: function() {
setTimeout(() => {
console.log(this.name); // 这里this指向person对象,而不是全局对象或window
}, 1000);
}
};

person.greet(); // 一秒钟后输出: Bob

call方法的作用是调用一个函数,并显式地设置函数体内的this对象,同时传递参数给这个函数。call方法的第一个参数是this的绑定对象,后面的参数是传递给函数的参数。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
function Person(name) {
this.name = name;
}

Person.prototype.introduce = function() {
return "My name is " + this.name;
};

var animal = { name: "Dog" };

// 使用call方法借用Person的introduce方法
var animalIntroduce = Person.prototype.introduce.call(animal);
console.log(animalIntroduce); // 输出: My name is Dog

这里 .call(animal) 就改变了一个原型构造函数this 值为对象 animal,实现了方法的借用。

其它的功能比如改变函数的调用上下文,实现继承等。

示例:

比如数组的一个方法 filter,想要作用于类数组对象上,可以这样写:

1
[].filter.call(item.parentElement.children, el => el !== item)

这里 item.parentElement.children 返回的是元素 item 的父元素的所有子元素的集合,是一个类数组对象,为了对它进行 filter 的方法,可以利用 call,实现方法的借用,后面 el => el !== item 是原 filter 函数的参数,表示 callback 筛选条件。

toggle

切换某元素的某个 class 的开关状态,若存在则移除它,若不存在则添加它。

1
element.classList.toggle("changed", [true/false]);

第二个参数可选,若 true 则强制添加,若 false 则强制删除。

getBoundingClientRect

是元素的一个方法,返回一个包含该元素信息的 DOMRect 对象。

提供以下属性:

  • **top**:元素上边缘到视口上边缘的距离。
  • **right**:元素右边缘到视口左边缘的距离。
  • **bottom**:元素下边缘到视口上边缘的距离。
  • **left**:元素左边缘到视口左边缘的距离。
  • **width**:元素的宽度(相当于 right - left)。
  • **height**:元素的高度(相当于 bottom - top)。

异步(asynchronous)

回调函数

一个函数接受另一个函数作为参数,并在进行一系列操作之后回调这个函数。

示例:

1
2
3
4
5
6
7
8
9
10
function fetchData(callback) {
setTimeout(() => {
callback("Data fetched");
}, 1000);
}

fetchData(data => {
console.log(data); // 输出 "Data fetched"
});

Promise

Promise 对象返回一个异步操作的最终完成/失败及其结果值,它可以将一个操作异步化。

什么是异步?什么是同步?

正常来讲一个 javascript 程序是按照顺序执行的,上一个函数执行完之前,底下的函数只能干等着。

如果这是一个非常耗时的网络请求,我们完全可以一边执行请求,一边执行其它的代码,这就是异步,反之等待请求完成后再执行其它代码就是同步。

创建一个 Promise 对象:

1
2
3
4
5
6
7
8
let promise = new Promise((resolve, reject) => {
// 异步操作的代码
if (/* 异步操作成功 */) {
resolve('成功的结果'); // 异步操作成功时调用
} else {
reject('失败的原因'); // 异步操作失败时调用
}
});

一个 Promise 对象在被创建后里面的操作会立刻执行。

它有三种状态:

  • pending
  • fulfilled
  • rejected

比如我想实现两个异步操作都结束时将它们的结果值相加,那么可以使用 Promise.all() 函数,参数是一个 Promise 数组,当里面的 Promise 都成功时,返回一个数组,里面是各个 Promise 的结果值。

这样就可以让两个操作并行,节约时间。

1
2
3
4
5
6
const promise1 = new Promise(resolve => setTimeout(() => resolve(2), 20));
const promise2 = new Promise(resolve => setTimeout(() => resolve(5), 60));

const [a, b] = await Promise.all([promise1, promise2]);

console.log(a + b);

Leetcode 例题

如果我想在超时之后返回 reject 并且终止进程防止内存泄漏,可以这样:

1
2
3
4
5
6
7
async function(...args) {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => { reject("Time Limit Exceeded");
}, t);
fn(...args).then(resolve).catch(reject).finally(() => clearTimeout(timeout));
})
}

还可以保证函数的正常运行,如果运行成功,那么 .then(resolve,否则就 .catch(reject),并且最后结束这个 timout

Leetcode 例题

async/await

async 用于声明一个异步函数,使它返回一个 Promise 对象。

await 只能在 async 函数内部使用,用于等待一个 Promise 完成,并返回 Promise 的结果。

这样可以使我们可以以同步的方式处理异步代码。

注意:

如果需要在循环中使用异步操作,那么是不可以使用 forEach 或者 map 这种方法的,它不会等待 await 执行完,而是直接进入下一个循环。

如何解决?

使用 for...of 循环。

如何让所有的异步操作并发执行呢?

1
2
3
4
5
6
7
8
9
async function fn() {
const promises = [
someAsyncOperation(),
someAsyncOperation(),
someAsyncOperation()
];
for await (let result of promises);
console.log("done");
}

promises 中存储的是若干个 Promise 对象,这些对象在创建 promises 时即开始并发执行,用 for await 来依次等待它们完成(所有的 Promise 是同时运行的),这样就可以在它们都运行完成后退出循环进行下一步的操作。

1
2
3
4
5
6
class Day {
constructor(day, date) {
this.day = day;
this.date = date;
}
}

constructor 构造函数中,成员变量不需要显式声明,使用 new Day(day, date) 进行实例化。

Extends

类之间可以继承,子类可以继承父类的功能也可以重写父类的方法。

使用在子类中使用 super() 调用父类的构造函数。

JSON

parse

1
JSON.parse(string);

用于将 JSON 字符串转换为 JS 对象。

stringify

1
JSON.stringify(obj);

将对象转换为 JSON 字符串。

Map

转换为 Object

1
const obj = Object.fromEntries(map);

转换为 Map

1
2
const temp = Object.entries(obj); // 转换为二维键值数组
let map = new Map(temp)

Backend

res

响应体,后端可以进行一些响应返回给前端。

常用:

  • res.send():返回纯文本/ HTML 数据
  • res.json():将对象转化为 JSON 字符串并返回
  • res.status():设置 HTTP 状态码
  • res.sendFile():发送文件
  • res.setHeader():设置响应头
  • res.redirect():将客户端重定向到另一个 URL
  • Title: JavaScript Note
  • Author: Falling_Sakura
  • Created at : 2024-05-22 23:33:11
  • Updated at : 2024-11-21 10:44:39
  • Link: https://vercel.fallingsakura.top/fbbf86b6.html
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments