首页 > 其他分享 >Js数组&高阶函数

Js数组&高阶函数

时间:2024-10-16 18:42:59浏览次数:7  
标签:arr console log Js let 数组 高阶 函数

数组也是一种复合数据类型,在数组可以存储多个不同类型的数据

  • 数组中存储的是有序的数据,数组中的每个数据都有一个唯一的索引可以通过索引来操作获取数据
  • 数组中存储的数据叫做元素
  • 任何类型的值都可以成为数组中的元素

基本操作

创建数组
// 通过Array创建数组
const arr = new Array()
// 通过[]创建数组
const arr = []
数组添加元素
// 通过索引添加元素
arr[0] = "test"
// 如果索引不是连续的,中间的索引也会创建,只是元素是空,应该避免使用非连续数组,性能不好
arr[3] = "2"
// 定义的时候添加元素
const a = new Array(1,3,4)
const arr = ["1","test"]
读取元素
// 通过索引读取,如果读取一个不存在的元素,返回undefined
const arr = ["1","test"]
arr[0] // "1"
获取数组长度
// 获取的实际值是数组的最大的索引+1,非连续数组因为有空值,不会特别准确
console.log(arr.length) 

// 向数组的最后添加元素
arr[arr.length] = "3"

// 修改长度,如果改大了,多出的部分会是空元素,如果改小,会从后往前删除元素
arr.length = 10 
数组遍历 for-of
arr = [1,2,3,4,5,6,7,8,9,10]

// 通过长度遍历-正序
for(let i=0; i < arr.length;++){
  console.log(arr[i])
}

// 通过长度遍历-倒序
for(let i=arr.length-1;i>=0;i--){
    console.log(arr[i])
}

// for-of语句可以用来遍历可迭代对象
for(let a of arr){
      console.log(a)
}

数组方法(非破坏性)

方法大全

增删改查
// 检查一个对象是否是数组
let arr = []
console.log(Array.isArray(arr)) // true
let arr = [1,2,3]
// 根据索引获取数组中的指定元素,
console.log(arr.at(2))
let arr = [1,2,3]
let arr1 = [4,5,6]

// 用来连接两个或多个数组
// 非破坏性方法,不会影响原数组,而是返回一个新的数组
let new_arr = arr.concat(arr1,[7,8])
console.log(new_arr) // [1,2,3,4,5,6,7,8]

let arr = [1,2,3,2]
// 获取元素在数组中第一次出现的索引
// 参数:要查询的元素,查询的起始位置
console.log(arr.indexOf(2)) // 1
console.log(arr.indexOf(2,2)) // 3
let arr = [1,2,3,2]
 // 获取元素在数组中最后一次出现的位置,找到了则返回元素的索引,没有找到返回-1
console.log(arr.lastIndexOf(2)) // 3

let arr = [1,2,3,2]
 // 将一个数组中的元素连接为一个字符串

console.log(arr.join("~")) // 1~2~3~2
let arr = [1,2,3,2]

// 用来截取数组(非破坏性方法)

/*
 参数:1.截取开始的索引(包括该索引元素)
     2.截取的结束索引(不包括该索引元素,该参数可以省略不写,如果省略则会一直截取到最后
     如果将两个参数全都省略,则可以对数组进行浅拷贝


*/
console.log(arr.slice(0,2)) // [1,2]
深拷贝&浅拷贝
// arr1和arr不是复制,两个指向的是一个内存地址,修改任意一个会影响其他数组
let arr = [1,2,3,2]
let arr1 = arr



/*
  浅拷贝
  通常对对象的拷贝都是浅拷贝
  浅拷贝对对象的浅层进行复制(只复制一层)
  如果对象中存储的数据是原始值,那么拷贝的深浅是不重要
  浅拷贝只会对对象本身进行复制,不会复制对象中的属性(或元素)
  调用slice时,会产生一个新的数组对象,从而完成对数组的复制- 浅拷贝
  
*/
 
