目录
一、函数
JavaScript 函数是一段可以重复使用的代码,用于执行特定的任务或计算值。函数可以接收输入参数(传递给函数的值)并返回输出值(从函数返回的值)。
1.1.初识函数
1.函数类型:
- 普通函数:使用
function关键字声明的函数。 - 匿名函数:没有名字的函数,通常作为其他函数的参数或赋值给变量。
- 箭头函数:ES6 引入的一种更简洁的函数写法,适用于简单函数。
- 立即调用的函数表达式(IIFE) :在定义后立即执行的函数,通常用于创建独立的作用域。
2.函数的定义
// 命名函数(普通函数)
function 函数名(){
函数体(在函数中要写的代码)
return value; // 可选
}
函数名(); //调用函数
// 匿名函数
function(){ }
使用箭头函数可以定义一个更简洁的函数
const 函数名=()=>{
函数体
return value; // 如果函数体只有一行,可以省略花括号和 return 关键字
};
假设变量名和函数名重名,执行的优先级是什么?
优先级:变量的赋值>函数的声明>变量的声明
3.调用函数
方法:函数名();
例
// 封装函数(其实就是把功能写在函数里面)
function sum(){
var and = 0;
for(var i=0;i<101;i++){
and+=i;
}
console.log(and);
}
sum();
sum(); //可以重复调用
1.2.函数参数和返回值
1.参数
形参:在定义函数时,小括号里面的参数
实参:函数调用时括号里面的变量就叫实参
例
function sum(one,end){
var and = 0;
for(var i=one;i<=end;i++){
and+=i;
}
console.log(and);
}
sum(30,80);
其中的30和80是实参,one和end就是形参,one对应的是30,end对应80,如果把one和end调换,那么one就对应80,这里只看位置,不看参数。
2.函数返回值
函数可以使用 return 语句返回值。如果函数没有 return 语句或没有执行到 return 语句,则返回 undefined。
var 变量 = 方法(); 方法执行完返回的结果就是返回值。
function sum(one,end){
var and = 0;
for(var i=one;i<=end;i++){
and+=i;
}
console.log(and);
return and; //设置函数的返回值(如果不写return,返回值就是undefined)
//return "张三"; 写什么就返回什么
//return 一定要写在函数的最下方,return还有个功能,能直接终止代码的执行
}
var a=sum(1,100);——(a接收到了and)
console.log(a/2);
//一旦写了返回值要伸手接
// 也可以这样写:sum(1,100);
// console.log(sum(1,100)/2);
1.3.函数的特性
1.3.1.作用域
定义:代码(变量)可以使用的范围,可以提高程序的可靠性,也剋减少命名的冲突。
函数具有自己的作用域,可以访问函数内部声明的变量和参数,但不能直接访问函数外部的变量(除非通过特定的方式,如闭包)
全局作用域: 在整个script标签里任意一个地方都可以使用
局部作用域: 通常在函数内部定义的就是局部作用域,只在函数内有效
在全局里面定义的变量就叫全局变量
在局部里面定义的变量就叫局部变量
全局作用域无法访问局部变量,但是局部作用域可以访问全局变量
var and=200; //全局变量(就声明了一个变量)
function sum(){
and = 300;——//赋值了300
//所有不加var的使用,默认视为全局变量,无论写在函数内还是函数外——不推荐使用
console.log(and);//300
}
sum();
console.log(and); // 全局 ,输出300 (函数外部无法访问函数内部定义变量)
变量提升
将变量的声明或函数的声明提升到当前作用域的最上方,提升结束以后代码才会开始从上往下运行——这就是变量提升
注意:变量的提升只会将变量的声明提升到当前所处作用域的最上方,变量的赋值不会被提升
console.log(a);
var a=100;
// 执行过程如下:
var a;
console.log(a); ——输出undefined
a =100;
var和let的区别
var :1.变量提升
2.可以重复声明不报错
3.没有块级作用域
Let:1.不会变量提升
2.不可以重复声明
3.有块级作用域({}就是块(封闭起来了))
回调函数
回调函数,也就是说一个函数作为参数传递给另一个函数里,再去调用
function f1(one){
// console.log(one);
one(); ——调用,输出我是f2
}
function f2(){
console.log("我是f2");
}
f1(f2);——把f2赋值给了one
1.3.2.闭包(重点)
特点:一个函数可以访问到另一个函数内部定义的变量
用途:
1.可以读取函数内部的变量
2.让函数里面的变量始终保存在内存中不被回收
变量回收
1.全局变量不会被回收
2.局部变量会被回收,也就是说当一个函数运行完以后,函数内部的东西就会随运行结束而销毁
3.如果该局部变量被另一个作用域所引用,那么也不会被回收
注意:这种变量没有被正常回收的现象,我们叫内存泄漏
不建议经常使用闭包函数,会导致内存泄漏
1.3.3.递归
递归函数是调用自身的函数。递归函数通常有一个基准情况(base case),当满足某个条件时停止递归调用,否则它会继续调用自身。递归是解决某些问题的一种有效方法,但需要注意避免无限递归和栈溢出。
例
let num = 0;
function sum(){
if(num===21){
return //这里是用作结束不是用于返回值
}
num++;
sum();//(调用自己)
}
sum();
console.log(num);//输出21
递归计算阶乘的函数
function factorial(n) {
if (n === 0) {
return 1; // 基准情况
} else {
return n * factorial(n - 1); // 递归调用
}
}
console.log(factorial(5)); // 输出: 120
二、数组
2.1.数组的使用
2.1.1.创建数组
1.字面量方式
let arr = [1, 2, 3, "hello", {name: "Alice"}];
2.构造器方式
let arr = new Array(1, 2, 3);
// 或者创建一个具有特定长度的数组(但元素未定义)
let emptyArr = new Array(5);
2.1.2.访问数组元素
通过索引访问
console.log(arr[0]); // 输出: 1
2.1.3.数组长度
获取数组长度
console.log(arr.length); // 输出: 5
设置数组长度(会截断或扩展数组)
arr.length = 3; // arr 现在是 [1, 2, 3]
arr.length = 7; // arr 现在是 [1, 2, 3, empty × 4],后四个元素为 undefined
2.1.4.遍历数组方法
1.使用for循环
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
2.使用for...of循环
for (let item of arr) {
console.log(item);
}
3.使用forEach方法
arr.forEach(function(item) {
console.log(item);
});
2.2.数组的内置方法(重点)
2.2.1.添加元素
末尾添加push()
有返回值,返回的是当前数组的长度
let arr = [1,2,3];
arr.push(4); // arr 现在是 [1, 2, 3, 4]
开头添加unshift()
arr.unshift(0); // arr 现在是 [0, 1, 2, 3, 4]
在特定位置添加
arr.splice(2, 0, "inserted"); // arr 现在是 [0, 1, "inserted", 2, 3, 4]
2.2.2.删除元素
末尾删除pop()
调用一次删除一个。有返回值,返回的是被删除的元素
arr.pop(); // arr 现在是 [0, 1, "inserted", 2, 3]
开头删除shift()
调用一次删除一个。有返回值,返回的是被删除的元素
arr.shift(); // arr 现在是 ["inserted", 2, 3]
删除特定位置:splice(开始的位置(索引值),删除的长度,要替换的元素)——前两个参数必填,第三个可选。有返回值,返回的也是被删除的元素,但是是数组的结构( 能删除,能添加,能替换)
例如:
arr.splice(1, 1); // 从索引 1 开始删除 1 个元素,arr 现在是 ["inserted", 3]
2.2.3数组的方法
concat() 合并数组,并返回合并后的新数组
例如:
let arr = [1,2,3];
let demo = [4,5,6,7];
let newArr = arr.concat(demo);
console.log(newArr);
slice(截取开始的位置,截取结束的位置) 截取数组,并返回截取后的新数组。(包含开头不包含结尾)
例如:
let demo = [4,5,6,7,8,9];
let test = demo.slice(-2);// 负数代表倒着数
let test = demo.slice(2,4);
// 如果只填一个开始,则会自动截取到结尾
sort() 用来给数组进行排序的,但是要传入一个函数规则。有返回值,返回的是排序好的新数组。
例如:
let list = [2,3,1,7,5,8,0];
function bank(a,b){
// a 代表相邻的 左边的元素,相当于arr[i]
// b 代表相邻的 右边的元素,相当于arr[i+1]
if(a<b){
return -1;
}
if(a>b){
return 1;
}
return 0;
// sort 如果你return 1 ,则代表b会排列到a之前
// 如果你return -1 ,则代表a会排列到b之前
// 如果你return 0,则代表a和b的位置不变
}
let demo = list.sort(bank);//传入一个函数,里面是写好的规则
console.log(demo);
reverse() 对数组进行反转
例如:
let list = [2,3,1,7,5,8,0];
let mo = list.reverse();
console.log(mo);
indexOf(要查找的元素,查找开始的位置(选填)) 查找数组中是否有该元素,如果有则返回该元素所在的下标,如果没有返回-1。
例如:
let demo = [4,5,6,7,8,9,11,5,6];
let num = demo.indexOf(6,-3);
//输出下标8
// 负数是倒着数(从-1开始),不管填正数还是负数,都是从开始位置往后数,寻找要查找的元素
console.log(num);
let test = [1,2,3,2,1,2,4,5,6,7,2,1];
// 去重,传递需要去重的数组,有返回值,返回的是去重好的数组
function uni(arr){
let demo = [];
for(let i=0;i<arr.length;i++){
if(demo.indexOf(arr[i]) === -1){
demo.push(arr[i]);
}
}
return demo;
}
let a = uni(test);
console.log(a);
join() 将数组按照指定字符拼接成字符串
例如:
let test = [1,2,3,2,1,2,4,5,6,7,2,1];
let str = test.join("");
console.log(str);//----输出123212456721
forEach() 可以用来遍历数组
arr.forEach(function(item) {
console.log(item);
});
filter() 过滤出符合条件的元素,生成一个新的数组
let evens = arr.filter(function(item) {
return item % 2 === 0;
}); // [2]
map() 遍历一个数组,并且会返回一个新数组,必须要return,返回的是组成新数组的每一项元素
let arr = [1,2,3,4,5,6]
let doubled = arr.map(function(item) {
return item * 2;
}); // [2, 4, 6]
2.2.4.冒泡排序(重点)
冒泡排序(Bubble Sort)是一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复进行的,直到没有再需要交换的元素为止,这意味着该数列已经排序完成。
function bubbleSort(arr) {
let n = arr.length;
// 外层循环控制遍历次数
for (let i = 0; i < n - 1; i++) {
// 内层循环控制每一轮的比较和交换
for (let j = 0; j < n - 1 - i; j++) {
// 如果前一个元素比后一个元素大,则交换它们
if (arr[j] > arr[j + 1]) {
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
// 示例
let array = [64, 34, 25, 12, 22, 11, 90];
console.log("排序前的数组: ", array);
let sortedArray = bubbleSort(array);
console.log("排序后的数组: ", sortedArray);
复杂度分析:
时间复杂度:在最坏情况下(数组是逆序的),时间复杂度为 O(n^2)。
空间复杂度:由于冒泡排序是原地排序(不需要额外的存储空间),空间复杂度为 O(1)。
2.3.二维数组
1.创建二维数组
通过嵌套数组字面量或Array构造函数来创建二维数组。
使用数组字面量
let matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
使用Array构造函数
使用Array构造函数和fill方法(在ES6及更高版本中可用)来创建和填充二维数组:
let rows = 3, cols = 3;
let matrix = Array.from({ length: rows }, () => Array(cols).fill(0));
// matrix现在是:
// [
// [0, 0, 0],
// [0, 0, 0],
// [0, 0, 0]
// ]
2.访问二维数组的元素
通过两个索引来访问二维数组的元素:第一个索引表示行,第二个索引表示列。
let value = matrix[1][2]; // 获取第二行第三列的元素,值为6
3.修改二维数组的元素
通过两个索引来修改二维数组的元素:
matrix[1][2] = 99; // 将第二行第三列的元素修改为99
4.遍历二维数组
使用嵌套的for循环来遍历二维数组的所有元素:
for (let i = 0; i < matrix.length; i++) {
for (let j = 0; j < matrix[i].length; j++) {
console.log(matrix[i][j]);
}
}
5.冒泡排序二维数组(按行或列)
虽然冒泡排序通常用于一维数组,但你也可以对二维数组的某一行或某一列进行排序。下面是一个按列对二维数组进行冒泡排序的例子
function bubbleSort2DByColumn(matrix) {
let rows = matrix.length;
let cols = matrix[0].length;
for (let col = 0; col < cols; col++) {
for (let row = 0; row < rows - 1; row++) {
for (let k = 0; k < rows - row - 1; k++) {
if (matrix[k][col] > matrix[k + 1][col]) {
// 交换matrix[k][col]和matrix[k + 1][col]所在的行(或只交换这两个元素,取决于需求)
let tempRow = matrix[k];
matrix[k] = matrix[k + 1];
matrix[k + 1] = tempRow;
}
}
}
}
return matrix;
}
// 示例
let array2D = [
[3, 2, 1],
[6, 5, 4],
[9, 8, 7]
];
console.log("排序前的二维数组: ");
console.log(array2D);
let sortedArray2D = bubbleSort2DByColumn(array2D);
console.log("排序后的二维数组(按列): ");
console.log(sortedArray2D);
注意:上面的
bubbleSort2DByColumn函数实际上是通过交换整行来实现按列排序的。如果你只想按列排序但不想改变行的其他元素的位置,你需要一个更复杂的算法来只交换列元素而不是整行。然而,对于大多数实际应用来说,交换整行通常是可接受的,特别是当二维数组表示的是表格数据时
码字不易,但看到您的点赞,一切都值得了!