【JavaScript高级】函数相关知识:函数、纯函数、柯里化、严格模式

2023-11-02

函数

函数对象的属性

  • name:可以获得函数的名称
function foo(){

}
console.log(foo.name);//foo
  • length:用于返回函数参数的个数,rest参数不算在内
var bar = (name, age, ...args) => {

}
console.log(bar.length);//2

arguments

arguments 是一个 对应于 传递给函数的参数类数组(array-like) 对象。函数的所有参数都会传给arguments

function foo(x, y) {
  console.log(arguments) // [arguments] {'0': 10, '1': 20, '2': 30, '3': 40}
}
foo(10, 20, 30, 40)

array-like表示它不是一个数组类型,而是一个对象类型:

  • 有数组的一些特性,如length,如可以通过index索引来访问
  • 没有数组的一些方法,比如filter、map等

arguments转Array

将arguments转成Array后可以使用数组的一些特性。

方法1:遍历arguments,添加到一个新数组中

var newArray = []

function foo(x, y) {
    for (arg of arguments) {
        newArray.push(arg);
    }
}

foo(1, 2, 3, 4, 5)

console.log(newArray);//(5) [1, 2, 3, 4, 5]

方法2:调用数组slice函数的call方法,了解即可

对数组做一个截取,截取的是this。
这里slice没有参数,所以是从头截取到尾。
把this绑定到arguments上,就可以截取整个arguments。

function foo() {
    var args1 = [].slice.call(arguments) 
    console.log(args1);
}
foo(1, 2, 3, 4, 5, 6)//(6) [1, 2, 3, 4, 5, 6]

方法3:ES6中的两个方法

  • Array.from
function foo() {
    var args1 = Array.from(arguments)
    console.log(args1);
}
foo(1, 2, 3, 4, 5, 6)//(6) [1, 2, 3, 4, 5, 6]
  • […arguments]
function foo() {
    var args1 = [...arguments]
    console.log(args1);
}
foo(1, 2, 3, 4, 5, 6)//(6) [1, 2, 3, 4, 5, 6]

箭头函数不绑定arguments

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

var bar = () => {
    console.log(arguments);
}
bar(1, 2, 3)
//报错:ncaught ReferenceError: arguments is not defined

箭头函数不绑定arguments,于是就会去上层找:箭头函数——全局——window。发现都没有就报错了。

剩余参数(rest)

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

function foo(x, y, ...rest) {
   console.log(x, y);//1 2
   console.log(rest);//[3,4,5]
}

foo(1, 2, 3, 4, 5)

剩余参数与arguments:

  • 剩余参数只包含没有对应形参的实参,而 arguments 包含了传给函数的所有实参
  • arguments对象不是一个真正的数组,而rest参数一个真正的数组,可以进行数组的所有操作
  • 剩余参数必须放到参数的最后一个位置,否则会报错

纯函数

定义

满足以下要求则此函数为纯函数:

  • 函数相同输入必产生相同输出
  • 函数的输出和输入值与外界的其他隐藏信息或状态无关,也和I/O设备所产生的外部输入无关(其实就是上一条的展开)
  • 该函数不能有语义上可观察的函数副作用,诸如“触发事件”,使输出设备输出,或更改输出值以外物件的内容等

省流版:

  • 确定的输入,一定会产生确定的输出
  • 函数在执行过程中,不能产生副作用

什么是副作用

在执行一个函数时,除了返回函数值之外,还对调用函数产生了附加的影响

如:修改了全局变量,修改参数或者改变外部的存储。

function foo(info) {
  console.log(info.name, info.age, info.height);
  info.flag = "打印结束了";
}

var obj = {
  name: "kaisa",
  age: 18,
  height: 1.88,
};

foo(obj);
console.log(obj);

这里调用函数就为obj添加了一个flag属性,这就是副作用。

纯函数在执行过程中不能产生这样的副作用,因为副作用是bug的温床。

纯函数的案例