let arr2 = [{"name":"l"},{"name":"q"}] 
let arr3 = arr.slice() 

 
/*
深拷贝
深拷贝指不仅复制对象本身,还复制对象中的属性和元素
因为性能问题,通常情况不太使用深拷贝

*/
let arr4 = [{"name":"l"},{"name":"q"}] 
let arr5 = structuredClone(arr4)
展开运算符...
let arr = [{"name":1},{"name":2}]
// 可以将一个数组中的元素展开到另一个数组中或者作为函数的参数传递,
// 浅复制
let arr2 = [...arr]
console.log(arr2) // [ { name: 1 }, { name: 2 } ]

对象的复制
/*
Object.assign(目标对象, 被复制的对象)
将被复制对象中的属性复制到目标对象里,并将目标对象返回
*/

const obj = {"name":1}
const  obj1 = Object.assign({},obj)
console.log(obj1) // { name: 1 }
const obj = {"name":1}

const  obj1 = Object.assign({"age":1},obj)
console.log(obj1) // { age: 1, name: 1 }

// 也可以使用展开运算符进行对象复制
const obj = {"name":1}

const  obj1 = {...obj}
console.log(obj1) // { name: 1 },将obj中的属性在新对象中展开

数组方法(破坏性)

const  arr = []

// 向数组的末尾添加一个或多个元素,并返回新的长度
let l = arr.push(1,2,3)
console.log(l) // 3
console.log(arr) // [ 1, 2, 3 ]
const  arr = [1,2,3,4,5]
// 删除并返回数组的最后一个元素
let a = arr.pop()
console.log(a) //  5
console.log(arr) // [ 1, 2, 3, 4 ]
console.log(arr.length) // 4
const  arr = [1,2,3,4,5]
// 向数组的开头添加一个或多个元素,并返回新的长度
let a = arr.unshift(99,98)
console.log(a) //  7
console.log(arr) // [99, 98, 1, 2, 3, 4 ]
const  arr = [1,2,3,4,5]
// 删除并返回数组的第一个元素
let a = arr.shift()
console.log(a) //  1
console.log(arr) // [ 2, 3, 4, 5]
console.log(arr.length) // 4
// 可以删除、插入、替换数组中的元素
// 参数:1. 删除的起始位置  2. 删除的数量 3. 要插入的元素 返回值:删除的元素

// 删除元素
const  arr = [1,2,3,4,5]
let a = arr.splice(1,2)
console.log(a) // [2,3]
console.log(arr) // [1,4,5]

// 替换元素
const  arr = [1,2,3,4,5]
let a = arr.splice(1,1,"ao") // 可以写多个元素
console.log(a) // [2]
console.log(arr) // [ 1, 'ao', 3, 4, 5 ]


// 插入元素
const  arr = [1,2,3,4,5]
let a = arr.splice(1,0,"ao","to") //在下表为1的地方开始插入ao,to,后续元素后移
console.log(a) // []
console.log(arr) // [ 1, 'ao','to', 2, 3, 4, 5 ]

// 反转数组
const  arr = [1,2,"a","s",5]
arr.reverse()
console.log(arr) // [ 5, 's', 'a', 2, 1 ]


数组去重

const arr = [1, 2, 3, 2, 4, 1];
// 使用set方法去重
const arr1 = [...new Set(arr)];
console.log(arr1); // [1, 2, 3, 4]
// 循环判断去重
const arr = [1, 2, 1, 3, 2, 2, 4, 5, 5, 6, 7]

const newArr = []

for(let ele of arr){
    if(newArr.indexOf(ele) === -1){
        newArr.push(ele)
    }
}

console.log(newArr)

高阶函数

如果一个函数的参数或返回值是函数,则这个函数就称为高阶函数
将函数作为参数,意味着可以对另一个函数动态的传递代码

回调函数
function user(fn,age){
    fn(age)
}

function admin(age){
    return age === 18;
}

