JavaScript函数的增强知识

news2024/12/23 4:37:45

函数属性和arguments以及剩余参数

函数属性name与length

◼ 我们知道JavaScript中函数也是一个对象,那么对象中就可以有属性和方法。
◼ 属性name:一个函数的名词我们可以通过name来访问;

    // 自定义属性
    foo.message = "Hello Foo"
    console.log(foo.message)
 
    // 默认函数对象中已经有自己的属性
    // 1.name属性
     console.log(foo.name)
     console.log(bar.name)
 
     // 将两个函数放到数组中(了解)
     var fns = [foo, bar]
     for (var fn of fns) {
       console.log(fn.name)
     }

◼ 属性length:属性length用于返回函数参数的个数;
 注意:rest参数是不参与参数的个数的;

    // 2.length属性: 参数的个数
    function test() {
    }
    test(111, 222, 333)
    console.log(foo.length)
    console.log(bar.length)
    console.log(test.length)
 
 
    // 额外补充
    // function demo(...args) {
    // }
    // demo("abc", "cba", "nba")

函数的arguments

◼ arguments 是一个 对应于传递给函数的参数 的 类数组(array-like)对象。
◼ array-like意味着它不是一个数组类型,而是一个对象类型:
 但是它却拥有数组的一些特性,比如说length,比如可以通过index索引来访问传递给函数的参数
 但是它却没有数组的一些方法,比如filter、map等;


    function foo(m, n) {
      // arguments 类似数组对象
      console.log(arguments)
      // 1.默认用法:
      // 通过索引获取内容
      // console.log(arguments[0])
      // console.log(arguments[1])
 
      // // 遍历
      // for (var i = 0; i < arguments.length; i++) {
      //   console.log(arguments[i])
      // }
      // for (var arg of arguments) {
      //   console.log(arg)
      // }
 
      // 2.需求获取所有参数中的偶数
      // 数组 filter
      // for (var arg of arguments) {
      //   if (arg % 2 === 0) {
      //     console.log(arg)
      //   }
      // }
      // var evenNums = arguments.filter(item => item % 2 === 0)
      // console.log(eventNums)
 
    }
 
    foo(10, 25, 32, 41)

arguments转成Array

◼ 在开发中,我们经常需要将arguments转成Array,以便使用数组的一些特性。
 常见的转化方式如下
◼ 转化方式一:
 遍历arguments,添加到一个新数组中;
◼ 转化方式二:较难理解(有点绕),了解即可
 调用数组slice函数的call方法;
◼ 转化方式三:ES6中的两个方法
 Array.from
 [...arguments]

// 2.1.将arguments转成数组方式一:
      // var newArguments = []
      // for (var arg of arguments) {
      //   newArguments.push(arg)
      // }
      // console.log(newArguments)
 
      // 2.2.将arguments转成数组方式三: ES6中方式
      // var newArgs1 = Array.from(arguments)
      // console.log(newArgs1)
      // var newArgs2 = [...arguments]
      // console.log(newArgs2)
 
      // 2.3.将arguments转成数组方式二: 调用slice方法
      var newArgs = [].slice.apply(arguments)
      // var newArgs = Array.prototype.slice.apply(arguments)
      console.log(newArgs)

箭头函数不绑定arguments

箭头函数是不绑定arguments的,所以我们在箭头函数中使用arguments会去上层作用域查找

 // 1.箭头函数不绑定arguments
    var bar = () => {
       console.log(arguments)
     }
 
    bar(11, 22, 33)//报错
 
 
    // 2.函数的嵌套箭头函数
    function foo() {
      var bar = () => {
        console.log(arguments)
      }
      bar()
    }
 
    foo(111, 222)//正常运行,因为foo有argument

函数的剩余参数

◼ ES6中引用了rest parameter,可以将不定数量的参数放入到一个数组中:
如果最后一个参数是 ... 为前缀的,那么它会将剩余的参数放到该参数中,并且作为一个数组;

也可以一个函数只有剩余参数