1

var names = ["aaa", "bbb", "ccc", "ddd"];

// slice截取数组时不会对原数组进行任何操作, 而是生成一个新的数组
var newNames1 = names.slice(0, 2);
console.log(newNames1);

// splice截取数组, 会返回一个新的数组, 也会对原数组进行修改
var newNames2 = names.splice(0, 2);
console.log(newNames2);
console.log(names);

slice是纯函数,splice函数不是纯函数。

2

function foo(item1, item2) {
  return = item1 + item2
}

是纯函数.

3

var foo = 5;

function add(num) {
  return foo + num;
}

console.log(add(5)); // 10
foo = 10;
console.log(add(5)); // 15

不是纯函数.

4

function printInfo(info) {
  console.log(info.namem, info.age);
  info.name = "哈哈哈";
}

不是纯函数.

作用和优势

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

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

柯里化

定义

只传递给函数一部分参数来调用它,让它返回一个函数去处理剩余的参数,这个过程就称之为柯里化

也就是将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)©

举个例子:

柯里化前:

function foo(x, y, z) {
  console.log(x + y + z) // 60
}
foo(10, 20, 30)

柯里化后:

// 柯里化函数 普通写法
function foo1(x) {
  return function foo2(y) {
    return function foo3(z) {
      console.log(x + y + z); // 60
    };
  };
}
foo1(10)(20)(30);
// 柯里化函数 箭头函数写法
var foo = (x) => {
  return (y) => {
    return (z) => {
      console.log(x + y + z);
    };
  };
};
foo(10)(20)(30);

// 简写箭头函数
var foo1 = x => y => z => console.log(x + y + z);
foo1(10)(20)(30);

优势

优势1:函数的职责单一

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

如:传入的函数需要分别被进行如下处理

  1. +2
  2. *2
  3. **2
function foo(x) {
   x = x + 2;
   return function foo1(y) {
       y = y * 2;
       return function foo2(z) {
           z = z ** 2;
           return x + y + z;
       }
   }
}

优势2:函数的参数复用

function makeAdder(num) {
  return function (count) {
    return num + count;
  };
}

// 将num参数固定为5, 以后和5相加, 只需要调用add5
var add5 = makeAdder(5);
add5(10); // 15
add5(100); // 105

// 将num参数固定为10, 以后和10相加, 只需要调用add10
var add10 = makeAdder(10);
add10(10); // 20
add10(100); // 110

自动柯里化

实际开发中, 一般引用的第三库中都有自动柯里化的函数。

组合函数

定义

一种对函数的使用技巧、模式。举个例子:我们想对多个数字进行先*2,再平方的操作。

不组合:

function fn1(num) {
   return num * 2;
}

function fn2(num) {
    return num ** 2;
}

console.log(fn2(fn1(10)));//400
console.log(fn2(fn1(20)));//1600

组合:

function fn3(num){
    return fn2(fn1(num))
}

console.log(fn3(10));//400
console.log(fn3(20));//1600

组合函数的封装

了解即可。
在这里插入图片描述

其他

with语句

with语句扩展一个语句的作用域链
不建议使用 with语句,因为它可能是混淆错误和兼容性问题的根源。

这里如果没有with,js会直接在全局里面找。使用with就可以查找obj中的属性。

var obj = {
  name: "kaisa",
  age: 18,
  height: 1.88,
};

//使用with可以查找obj中的属性
with (obj) {
  console.log(name, age, height);
}

更多可以看看这里:JavaScript中 with的用法

eval函数

内建(内置)函数 eval 允许执行一个代码字符串。

eval是一个特殊的函数,它可以将传入的字符串当做JavaScript代码来运行,如:

var string = `var name = "kaisa";
              console.log(name);`;
eval(string); // kaisa

eval会将最后一句执行语句的结果,作为返回值,如:

var string = `var name = "kaisa";
              console.log(name);
              123`;
var result = eval(string);
console.log(result) // 123