// 一个函数当做参数传递给另一个函数,这个函数称作回调函数(callback)
user(admin,18)


// 通常回调函数使用匿名函数定义
user(a => age === 18,18)

可以通过高阶函数,来动态的生成一个新函数

function a(){
    return "hello"
}


function b(fn){
    return () => {
        // ... 其他自定义代码
        
        return fn()
    }
}
闭包

可以利用函数,来隐藏不希望被外部访问到的变量

  • 闭包:
    闭包就是能访问到外部函数作用域中变量的函数

  • 什么时候使用:
    当我们需要隐藏一些不希望被别人访问的内容时就可以使用闭包

  • 构成闭包的条件:

       1. 函数的嵌套
    
    1. 内部函数要引用外部函数中的变量

    2. 内部函数要作为返回值返回

function Sum() {
    let num = 0 // 位于Sum作用域中
    return () => {
        num++
        return num
    }
}


const newFn = new Sum()
console.log(newFn()) // 1
console.log(newFn()) // 2
console.log(newFn()) // 3

函数的作用域在函数创建时就已经确定(词法作用域),和调用位置无关

// 闭包的原理就是利用词法作用域
let a = "全局"


function one(){
    console.log(a) // 全局
    return a
}



function two(){
    let a = "局部"
    console.log(a) // 局部
    one()  // 全局

    function three(){ 
        console.log(a) // 局部,函数定义是外部变量a是two中的a
    }
    return three
}



let fn = two()
fn()

闭包的生命周期:

  1. 闭包在外部函数调用时产生,外部函数每次调用都会产生一个全新的闭包
  2. 在内部函数丢失时销毁(内部函数被垃圾回收了,闭包才会消失)

注意事项:

  • 闭包主要用来隐藏一些不希望被外部访问的内容,
  • 这就意味着闭包需要占用一定的内存空间

相较于类来说,闭包比较浪费内存空间(类可以使用原型而闭包不能)

  • 需要执行次数较少时,使用闭包
  • 需要大量创建实例时,使用类
递归

调用自身的函数称为递归函数

递归的作用和循环是基本 一致的

function test(num){
    // 终止条件
    if (num === 1){
        return 1
    }
     // 调用自身
    return test(num-1) * num
}

递归的核心思想就是将一个大的问题拆分为一个一个小的问题,小的问题解决了,大的问题也就解决了

编写递归函数,一定要包含两个要件:

  1. 基线条件 —— 递归的终止条件
  2. 递归条件 —— 如何对问题进行拆分

递归的作用和循环是一致的,不同点在于,递归思路的比较清晰简洁,循环的执行性能比较好
在开发中,一般的问题都可以通过循环解决,也是尽量去使用循环,少用递归
只在一些使用循环解决比较麻烦的场景下,才使用递归

数组方法(回调函数参数)

/*
  sort用来对数组进行排序(会对改变原数组)
  sort默认会将数组升序排列
    注意:sort默认会按照Unicode编码进行排序,所以如果直接通过sort对数字进行排序
        可能会得到一个不正确的结果
  参数:
    - 可以传递一个回调函数作为参数,通过回调函数来指定排序规则
        (a, b) => a - b 升序排列
        (a, b) => b - a 降序排列
*/

let arr = [3,3,4,6,8,1,2,10]


arr.sort((a,b) => a -b)

console.log(arr)
/*
 用来遍历数组
 需要一个回调函数作为参数,这个回调函数会被调用多次
 数组中有几个元素,回调函数就会调用几次
 每次调用,都会将数组中的数据作为参数传递
 回调函数中有三个参数:
    element 当前的元素
    index 当前元素的索引
    array 被遍历的数组
*/

let arr = [3,3,4,6,8,1,2,10]


