JavaScript Note

JavaScript Note

Falling_Sakura Fixed

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 循环,这里就不献丑了。

常用方法

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"]

JSON

JSON.stringify()

将值转换为 JSON 字符串(通常传入对象或数组)。

filter

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

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

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

setTimeout

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

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

splice

1
array.splice(index, x);

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

setInterval

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

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

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

如果要停止它,那么要先保存它的 ID

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

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

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!";
};

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 类。

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 则强制删除。

异步(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 对象表示一个异步操作的最终完成/失败及其结果值。

创建一个 Promise 对象:

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

有三种状态:

  • pending
  • fulfilled
  • rejected

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

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

let []

Leetcode 例题

async/await

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

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

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

  • Title: JavaScript Note
  • Author: Falling_Sakura
  • Created at : 2024-05-22 23:33:11
  • Updated at : 2024-06-22 20:59:40
  • Link: https://vercel.fallingsakura.top/fbbf86b6.html
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments