当前位置: 首页 > news >正文

js 函数、闭包及函数对象

 js的函数是对象,可以通过程序来操控。比如,可以把函数赋值给变量,然后再传递给其他函数,也可以在函数上设置属性,甚至调用函数的方法。

js函数可以嵌套定义在其他函数里,内嵌函数可以访问定义在函数作用域的任何变量。这意味着js函数是闭包,基于闭包可以实现重要且强大的编程技巧。

1 定义函数

function关键字可以用作函数声明或表达式。ES6定义了“箭头函数”,语法特别简洁,很适合把函数作为参数传给另一个函数。

1.1 函数声明

例如 function fun(x,y) {}

1)函数的名字变成了一个变量,这个变量的值就是函数本身。

2)函数声明语句会被“提升”到包含脚本、函数或代码块的顶部,因此,调用代码可以出现在函数定义代码之前。

1.2 函数表达式

很像函数声明,但函数表达式出现在复杂表达式或语句的上下文中,而且函数名是可选的。例如:

cosnt fun1 = function(x) { return x + 1; };

// 函数表达式可以包含名字,这对递归有用。

const fun2 = function fun(x) { if (x <= 1) return 1; else return fun(x-1); };

// 可以作为其他函数的参数

[1,2,3].sort(function(a,b) { return a-b; });

// 可以定义完立即调用

let resutl = (function(x) { return x * x; }(10)); // result = 100

表达式函数不能在它们定义之前被调用。

1.3 箭头函数

ES6中定义的,一般形式是圆括号中逗号分隔的参数列表,后跟箭头=>,再跟包含在花括号中的函数体,例如:

(x,y) => { return x+y; }

// 函数体中只有一个return语句时,可以省略return关键字、语句末尾的分号以及花括号

(x,y) => x+y

// 只有一个参数时,也可省略包围参数列表的圆括号

x => x * x

// 对于没有参数的箭头函数,则必须把空圆括号写出来

() => 37

箭头函数相比于其他方式定义的函数,有关极其重要的区别:箭头函数从定义自己的环境继承this值。而不想其他方式定义的函数从调用上下文继承this值。而且箭头函数没有prototype属性。

2 调用函数

js函数可以通过5种方式来调用:1)作为函数;2)作为方法;3)作为构造函数;4)通过call()或apply()方法间接调用;5)通过js语言特性隐式调用。

函数调用

对于非严格模式下的函数调用,this值是全局对象。但在严格模式下,this值是undefined。

方法调用

this值是调用它的对象。

箭头函数

总是继承自身定义所在环境的this值。

表 函数调用、方法调用及箭头函数的this值

隐式函数调用:对象属性的设置或获取方法、代理对象等。

2.1 构造函数调用

如果函数或方法调用前面加了一个关键字,那它就是构造函数调用。

例如:let o = new Object();

与常规函数的区别在于参数处理、调用上下文(this)和返回值。

构造函数调用会创建一个新的空对象,这个对象继承构造函数的prototype属性指定的对象。新创建的对象会被复制到这个函数的this中。例如:

let obj = new o.m(); 在方法m中,this值是这个被创建的对象而不是o。

构造函数正常情况下不使用return关键字,但是如果构造器函数显式使用啦return语句返回某个对象,那么这个对象就会变成调用表达式的值。如果没有使用return 或者 return 的是一个原始值,则这个返回值会被忽略,仍然以新创建的对象作为调用表达式的值。

3 函数作为值

js 中函数是一个对象。

function fun() {}; //定义一个fun函数,fun是引用函数对象的一个变量名。

let o = {fun: function() {}}; //把函数赋值给对象的属性

3.1 定义函数自己的属性

如果一个函数需要一个“静态”变量,且这个变量的值需要在函数每次调用时都能访问到,则通常把这个变量定义为函数自身的一个属性。例如:

fun.counter = 0;

function fun() { return fun.counter++; }

fun(); // 0

fun(); // 1

4 闭包

js使用词法作用域,这意味着函数执行时使用的是定义函数时生效的变量作用域,而不是调用函数时生效的变量作用域。js函数对象内部不仅要包括函数代码,还要包括对函数定义所在作用域的引用。这种函数对象与作用域(即一组变量绑定)组合起来解析函数变量的机制,被称作闭包。

4.1 闭包的作用

闭包真正值得关注的时候,是定义函数与调用函数的作用域不同的时候。

最常见的情形是一个函数返回了在它内部定义的嵌套函数。

let scope = "global";

function fun() {

let scope = "fun-local";

return function() { return scope }

}。

console.log(fun()());  //fun-local

闭包的本质是:它们会捕获自身定义所在外部函数的局部变量绑定。

let addFun = ( function () {

let count = 0;

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

}());

console.log(addFun()); // 0

console.log(addFun()); // 1

在上面代码中,不能通过其他方式直接操作count变量,只能通过addFun这个函数。这样就实现了一个通用的共享私有状态的函数。

4.2 var 和 let 作用域问题

function fun() {

let funArr = [];

for (var i = 0; i < 3; i++) {

funArr[i] = () => i;

}

return funArr

}

let funArr = fun();

console.log(funArr[0]());   // 3

console.log(funArr[1]()) ;  // 3

console.log(funArr[2]());  // 3

这跟我们预期结果不同,预期结果是:1、2、3 而不是全都是3。这是因为var作用域提升到了fun()函数顶部,而不是只局限于1次循环,而且与闭包关联的作用域是“活的”,所以在for循环中,修改了i的变量值,最后值变为3,在后续调用中,都共同访问了i这个变量,所以返回的值都是3。

ES6增加了块级作用域变量解决了这个问题,只要把var替换成let或者const。

function fun() {

let funArr = [];

for (let i = 0; i < 3; i++) {

funArr[i] = () => i;

}

return funArr

} l

et funArr = fun();

console.log(funArr[0]());  // 0

console.log(funArr[1]());  // 1

console.log(funArr[2]());  // 2

let 和const是块级作用域的标志,这意味着每一次循环都会定义一个与其他循环不同的独立作用域,而每个作用域中都有自己独立的i绑定。

5 函数属性、方法和构造函数

5.1 call()和apply()方法

运行间接调用一个函数,就像这个函数是某个其他对象的方法一样。第一个参数是要在其上调用这个函数的对象,也就是函数的上下文(this)。

function fun() { console.log(this) }

let obj = { name: ‘obj’}

fun.call(obj);

其中fun.call(obj);的作用相当于:

obj.m = fun;

obj.m();

delete obj.m;

如果箭头函数调用call()及apply()方法,则第一个参数实际上会被忽略。

除了第一个参数,后续所有参数都会传给被调用的函数,apply()方法与call()方法类似,只不过要传给函数的参数需要以数组的形式提供,例如:

function fun(x,y,z) {};

let obj = {};

fun.call(obj,1,2,3); //等价于fun.apply(obj,[1,2,3])

5.2 bind()方法

把函数绑定到对象上,bind()方法第一个参数是要绑定的对象。这个方法会绑定一个新的函数,如果作为函数来调用这个新函数,就会像f是绑定对象的方法一样调用原始函数。

function fun() { console.log(this.x) }

let obj = {x:3};

let newFun = fun.bind(obj)

newFun(); // 3

console.log(obj); // { x: 3 },注意,bind()方法并不会改变该对象的结构,即obj实际上是没有fun这个方法

let obj2 = {x:4, newFun}; obj2.newFun(); // 3, 仍然是像fun是obj上的方法一样,即始终是obj调用了fun

注意,箭头函数调用了bind方法绑定不会起作用。

5.2.1 绑定部分应用

bind()方法也可以执行“部分应用”,即在第一个参数之后传给bind()的参数也会随着this值一起被绑定。

let sum = (x,y) => x + y;

let fun1 = sum.bind(null,3)

console.log(fun1(2,4)); // 5. sum函数中x已被绑定,fun1()形参只有一个y

5.3 Function()构造函数

const f = new Function(“x”,”y”,”return x+y;”); 相当于

const f = function(x,y) { return x+y; };

最后一个参数是函数体文本,可以包含任意js语句,相互以分号分隔。其他参数是新函数的参数名。