◼ 那么剩余参数和arguments有什么区别呢?
 剩余参数只包含那些没有对应形参的实参,而 arguments 对象包含了传给函数的所有实参;
 arguments对象不是一个真正的数组,而rest参数是一个真正的数组,可以进行数组的所有操作;
 arguments是早期的ECMAScript中为了方便去获取所有的参数提供的一个数据结构,而rest参数是ES6中提供并且希望以此来替代arguments的;
◼ 剩余参数必须放到最后一个位置,否则会报错。

 // 剩余参数: rest parameters
    function foo(num1, num2, ...otherNums) {
      // otherNums数组
      console.log(otherNums)
    }
 
    foo(20, 30, 111, 222, 333)
 
 
    // 默认一个函数只有剩余参数
    function bar(...args) {
      console.log(args)
    }
 
    bar("abc", 123, "cba", 321)
 
    // 注意事项: 剩余参数需要写到其他的参数最后

纯函数的理解和应用

◼ 函数式编程中有一个非常重要的概念叫纯函数,JavaScript符合函数式编程的范式,所以也有纯函数的概念;
 在react开发中纯函数是被多次提及的;
 比如react中组件就被要求像是一个纯函数(为什么是像,因为还有class组件),redux中有一个reducer的概念,也是要求必须是一个纯函数;
 所以掌握纯函数对于理解很多框架的设计是非常有帮助的;


◼ 纯函数的维基百科定义:
 在程序设计中,若一个函数符合以下条件,那么这个函数被称为纯函数:
 此函数在相同的输入值时,需产生相同的输出。
 函数的输出和输入值以外的其他隐藏信息或状态无关,也和由I/O设备产生的外部输出无关。
 该函数不能有语义上可观察的函数副作用,诸如“触发事件”,使输出设备输出,或更改输出值以外物件的内容等。


◼ 当然上面的定义会过于的晦涩,所以简单总结一下:
 确定的输入,一定会产生确定的输出;(不能使用闭包,否则全局变量可能会影响值的输出)
 函数在执行过程中,不能产生副作用;


◼ 那么这里又有一个概念,叫做副作用,什么又是副作用呢?
 在计算机科学中,也引用了副作用的概念,表示在执行一个函数时,除了返回函数值之外,还对调用函数产生了附加的影响,比如修改了全局变量,修改参数或者改变外部的存储;
◼ 纯函数在执行的过程中就是不能产生这样的副作用:
 副作用往往是产生bug的 “温床”。

    function sum(num1, num2) {
      return num1 + num2
    }
 
    // 不是一个纯函数
    var address = "广州市"
    function printInfo(info) {
      console.log(info.name, info.age, info.message)
      info.flag = "已经打印结束"
      address = info.address
    }
 
    var obj = {
      name: "why",
      age: 18,
      message: "哈哈哈哈"
    }
 
    printInfo(obj)
 
    console.log(obj)
    if (obj.flag) {
       
    }

◼ 我们来看一个对数组操作的两个函数:
         slice:slice截取数组时不会对原数组进行任何操作,而是生成一个新的数组;
         splice:splice截取数组, 会返回一个新的数组, 也会对原数组进行修改;
◼ slice就是一个纯函数,不会修改数组本身,而splice函数不是一个纯函数;

纯函数的作用与优势

为什么纯函数在函数式编程中非常重要呢?
 因为你可以安心的编写和安心的使用;
 你在写的时候保证了函数的纯度,只是单纯实现自己的业务逻辑即可,不需要关心传入的内容是如何获得的或者依赖其他的
外部变量是否已经发生了修改;
 你在用的时候,你确定你的输入内容不会被任意篡改,并且自己确定的输入,一定会有确定的输出;


◼ React中就要求我们无论是函数还是class声明一个组件,这个组件都必须像纯函数一样,保护它们的props不被修改:


柯里化的理解和应用

◼ 柯里化也是属于函数式编程里面一个非常重要的概念。
 是一种关于函数的高阶技术;
 它不仅被用于 JavaScript,还被用于其他编程语言;


◼ 我们先来看一下维基百科的解释:
 在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化;
 是把接收多个参数的函数,变成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数,而且返回结果的新函数的技术;
 柯里化声称 “如果你固定某些参数,你将得到接受余下参数的一个函数”;


◼ 维基百科的结束非常的抽象,我们这里做一个总结:
 只传递给函数一部分参数来调用它,让它返回一个函数去处理剩余的参数;
 这个过程就称之为柯里化;


◼ 柯里化是一种函数的转换,将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)。
 柯里化不会调用函数。它只是对函数进行转换。

    // 普通的函数
    function foo1(x, y, z) {
      console.log(x + y + z)
    }
 
    // foo1(10, 20, 30)
    // foo1(20, 33, 55)
 
 
    // 因为foo不是一个柯里化的函数, 所以目前是不能这样调用
    // 柯里化函数
    function foo2(x) {
      return function(y) {
        return function(z) {
          console.log(x + y + z)
        }
      }
    }
 
    foo2(10)(20)(30)
    foo2(20)//无输出值,因为只调用了最外层
 
 
    // 另外一种写法: 箭头函数的写法
    // function foo3(x) {
    //   return y => {
    //     return z => {
    //       console.log(x + y + z)
    //     }
    //   }
    // }
    // 另外一种写法: 箭头函数的简化写法
 
    var foo3 = x => y => z => {
      console.log(x + y + z)
    }
 
    foo3(10)(20)(30)

柯里化优势(没懂)

◼ 那么为什么需要有柯里化呢?
 在函数式编程中,我们其实往往希望一个函数处理的问题尽可能的单一,而不是将一大堆的处理过程交给一个函数来处理;
 那么我们是否就可以将每次传入的参数在单一的函数中进行处理,处理完后在下一个函数中再使用处理后的结果;

◼ 比如上面的案例我们进行一个修改:传入的函数需要分别被进行如下处理
 第一个参数 + 2
 第二个参数 * 2
 第三个参数 ** 2

 ◼ 另外一个使用柯里化的场景是可以帮助我们可以复用参数逻辑:
 makeAdder函数要求我们传入一个num(并且如果我们需要的话,可以在这里对num进行一些修改);
 在之后使用返回的函数时,我们不需要再继续传入num了

 柯里化案例练习

这里我们在演示一个案例,需求是打印一些日志:
 日志包括时间、类型、信息;

    // 案例一: 打印一些日志
    // 信息一: 日志的时间
    // 信息二: 日志的类型: info/debug/feature
    // 信息三: 具体的信息
 
    // 1.没有柯里化的时候做法
    function logInfo(date, type, message) {
      console.log(`时间:${date} 类型:${type} 内容:${message}`)
    }
 
    // // 打印日志
    // logInfo("2022-06-01", "DEBUG", "修复界面搜索按钮点击的bug")
 
    // // 又修复了一个bug
    // logInfo("2022-06-01", "DEBUG", "修复了从服务器请求数据后展示的bug")
    // logInfo("2022-06-01", "DEBUG", "修复了从服务器请求数据后展示的bug")
    // logInfo("2022-06-01", "DEBUG", "修复了从服务器请求数据后展示的bug")
     
    // logInfo("2022-06-01", "FEATURE", "增加了商品的过滤功能")
 
 
    // 2.对函数进行柯里化: 柯里化函数的做法
    // var logInfo = date => type => message => {
    //   console.log(`时间:${date} 类型:${type} 内容:${message}`)
    // }
    function logInfo(date) {
      return function(type) {
        return function(message) {
          console.log(`时间:${date} 类型:${type} 内容:${message}`)
        }
      }
    }
 
    var logToday = logInfo("2022-06-01")
    var logTodayDebug = logToday("DEBUG")
    var logTodayFeature = logToday("FEATURE")
 
    // 打印debug日志
    logTodayDebug("修复了从服务器请求数据后展示的bug")
    logTodayDebug("修复界面搜索按钮点击的bug")
    logTodayDebug("修复界面搜索按钮点击的bug")
    logTodayDebug("修复界面搜索按钮点击的bug")
    logTodayDebug("修复界面搜索按钮点击的bug")
 
    logTodayFeature("新建过滤功能")
    logTodayFeature("新建搜索功能")
    function sum(num1, num2) {
      return num1 + num2
    }
 
    sum(5, 10)
    sum(5, 15)
    sum(5, 18)
 
    // makeAdder函数就是对sum的柯里化
    function makeAdder(count) {
      function add(num) {
        return count + num
      }
      return add
    }
 
    // 1.数字和5相加
    var adder5 = makeAdder(5)
    adder5(10)
    adder5(15)
    adder5(18)
 
    // 2.数组和10相加
    var adder10 = makeAdder(10)
    adder10(10)
    adder10(16)
    adder10(19)
 
    // adder5 = null
    // adder10 = null