不建议在开发中使用eval:

  • 可读性差(代码的可读性是高质量代码的重要原则)
  • eval是一个字符串,有可能在执行过程中被篡改,会造成被攻击的风险
  • eval的执行必须经过JavaScript解释器,不能被 JavaScript引擎 优化

严格模式

定义

  • 一种具有限制性的JavaScript模式,从而使代码隐式的脱离了 ”懒散(sloppy)模式“
  • 支持严格模式的浏览器在检测到代码中有严格模式时,会以更加严格的方式对代码进行检测和执行

严格模式对正常的JavaScript语义进行了一些限制:

  • 通过 抛出错误 来消除一些原有的 静默(silent) 错误
  • 让JS引擎在执行代码时可以进行更多的优化(不需要对一些特殊的语法进行处理)
  • 禁用了在ECMAScript未来版本中可能会定义的一些语法

开启

可以在js文件开启,也可以对某一个函数开启。

严格模式通过在文件或者函数开头使用 use strict 来开启

文件:

<script>
  // 给整个script标签开启严格模式
  "use strict"
</script>

函数:

function foo() {
  // 在foo函数作用域中开启严格模式
  "use strict";
}
  • 没有类似于 “no use strict” 这样的指令可以使程序返回默认模式
  • 现代 JavaScript 支持 “class” 和 “module” ,它们会自动启用 use strict

限制

更具体的可以看这里:JavaScript 严格模式(use strict)

在非严格模式下,一些错误也被认为是正确的,但在严格模式下就会报错。如:

1.无法意外的创建全局变量

在非严格模式下, 不使用var变量创建变量, 会默认创建到全局变量
在严格模式下是不允许的,会报错

2.严格模式会使引起静默失败(silently fail,注:不报错也没有任何效果) 的赋值操作抛出异常

"use strict"
var obj = {
	name: "why"
}

// 明确设置obj对象中的name属性不可修改
Object.defineProperty(obj, "name", {
  writable: false
})

obj.name = "kobe"
console.log(obj.name); // name

非严格模式下不允许修改, 但是也不会报错
严格模式下, 明确说明obj中的name不可修改, 如果修改就会报错

3.严格模式下试图删除不可删除的属性会报错

非严格模式下, 不允许删除, 也不会报错。(无事发生)

4.严格模式不允许函数参数有相同的名称

非严格模式下允许。

5.严格模式不允许0开头的八进制语法

非严格模式下, 0开头的数字都会被默认为八进制
严格模式下, 0开头8进制是不允许写的, 0o是允许的

6.严格模式下,不允许使用with

7.严格模式下,eval不能为上层创建变量

8.严格模式下,this绑定不会默认转成对象

非严格模式下, 字符串和数字类型会转换成对应的包装类对象
严格模式下, 不会转换成对象, 且严格模式下独立函数调用不绑定全局对象window, 而是一个undefined

参考