arr.forEach((element,index,array)=>{
    console.log(element)
    console.log(index)
    console.log(array)
})
/*
将数组中符合条件的元素保存到一个新数组中返回
需要一个回调函数作为参数,会为每一个元素去调用回调函数,并根据返回值(true、false)来决定是否将元素添加到新数组中
非破坏性方法,不会影响原数组

*/
/*
根据当前数组生成一个新数组
需要一个回调函数作为参数,
回调函数的返回值会成为新数组中的元素
非破坏性方法不会影响原数组
*/


let a = ["商城","账户","登录","注册"]


let b = a.map(ele => "<li>" + ele + "</li>")

console.log(b) // [ '<li>商城</li>', '<li>账户</li>', '<li>登录</li>', '<li>注册</li>' ]


/*
可以用来将一个数组中的所有元素整合为一个值
参数:
    1. 回调函数,通过回调函数来指定合并的规则
    2. 可选参数,初始值
*/

let arr = [1,2,3,4,5,6,7,8,10]

let b = arr.reduce((a,b) => a+b)
console.log(b) // 46



let arr2 = [1,2,3,4,5,6,7,8,10]

let b2 = arr2.reduce((a,b) => a+b,10)
console.log(b2) // 56

函数可变参数

/*
arguments是函数中又一个隐含参数
arguments是一个类数组对象(伪数组)
和数组相似,可以通过索引来读取元素,也可以通过for循环变量,但是它不是一个数组对象,不能调用数组的方法
arguments用来存储函数的实参,
无论用户是否定义形参,实参都会存储到arguments对象中
可以通过该对象直接访问实参

*/


function test(){
    console.log(arguments) // { '0': 1, '1': 3, '2': 4 }
    console.log(arguments[0]) // 1

}


test(1,3,4)
/*
可变参数,在定义函数时可以将参数指定为可变参数
- 可变参数可以接收任意数量实参,并将他们统一存储到一个数组中返回
- 可变参数的作用和arguments基本是一致,但是也具有一些不同点:
    1. 可变参数的名字可以自己指定
    2. 可变参数就是一个数组,可以直接使用数组的方法
    3. 可变参数可以配合其他参数一起使用,当可变参数和普通参数一起使用时,需要将可变参数写到最后

*/


function test(...args){
    console.log(args) // [ 1, 3, 4 ]
    console.log(args[0]) // 1]


}


test(1,3,4)

call和apply

调用函数除了通过函数()调用外,还可以通过其他的方式调用

function test(){
  return "hello"
}

test.call() // "hello"
test.apply() // "hello"
/*
call 和 apply除了可以调用函数,还可以用来指定函数中的this
call和apply的第一个参数,将会成为函数的this
通过call方法调用函数,函数的实参直接在第一个参数后一个一个的列出来

*/
class  User{
    name = "l"
    age = 18
}




function test(a,b){
    console.log(this.name) // name
    console.log(this) // User { name: 'l', age: 18 }
    console.log(a) // 1
    console.log(b) // 2

}


let user = new User()
// 指定test函数的this是user对象
test.call(user,1,2)
// 通过apply方法调用函数,函数的实参需要通过一个数组传递
class  User{
    name = "l"
    age = 18
}




function test(a,b){
    console.log(this.name) // name
    console.log(this) // User { name: 'l', age: 18 }
    console.log(a) // 1
    console.log(b) // 2

}


let user = new User()
// 指定test函数的this是user对象
test.apply(user,[1,2])

bind

bind() 是函数的方法,可以用来创建一个新的函数

  • bind可以为新函数绑定this
  • bind可以为新函数绑定参数

箭头函数没有自身的this,它的this由外层作用域决定

  • 无法通过call apply 和 bind修改它的this
  • 箭头函数中没有arguments
class  User{
    name = "l"
    age = 18
}




function test(a){
    console.log(a) // 10
    console.log(this.name) // l

}


const user = new  User()

// 指定新函数的this和参数,如果是原函数()调用,则走原函数的参数和this
const newFn = test.bind(user,10)
newFn()