柯里化高级-自动科里化函数

with、eval的使用


严格模式的使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/617391.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nginx 之 Tomcat 负载均衡、动静分离

一.详细安装及操作实例&#xff08;Nginx 七层代理&#xff09; 首先至少准备三台服务器 Nginx 服务器&#xff1a;192.168.247.131:80 Tomcat服务器1&#xff1a;192.168.247.133:80 Tomcat服务器2&#xff1a;192.168.247.134:8080 192.168.247.134:80811.部署Nginx 负载均…

微信自动回复怎么设置呢?

友友们 你们是否有以下这些烦恼 1、每天要手动点击“添加”按钮多次以通过大量好友? 2、你是否经常需要在多个微信帐号之间来回切换&#xff1f; 3、你的回复速度慢&#xff0c;导致客户流失率高&#xff1f; 4、为了及时回复&#xff0c;你总是需要带着多部手机出门&…

二十一、C++11(中)

文章目录 一、左值&右值&#xff08;一&#xff09;基本概念1.左值是什么2.右值是什么 &#xff08;二&#xff09;左值引用和右值引用1.左值引用2.右值引用 二、右值引用使用场景和意义&#xff08;一&#xff09;引入&#xff08;二&#xff09;左值引用的使用场景&#…

Linux编译器(gcc/g++)调试器gdb项目自动化构建工具(make/Makefile)版本管理git

Linux编译器-gcc/g&&调试器gdb&&项目自动化构建工具-make/Makefile&&版本管理git &#x1f506;gcc/g的使用可执行文件的"生产"过程gcc如何完成预处理编译汇编链接 函数库函数库一般分为静态库和动态库两种静态C/C库的安装 gcc选项gcc选项记…

WPF 学习:如何照着MaterialDesign的Demo学习

文章目录 往期回顾对应视频资源如何照着wpf项目学习找到你想要抄的页面查找对应源码演示示例如何认清页面元素抄袭实战 项目地址总结 往期回顾 WPF Debug运行是 实时可视化树无效&#xff0c;无法查看代码 WPF MaterialDesign 初学项目实战&#xff08;0&#xff09;:github …

【Java】线程池的概念及使用、ThreadPoolExecutor的构造方法

什么是线程池为什么用线程池JDK提供的线程池工厂模式如何使用 自定义线程池ThreadPoolExecutor类的构造方法工作原理拒绝策略 线程池的使用 什么是线程池 在之前JDBC编程中&#xff0c;通过DataSource获取Connection的时候就已经用到了池的概念。这里的池指的是数据库连接池。…

Vue电商项目--uuid游客身份获取购物车数据

uuid游客身份获取购物车数据 获取购物车列表 请求地址 /api/cart/cartList 请求方式 GET 参数类型 参数名称 类型 是否必选 描述 无 无 无 无 返回示例 成功&#xff1a; { "code": 200, "message": "成功", "…

马尔萨斯 ( Malthus)人口指数增长模型Logistic 模型

3.要求与任务 从 1790 — 1990 年间美国每隔 10 年的人口记录如下表所示&#xff1a; 用以上数据检验马尔萨斯 ( Malthus)人口指数增长模型&#xff0c;根据检验结果进一步讨论马尔萨斯 人口模型的改进&#xff0c;并利用至少两种模型来预测美国2010 年的人口数量。 提示 1 &…

自学黑客(网络安全),一般人我还是劝你算了吧

