跳至主要內容

 

labuladong约 2227 字大约 7 分钟配套学习工具

因为我的 算法可视化面板 目前只支持 JavaScript 语言(对 Python 的支持正在开发),所以我就写一个极简 JavaScript 教程,带大家了解 JavaScript 的基本用法,目的是让不了解 JS 的读者也能把算法可视化面板用起来

大家应该也有体会,学习算法的过程中,编程语言其实只是个工具,我们仅仅会用到最简单的变量声明、循环控制、条件判断,再加上像数组、哈希表等基本数据结构。所以,只要你有任意其他熟悉的编程语言,你只需 5 分钟看看下面的内容,就足够使用可视化面板了。

JavaScript 基本语法

变量声明

首先说一下 JavaScript 的变量声明,它有三种声明变量的方式,分别是 var, let, const

const 声明的是常量,一旦声明就不能再修改,这个没什么好说的,一般在工程代码中才有使用场景,在算法代码中我们基本不会用到。

const a = 1;
a = 2; // 报错

varlet 都可以声明一般的变量,但它俩声明出来的变量可见性不一样,var 应该算是历史遗留问题,反正你就记住:无脑用 let 就行了,它声明的变量是块级作用域,这个行为和其他编程语言的行为是一样的

let str = "hello world";
str = "world"
console.log(str); // 输出 world

if (true) {
    // 这里的 str 和外面的 str 是两个不同的变量
    let str = "hello";
    console.log(str); // 输出 hello
}

但是你会发现,我的可视化代码中的顶层函数都是用 var 声明的,比如斐波那契数列的解法代码:

这是因为 LeetCode 上给的 JS 函数签名都是用 var 声明的,所以我也沿用 var 了,不过你非要改成 let 也是没问题的,这些都是小问题。

函数声明

JavaScript 的函数声明也很简单,就是这样:

function add(a, b) {
    return a + b;
}
console.log(add(1, 2)); // 输出 3

这个函数的声明和其他编程语言的声明是一样的,不过 JavaScript 中可能还会见到下面的匿名函数声明方式,相当于是用变量接收了一个匿名函数,不过使用起来都是一样的:

// 把 let 换成 var 也是一样的效果
let add = function(a, b) {
    return a + b;
}
console.log(add(1, 2)); // 输出 3


// 用 ES6 的箭头函数声明
let add = (a, b) => {
    return a + b;
}
console.log(add(1, 2)); // 输出 3

function 关键词声明的函数和用 () => {} 这种方式声明的箭头函数有一些关键差别,主要是函数体内使用 this 指针的行为不同,但是在算法题中基本不会用到这个特性,所以你可以认为这两种方式是一样的。

注意

在算法可视化面板中 开启递归过程的可视化 时,必须使用后两种匿名函数的声明方式,只能用 let add = function(...) {...} 这种形式,否则无法可视化出递归树,这个作为特殊情况记住就行了。

举个例子,你要用 @visualize status 关键词对递归函数开启可视化追踪,必须用下面第一种声明方式:

// 只可以用这种方式
// @visualize status(n)
var fib = function(n) {
    if (n < 2) {
        return n;
    }
    return fib(n - 1) + fib(n - 2);
}
let result = fib(5)


// 不要用箭头匿名函数的声明方式
// @visualize status(n)
var fib = (n) => {
    if (n < 2) {
        return n;
    }
    return fib(n - 1) + fib(n - 2);
}
let result = fib(5)


// 也不能用这种命名函数声明方式
// @visualize status(n)
function fib(n) {
    if (n < 2) {
        return n;
    }
    return fib(n - 1) + fib(n - 2);
}
let result = fib(5)

循环控制

JavaScript 的循环控制和其他编程语言也是一样的,常见的就是 forwhile

以遍历数组为例,先讲最常见的方式,用索引遍历:

// 遍历数组
let arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}
// 输出 1 2 3 4 5

然后是用 for...of 方式,可以直接遍历元素:

// 遍历数组
let arr = [1, 2, 3, 4, 5];
for (let item of arr) {
    console.log(item);
}
// 输出 1 2 3 4 5

用 `for ... of` 遍历元素

注意 JavaScript 用的是 of 来遍历数组元素,不要用 inin 有其他的作用,不过我们做算法题基本用不到,我就不啰嗦了。