Function()构造函数的主要作用是:动态创建和编译函数。

Function()创建的函数不使用词法作用域,而是始终编译为如同顶级函数一样。

let scope = "global";

function fun() {

let scope = "fun-local";

return new Function("console.log(scope)");

}

 fun()(); // 报错 scope is not defined

不要在Function构造函数的参数文本中,读取该参数文本以外的变量。

相关文章:

js 函数、闭包及函数对象

js的函数是对象&#xff0c;可以通过程序来操控。比如&#xff0c;可以把函数赋值给变量&#xff0c;然后再传递给其他函数&#xff0c;也可以在函数上设置属性&#xff0c;甚至调用函数的方法。 js函数可以嵌套定义在其他函数里&#xff0c;内嵌函数可以访问定义在函数作用域…...

SSM(Vue3+ElementPlus+Axios+SSM前后端分离)--搭建Vue 前端工程[二]

文章目录 SSM--搭建Vue 前端工程--项目基础界面实现功能02-创建项目基础界面需求分析效果图思路分析 代码实现项目前后端分离情况项目前后端分离情况如图 注意事项和细节 SSM–搭建Vue 前端工程–项目基础界面 实现功能02-创建项目基础界面 需求分析 效果图 思路分析 使用V…...

Android 之 AudioManager ( 音频管理器 )

本节引言&#xff1a; 在多媒体的第一节&#xff0c;我们用SoundPool写了个Duang的示例&#xff0c;小猪点击一个按钮后&#xff0c;突然发出"Duang"的 一声&#xff0c;而且当时的声音很大&#xff0c;吓死宝宝了 &#xff0c;好在不是上班时间&#xff0c;上班时间…...

2023爱分析·超自动化厂商全景报告|爱分析报告

关键发现 当前的超自动化定义主要从技术组合角度阐述超自动化内涵&#xff0c;较难和业务价值建立链接。爱分析对超自动化作如下新定义&#xff1a;超自动化指利用RPA、iPaaS、AI、低代码、BPM、流程挖掘等自动化技术&#xff0c;实现组织端到端流程自动化以及新业务流程快速编…...

【C++进阶知识】04 - 函数默认实参、默认初始化、initializer_list

1. 函数默认实参 默认实参需要注意以下几点&#xff1a; &#xff08;1&#xff09;函数默认实参的赋值应从右往左&#xff0c;否则编译报错&#xff0c;因为参数入栈应该从右往左。 void f(int, int, int 1); void f(int, int 2, int); void f(int 3, int, int);&#x…...

C语言笔试训练【第三天】

大家好&#xff0c;我是纪宁。 今天是C语言笔试训练的第三天&#xff0c;大家加油&#xff01; 第一题 1、已知函数的原型是&#xff1a; int fun(char b[10], int *a) &#xff0c;设定义&#xff1a; char c[10];int d; &#xff0c;正确的调用语句是&#xff08; &#xf…...

Android SystemServer中Service的创建和启动方式(基于Android13)

Android SystemServer创建和启动方式(基于Android13) SystemServer 简介 Android System Server是Android框架的核心组件&#xff0c;运行在system_server进程中&#xff0c;拥有system权限。它在Android系统中扮演重要角色&#xff0c;提供服务管理和通信。 system …...

Meta开源AI音频和音乐生成模型

在过去的几年里&#xff0c;我们看到了AI在图像、视频和文本生成方面的巨大进步。然而&#xff0c;音频生成领域的进展却相对滞后。MetaAI这次再为开源贡献重磅产品&#xff1a;AudioCraft&#xff0c;一个支持多个音频生成模型的音频生成开发框架。 AudioCraft开源地址 开源地…...

rust怎么解析json数据?

关注我&#xff0c;学习Rust不迷路&#xff01;&#xff01; 在 Rust 中&#xff0c;你可以使用 serde 库来实现结构体与 JSON 之间的互相转换。 serde 是 Rust 社区最常用的序列化和反序列化库&#xff0c;它提供了方便的功能来处理结构体与 JSON 之间的转换。 首先&#xff…...