作为从16年接触网络安全的小白&#xff0c;谈谈零基础如何入门网络安全&#xff0c;有不对的地方&#xff0c;请多多指教。 这些年最后悔的事情莫过于没有把自己学习的东西积累下来形成一个知识体系。 后续我也会陆续的整理网络安全的相关学习资料及文章&#xff0c;与大家一…

数据结构与算法练习(三)二叉树

文章目录 1、树2、二叉树3、满二叉树4、完全二叉树5、二叉树的遍历&#xff08;前序、中序、后序&#xff09;二叉树删除节点或树 6、顺序存储二叉树顺序存储二叉树遍历&#xff08;前序、中序、后序&#xff09; 7、线索化二叉树中序线索二叉树前序线索二叉树后序线索二叉树 1…

Matlab 之 Curve Fitting APP 使用笔记

文章目录 Part.I IntroductionPart.II 使用笔记Chap.I 拟合函数Chap.II 注意事项 Part.I Introduction 曲线或曲面拟合获取拟合参数。本篇博文主要记录一下 Matlab 拟合 APP Curve Fitting 的使用方法。 Part.II 使用笔记 这个APP用来做拟合的&#xff0c;包括二维数据的线拟…

常见的样本统计量及其数字特征

常见的样本统计量及其数字特征 下图来自《统计学图鉴》 样本统计量有什么作用&#xff1f; 因为总体特征包含有总体均值、总体方差等特征&#xff0c;我们在用样本推断总体时&#xff0c;其实就是用样本特征去估计总体特征&#xff0c;例如&#xff1a;样本均值这个统计量的期…

案例33:基于Springboot名城小区物业管理系统开题报告设计

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

Spark RDD统计每日新增用户

文章目录 一&#xff0c;提出任务二&#xff0c;实现思路三&#xff0c;准备工作1、在本地创建用户文件2、将用户文件上传到HDFS指定位置 四&#xff0c;完成任务1、在Spark Shell里完成任务&#xff08;1&#xff09;读取文件&#xff0c;得到RDD&#xff08;2&#xff09;倒排…

为什么要对实体类进行序列化并且要生成序列化ID?

一、为什么要对实体类进行序列化且要生成序列化ID 在Java开发中&#xff0c;实体类将会被用来与其他对象进行交互。Java语言是面向对象的&#xff0c;所以实体类包含了很多信息和方法。序列化是Java中一种将对象转换为字节流的机制&#xff0c;使得对象可以在网络上传输和存储。…

相机成像模型(一)

相机模组 如上图所示相机模组由多个元件组成,其中比较重要的元件包括镜头、感光芯片、驱动芯片。镜头的作用是聚集光线,确保良好的成像环境;感光芯片将光信号转换为电信号;驱动芯片则负责信号处理(去噪、白平衡等)与格式转换。 相机的成像过程为物体通过镜头聚集…

jvm cpu 高定位

快速的发现线程cpu高, 最终发现是gc线程, 最终去分析jvm top -o %CPU top -Hp108920 jmap -dump:formatb,fileheap.bin 108920 jvm 命令和工具_个人渣记录仅为自己搜索用的博客-CSDN博客 $ jstat -gcold 108920 MC MU CCSC CCSU OC OU YGC FGC FGCT GCT 218368.0 212670.3 253…

Java POI技术

引入依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.0.1</version> </dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-oo…

Netty的bytebuf详解

ByteBuf ByteBuf是对nio中ByteBuffer的增强。主要的增强点就是ByteBuf它可以动态调整容量大小&#xff0c;当要存储的数据超过了当前容量的上限就会进行扩容&#xff0c;扩容的上限是多少&#xff1f;扩容机制是什么&#xff1f;请跟着本文往下看。对了&#xff0c;还有一个增强…

区间预测 | MATLAB实现基于QRCNN-GRU卷积门控循环单元多变量时间序列区间预测

区间预测 | MATLAB实现基于QRCNN-GRU卷积门控循环单元多变量时间序列区间预测 目录 区间预测 | MATLAB实现基于QRCNN-GRU卷积门控循环单元多变量时间序列区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 1.Matlab实现基于QRCNN-GRU卷积神经网络结合门控循…