我知道有些其他语言会用 in 遍历数组元素,所以特此提醒,不要搞错了。

while 循环和其他语言一样,举个简单例子:

let arr = [1, 2, 3, 4, 5];
let i = 0;
while (i < arr.length) {
    console.log(arr[i]);
    i++;
}
// 输出 1 2 3 4 5

条件判断

if else 的用法和其他语言完全一致,没啥可说的,举个简单的例子:

let a = 1;
if (a === 1) {
    console.log("a 等于 1");
} else {
    console.log("a 不等于 1");
}

用 `===` 判断相等

这里也有一个小坑,就是 JavaScript 中的 ===== 的区别。== 是值相等就行,=== 是值和类型都相等才行。

简单讲,你就记住其他语言中的 == 在 JavaScript 中是 ===,不要在 JavaScript 中用 == 就行了

JavaScript 基本数据结构

字符串

JavaScript 中的字符串和其他语言一样,没啥特别的,举个例子:

let str = "hello world";
console.log(str.length); // 输出 11
console.log(str[0]); // 输出 h
console.log(str === "hello world"); // 输出 true

// 字符串分割
let arr = str.split(" ");
console.log(arr); // 输出 ["hello", "world"]

// 获取子串,多种方式都可以
console.log(str.substring(0, 5)); // 输出 hello
console.log(str.slice(0, 5)); // 输出 hello
console.log(str.substr(0, 5)); // 输出 hello

// 字符串拼接
let str2 = "world";
console.log(str + " " + str2); // 输出 hello world world

数组

有以下几种方法创建数组:

let arr1 = [1, 2, 3, 4, 5];
let arr2 = new Array(1, 2, 3, 4, 5);

// 创建一个长度为 5 的数组,每个元素都是 undefined
let arr3 = new Array(5);

// 创建一个长度为 5 的数组,每个元素都是 0
let arr4 = new Array(5).fill(0);

数组的常见操作:

let arr = [1, 2, 3, 4, 5];

// 获取数组长度
console.log(arr.length); // 输出 5

// 获取数组元素
console.log(arr[0]); // 输出 1

// 修改数组元素
arr[0] = 100;

// 复制数组的所有元素到一个新数组
let arr2 = arr.slice();
// 这也是一种复制数组的方法
let arr3 = [...arr];

// 在数组末尾添加一个元素
arr.push(6);

// 删除数组尾部的元素
arr.pop();

// 在数组开头添加一个元素
// 不常用,因为算法中都尽量避免在数组的非末尾位置增删元素
arr.unshift(0);

// 删除数组开头的元素
// 不常用,因为算法中都尽量避免在数组的非末尾位置增删元素
arr.shift();

好了,了解上述基本操作完全足够你在算法题中使用数组了。

哈希表

通俗来讲,JavaScript 中的对象就可以理解为是哈希表,因为 JavaScript 对象就是若干键值对。不过 ES6 中引入了 Map 类型,所以我们就规范一些,用 Map 类型来创建哈希表。

Map 的基本操作:

let map = new Map();

// 添加键值对
map.set("a", 1);
map.set("b", 2);
map.set("c", 3);

// 获取键值对
console.log(map.get("a")); // 输出 1

// 删除键值对
map.delete("a");

// 判断是否存在某个键
console.log(map.has("a")); // 输出 false
console.log(map.has("b")); // 输出 true

// 遍历键值对
for (let key of map.keys()) {
    console.log(key, map.get(key));
}
// 输出 b 2 和 c 3

了解这些就差不多了,遇到不会处理的场景再查查文档就行了。

哈希集合

ES6 中引入的 Set 类型就是哈希集合,它用来存储不重复的元素,基本操作如下:

let set = new Set();

// 添加元素
set.add(1);
set.add(2);
set.add(3);

// 删除元素
set.delete(1);

// 判断是否存在某个元素
console.log(set.has(1)); // 输出 false
console.log(set.has(2)); // 输出 true

// 遍历元素
for (let item of set) {
    console.log(item);
}
// 输出 2 和 3

其他特殊数据结构

在算法题中,还会用到一些特殊的数据结构,比如链表、树等,这些数据结构不是 JavaScript 内置的,不过我的算法可视化面板中已经实现了这些特殊数据结构,具体用法可以参考我的 算法可视化面板简介