STM32 NOR_FLASH 学习

NOR FLASH FLASH是常用的&#xff0c;用于存储数据的半导体器件&#xff0c;它具有容量大&#xff0c;可重复擦写、按“扇区/块”擦除、掉电后数据可继续保存的特性。 NOR FLASH的单位是MB&#xff0c;EEPROM的单位是KB。 NM25Q128&#xff0c;是NOR FLASH的一种&#xff0c…...

【数据结构|二叉树遍历】递归与非递归实现前序遍历、中序遍历、后序遍历

递归与非递归实现二叉树的前序遍历、中序遍历、后序遍历。 二叉树图 定义 前序遍历&#xff08;Preorder Traversal&#xff09;&#xff1a; 前序遍历的顺序是先访问根节点&#xff0c;然后按照先左后右的顺序访问子节点。对于上面的二叉树&#xff0c;前序遍历的结果是&…...

iPhone 8 Plus透明屏有哪些场景化应用?

iPhone 8 Plus是苹果公司于2017年推出的一款智能手机&#xff0c;它采用了全新的玻璃机身设计&#xff0c;使得手机更加美观和时尚。 而透明屏则是一种新型的屏幕技术&#xff0c;可以使手机屏幕呈现出透明的效果&#xff0c;给人一种科技感十足的视觉体验。 透明屏是通过使用…...

解决 MySQL 删除数据后,ID 自增不连续问题

修复前 除了部分数据&#xff0c;导致后续新增的数据&#xff0c;ID 自增不连续 解决方案 执行下方 SQL 语句即可修复此问题&#xff0c;mbs_order为需要修复的表名 SET i0; UPDATE mbs_order SET id(i:i1); ALTER TABLE mbs_order AUTO_INCREMENT0;...

arcgis--网络分析(理论篇)

1、定义概念 &#xff08;1&#xff09;网络&#xff1a;由一系列相互联通的点和线组成&#xff0c;用来描述地理要素&#xff08;资源&#xff09;的流动情况。 &#xff08;2&#xff09;网络分析&#xff1a;对地理网络&#xff08;如交通网络、水系网络&#xff09;&…...

Linux笔记1(系统状态等)

man命令&#xff1a; man name: man section name: man -k regexp: 在 Linux 中&#xff0c;man 命令用于查看命令、函数或配置文件等的手册页&#xff0c;提供了详细的帮助文档。man 是 "manual" 的缩写。man 命令的用法如下&#xff1a; man [选项] [命令名]例如&…...

Set-up ESP-AT Environment on Windows using CMD

Before you start, the following environments need to be installed: Git BashPython environment, suggest Python version: 3.8.7. Please ensure the installation of Python v3.8 version environment, and remember to select the option “add to PATH” during the in…...

SpringBoot中Redis报错:NOAUTH Authentication required

1、问题 org.springframework.dao.InvalidDataAccessApiUsageException: NOAUTH Authentication required.; nested exception is redis.clients.jedis.exceptions.JedisDataException: NOAUTH Authentication required. … 2、解决 如果提供了密码还没解决&#xff0c;那可能是…...

需求飙升120%!芭比产品火爆出圈,意大利人争相购买!

据外媒报道&#xff0c;真人版《芭比》成为今年夏天最火的电影&#xff0c;仅在美国和加拿大&#xff0c;该影片的票房收入就超过3.5亿美元。在意大利《芭比》也备受追捧&#xff0c;目前的票房收入突破1670万欧元&#xff0c;成为2023年观看人数第三多的电影。 除了电影界之外…...

echarts-pie---------3D曲状环形饼图实现!!!

示例&#xff08;参考此处饼图修改https://www.isqqw.com/viewer?id37497&#xff09; 话不多说直接上代码 此套代码可以直接再echarts官网中的此处运行 let selectedIndex ; let hoveredIndex ; option getPie3D([{name: 数学,value: 60,itemStyle: {color: #1890FF,},},{…...

合并两个有序链表(leetcode)

题目 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4]思路 每次递归都会比较当前两个节点的值&#xff0c;选择较小的节点作为合并后的链…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...