coderwhy的课
JS高级函数的增强使用、纯函数、柯里化、组合函数的详细介绍-及手写柯里化、手写组合函数
JavaScript函数式编程(纯函数、柯里化以及组合函数)
JavaScript函数的增强知识(argument、纯函数)
MDN-with语句
JavaScript中 with的用法
JavaScript 严格模式(use strict)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【JavaScript高级】函数相关知识:函数、纯函数、柯里化、严格模式 的相关文章

  • JavaScript onTouch 不工作

    谁能告诉我为什么这个 onTouch 处理程序没有触发 var myDiv document getElementById existingContent var myButton a href log out a myDiv append
  • React js Stripe 结账不起作用

    我正在尝试在 React js 应用程序中呈现条带结账默认表单
  • 了解设置 JQuery 变量

    了解设置 JQuery 变量 最近 我通过在 StackOverflow 上遇到的另一个问题寻找帮助 了解到如何设置 JQuery 变量 如下所示 您可以通过简单地调用变量来创建输入字段 并且锚变量似乎也定义了样式 var clicked
  • 为什么 JavaScript base-36 转换看起来不明确

    我目前正在编写一段使用 Base 36 编码的 JavaScript 我遇到了这个问题 parseInt welcomeback 36 toString 36 看来要回归了 welcomebacg 我在 Chrome 开发者控制台和 Nod
  • 在 Vue.js 中从父组件执行子方法

    目前 我有一个 Vue js 组件 其中包含其他组件的列表 我知道使用 vue 的常见方式是将数据传递给孩子 并从孩子向父母发出事件 但是 在这种情况下 我想在子组件中的按钮出现时执行子组件中的方法 parent被点击 哪种方法最好 一种建
  • 解析“流”JSON

    我在浏览器中有一个网格 我想通过 JSON 将数据行发送到网格 但浏览器应该在接收到 JSON 时不断解析它 并在解析时将行添加到网格中 换句话说 在接收到整个 JSON 对象后 不应将行全部添加到网格中 应该在接收到行时将其添加到网格中
  • 如何重定向到 instagram://user?username={username}

    我的 html 页面上有这个链接 可以在特定用户上打开 Instagram 应用程序 a href Link to Instagram Profile a 我一直在寻找自动运行 url instagram user username USE
  • 如何重置使用 JavaScript 更改的 CSS 属性?

    我的导航按钮的宽度从 100px 增加到 150px 当鼠标悬停在 nav li hover width 150px 但是使用 javascript 我已经做到了 无论选择哪个选项 宽度都将继续为 150px 当选择每个选项时 它会使其他选
  • 使用模数按字母顺序对列表进行排序

    我在获取元素列表并按字母顺序对它们进行排序方面没有任何问题 但我很难理解如何使用模数来做到这一点 更新 这是按我的方式工作的代码 但是 我更喜欢下面提供的答案的可重用性 因此接受了该答案
  • Node.js:如何在检索数据(块)时关闭响应/请求

    我正在用 node js 构建一个应用程序 它加载多个页面并分析内容 因为 node js 发送块 所以我可以分析这些块 如果一个块包含例如索引 nofollow 我想关闭该连接并继续其余部分 var host example com to
  • 从未用 @flow 标记的导入文件中获取类型定义

    TL DR我怎么告诉flow从未声明的导入模块导入类型定义 flow 加长版 流接缝能够从不使用流语法的文件中派生类型 请参阅示例 示例文件 flow js if Math random lt 0 5 var y hello else va
  • 为什么是 javascript:history.go(-1);无法在移动设备上工作?

    首先 一些背景 我有一个向用户呈现搜索页面 html 表单 的应用程序 填写标准并单击 搜索 按钮后 结果将显示在标准部分下方 在结果列表中 您可以通过单击将您带到新页面的链接来查看单个结果的详细信息 在详细信息页面中 我添加了一个 返回结
  • JavaScript 重定向到新窗口

    我有以下代码 它根据下拉列表的值重定向到页面 我如何使其在新窗口中打开 function goto form var index form select selectedIndex if form select options index
  • 如何将 Google Charts 与 Vue.js 库一起使用?

    我正在尝试使用 Vue js 库使用 Google Charts 制作图表 但我不知道如何添加到 div 这是我尝试做的 这是如何使用普通 javascript 添加图表 这是文档的代码示例 https developers google
  • 使用 KnockoutJs 映射插件进行递归模板化

    我正在尝试使用以下方法在树上进行递归模板化ko映射 插入 http knockoutjs com documentation plugins mapping html 但我无法渲染它 除非我定义separate每个级别的模板 在以下情况下
  • Firefox 书签探索未超过 Javascript 的第一级

    我已经编写了一些代码来探索我的 Firefox 书签 但我只获得了第一级书签 即我没有获得文件夹中的链接 e g 搜索引擎 雅虎网站 谷歌网站 在此示例中 我只能访问 Search engines 和 google com 不能访问 yah
  • HTML 离线应用程序缓存,列出下载的文件

    作为我正在构建的离线 Web 应用程序的加载屏幕的一部分 使用缓存清单 http developer apple com library safari documentation iPhone Conceptual SafariJSData
  • FireFox 中的自动滚动

    我的应用程序是实时聊天 我有一个 Div 来包装消息 每条消息都是一个 div 所以 在几条消息之后 我的 DOM 看起来像这样 div div Message number two div div div div
  • 如何在类似控制台的环境中运行 JavaScript?

    我正在尝试遵循这里的示例 http eloquentjavascript net chapter2 html http eloquentjavascript net chapter2 html and print blah 在浏览器中运行时
  • JQuery 图像上传不适用于未来的活动

    我希望我的用户可以通过帖子上传图像 因此 每个回复表单都有一个上传表单 用户可以通过单击上传按钮上传图像 然后单击提交来提交帖子 现在我的上传表单可以上传第一个回复的图像 但第二个回复的上传不起作用 我的提交过程 Ajax 在 php 提交