标签:arr,console,log,Js,let,数组,高阶,函数
From: https://www.cnblogs.com/Mickey-7/p/18470548

相关文章

  • <Leetcode:算法题及解析>最大子数组和(Javascript版)
    题目描述:给你一个整数数组nums,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组是数组中的一个连续部分。本题可以使用Kadane's算法实现,这是一种用于解决最大子数组和问题的高效算法。它由JosephBornKadane在1984年提出。这个算法的核......
  • Next.js 实战开发入门 1 开发环境部署 - 曲速引擎 Warp Drive
    开发目标我们将构建一个简化版本的财务仪表板,其内容包括:公共主页、登录页面、受身份验证保护的仪表板页面、用户可以添加、编辑和删除发票开发环境配置开发客户端Windows10(不限系统,兼容vscode即可)开发服务端Ubuntu24.04(不限系统,兼容node即可)开发工具VscodeVersion:......
  • 代码随想录算法训练营第一天|704二分查找、27移除元素、977有序数组的平方
    代码随想录算法训练营第一天|704二分查找、27移除元素、977有序数组的平方1Leetcode704二分查找题目链接:[704.二分查找](704.二分查找-力扣(LeetCode))文章链接:[代码随想录](代码随想录(programmercarl.com))视频链接:[手把手带你撕出正确的二分法|二分查找法|二分搜......
  • javaWeb项目-ssm+jsp股票交易管理系统功能介绍
    本项目源码(点击下方链接下载):java-ssm+jsp股票交易管理系统实现源码(项目源码-说明文档)资源-CSDN文库项目关键技术开发工具:IDEA、Eclipse编程语言:Java数据库:MySQL5.7+框架:ssm、Springboot前端:Vue、ElementUI关键技术:springboot、SSM、vue、MYSQL、MAVEN数据库工......
  • vue3简单使用threejs立方缓冲几何体(BoxGeometry)
    文章目录前言一、安装three二、使用步骤1.导入three、建立场景、相机和渲染器2.添加立方体3.渲染循环三、其他1.轨道控制器OrbitControls和坐标轴辅助对象AxesHelper2.GUI创建可交互的控件(点击全屏+退出全屏)3.监听窗口的变化执行一些重置操作四、完整代码五、效......
  • Nuxt.js 应用中的 modules:done 事件钩子详解
    title:Nuxt.js应用中的modules:done事件钩子详解date:2024/10/16updated:2024/10/16author:cmdragonexcerpt:modules:done是Nuxt.js中一个重要的生命周期钩子,在Nuxt应用初始化期间触发。该钩子允许开发者在用户定义的模块安装完成后执行特定操作,如初始化后续配......
  • 基于Node.js+vue个人博客系统(开题+程序+论文) 计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着互联网技术的快速发展,个人博客作为一种重要的网络应用形式,逐渐成为人们表达自我、分享知识和经验的重要平台。博客不仅能够记录个人的成长历程、生活点......
  • 基于Node.js+vue会议管理系统(开题+程序+论文) 计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着信息化时代的到来,各类会议活动日益频繁,会议管理成为组织工作中不可或缺的一环。传统的会议管理方式往往依赖于纸质记录和人工协调,不仅效率低下,还容易出......
  • 基于Node.js+vue高校食堂饭卡管理(开题+程序+论文) 计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景高校食堂作为学生学习和生活的重要场所,其管理效率和便捷性直接关系到学生的日常生活质量。传统的高校食堂饭卡管理方式往往依赖于人工操作和纸质记录,这不仅......
  • 使用 Vcpkg 安装 nlohmann/json
    使用Vcpkg安装nlohmann/json是一个简单且高效的方法,因为它会自动为你处理库的安装和配置。以下是详细的步骤:安装Vcpkg克隆Vcpkg仓库:打开命令提示符(CMD)或PowerShell,并运行以下命令来克隆Vcpkg仓库:shgitclonehttps://github.com/Microsoft/vcpkg.gitcdvcpkg安......