JS基础知识03-函数(数组、变量提升等)

40 阅读15分钟

目录

一、函数

1.1.初识函数

1.函数类型:

 2.函数的定义

3.调用函数

1.2.函数参数和返回值

1.参数

2.函数返回值

1.3.函数的特性

1.3.1.作用域

变量提升

var和let的区别

回调函数

1.3.2.闭包(重点)

变量回收

1.3.3.递归

二、数组

2.1.数组的使用

2.1.1.创建数组

2.2.数组的内置方法(重点)

2.2.1.添加元素

2.2.2.删除元素

2.2.3数组的方法

2.2.4.冒泡排序(重点)

2.3.二维数组

1.创建二维数组

使用数组字面量

使用Array构造函数

2.访问二维数组的元素

3.修改二维数组的元素

4.遍历二维数组

5.冒泡排序二维数组(按行或列)


一、函数

JavaScript 函数是一段可以重复使用的代码,用于执行特定的任务或计算值。函数可以接收输入参数(传递给函数的值)并返回输出值(从函数返回的值)。

1.1.初识函数

1.函数类型:

  1. 普通函数:使用 function 关键字声明的函数。
  2. 匿名函数:没有名字的函数,通常作为其他函数的参数或赋值给变量。
  3. 箭头函数:ES6 引入的一种更简洁的函数写法,适用于简单函数。
  4. 立即调用的函数表达式(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,则代表ab的位置不变
}
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函数实际上是通过交换整行来实现按列排序的。如果你只想按列排序但不想改变行的其他元素的位置,你需要一个更复杂的算法来只交换列元素而不是整行。然而,对于大多数实际应用来说,交换整行通常是可接受的,特别是当二维数组表示的是表格数据时

码字不易,但看到您的点赞,一切都值得了!