随机推荐

  • 如何在 Ubuntu 18.04 上安装 R

    R 是一种快速发展的开源编程语言和免费环境 专门从事统计计算和图形表示 它由 R 统计计算基金会支持 主要供统计学家和数据挖掘人员用于开发统计软件和执行数据分析 本教程将指导您完成在 Ubuntu 18 04 计算机上安装 R 的步骤 先决
  • 如何在 Linux 中复制文件和目录

    复制文件和目录是使用命令行时最常见的任务之一 Linux 中有多种用于复制文件的命令 其中cp and rsync是使用最广泛的工具 通常的做法是使用cp复制文件的命令和rsync复制目录 为了能够复制文件和目录 您必须至少具有源文件的读取
  • 如何在 Ubuntu 18.04 上安装和使用 Docker Compose

    Docker 组合是一个允许您定义和管理多容器 Docker 应用程序的工具 它使用 YAML 文件来配置应用程序的服务 网络和卷 Compose 可用于不同的目的 单主机应用程序部署 自动化测试和本地开发是 Docker Compose
  • 如何设置无密码 SSH 登录

    Secure Shell SSH 是一种加密网络协议 用于客户端和服务器之间的安全连接 支持多种身份验证机制 两种最流行的机制是基于密码的身份验证和基于公钥的身份验证 在本教程中 我们将向您展示如何设置基于 SSH 密钥的身份验证以及如何在
  • 如何在 Ubuntu 20.04 上安装 Visual Studio Code

    视觉工作室代码是微软开发的一款功能强大的开源代码编辑器 它具有内置的调试支持 嵌入式Git控制 语法突出显示 代码完成 集成终端 代码重构和片段 Visual Studio Code 是跨平台的 可在 Windows Linux 和 mac
  • 如何在 Debian 10 Linux 上安装 Webmin

    Webmin是一个用于管理 Linux 服务器的开源 Web 控制面板 它允许您管理系统用户 组 磁盘配额以及安装和配置 Web ssh ftp 电子邮件和数据库服务器 使用 Webmin 您几乎可以配置系统的每个方面 在本教程中 我们将向
  • 如何在 Ubuntu 18.04 上安装 Kvm

    KVM 基于内核的虚拟机 是内置于 Linux 内核中的开源虚拟化技术 它允许您运行多个基于 Linux 或 Windows 的隔离来宾虚拟机 每个来宾都有自己的操作系统和专用虚拟硬件 例如 CPU 内存 网络接口和存储 本指南介绍如何在
  • 如何在 Debian 10 上安装 Elasticsearch

    Elasticsearch 是一个开源分布式全文搜索和分析引擎 它支持 RESTful 操作 允许您实时存储 搜索和分析大量数据 Elasticsearch 是最流行的搜索引擎之一 为具有复杂搜索要求的应用程序 例如大型电子商务商店和分析应
  • (see DUPEFILTER_DEBUG to show all duplicates)

    出现 see DUPEFILTER DEBUG to show all duplicates 的原因 在爬虫出现了重复的链接 重复的请求 解决方法 在request添加dont filter True
  • 常见反爬虫方法以及怎样突破

    大家可能不知道 互联网中超过一半的流量是网络爬虫贡献的 若是网站不设置反爬虫机制 可能根本没法运营 于是都设置了各种各样的反爬虫机制 即使如此 网络爬虫还是有办法去突破 今天小编为大家介绍一些常见的反网络爬虫以及突破方法 1 动态页面限制
  • [阶段4 企业开发进阶] 7. 微服务--SpringCloud Alibaba

    文章目录 1 服务注册和配置中心Nacos 1 1 Nacos简介 1 2 Nacos作为服务注册中心 服务提供者注册 服务消费者注册和负载 服务注册中心对比 1 3 Nacos作为服务配置中心 基础配置 分类配置 DataID方案配置 G
  • 转载:中国电信、网通、联通ADSL用户必读:中国电信、网通、联通劫持dns(浏览器)解决方案

    中国电信 网通 联通ADSL用户必读 中国电信 网通 联通劫持dns 中国电信 网通 联通劫持ie浏览器 解决方案D 宽带连接有 也能上网但是本地连接一直显示为受限制的解决方法 我的电脑一直显示本地连接受限制或无连接而宽带连接能连上 这是为
  • Spring Cloud 集成Gson 包冲突

    昨天再引入包的时候 Run了下main直接报错 就知道是包版本冲突了 然后添加的包排除 启动是正常了 但是项目一跑方法直接抛出来 gson转换异常 所以又得放开 于是尝试下引入Gson包试试
  • 3D文档(BRD、MRD、PRD)怎么写

    3D文档 一般来说 BRD作为战略方向的制定 是最早产出的文档 而MRD则是在战略方向的基础上对市场进行的分析 同时对后续工作的方向进行一些说明和指导 也可以说是通过对市场环境 竞品的分析 明确用户定位和产品定位的过程 PRD则是在战略方向
  • rpm的安装和卸载

    1 安装rpm包 强制安装目录下所有rpm包 rpm ivh rpm force nodeps 2 卸载rpm包 rpm e 包名 rpm nodeps
  • Buck的振铃实验与分析

    上上期我们提到了buck电路的开关的振铃波形 本质原因是LC的阻尼振荡 文章偏理论 那BUCK到底是怎么产生尖峰振荡呢 要想把这个问题搞清楚 也很是不容易 所以文章有点长 请直接点赞转发加收藏 问题 本期主要分析以下这两个问题 1 死区时间
  • 缩尾处理 stata

    要求 对连续变量上下1 的分位数进行了缩尾处理 目录 安装 具体命令 疑问1 需要对所有变量缩尾吗 疑问2 面板数据每年的截面数据分别进行处理吗 还是这么多年都混在一起处理 安装 ssc install winsor2 结果发现自己卡在了第
  • android 绘图之Path与Paint详解 - 冷冷汤圆

    http www cnblogs com aibuli p efef9d774df97c553a8a0c0c3495ba35 html utm source tuicool utm medium referral
  • 注释转换小项目(c注释->到c++注释)

    首先欢迎阅读本文 注释转换小项目涉及到c语言对文件的操作 另外这个小项目还应该对各种情况都考虑到 将c语言注释转换为c 注释 经过分析思考 我得到证据要的注释转换有以下几类 我将之整理并放入一个文件里 起名input c 1 一般情况 in
  • 【JavaScript高级】函数相关知识:函数、纯函数、柯里化、严格模式

    文章目录 函数 函数对象的属性 arguments arguments转Array 箭头函数不绑定arguments 剩余参数 rest 纯函数 定义 纯函数的案例 作用和优势 柯里化 定义 优势 自动柯里化 组合函数 定义 组合函数的封装