本文基于: Bilibili - 自由的加百利

前置条件:

  • 需掌握函数的编写、传参、返回、调用
  • 理解作用域、掌握定时器的用法
  • 知道引用类型和基本数据类型的区别
  • 知道函数也是引用类型
  • 听说过同步异步的概念
  • 了解类和对象的关系

匿名函数

来看一下一个函数的基本属性:

匿名函数的自运行

我们可以将一个普通函数去掉它的名字,这样就成功的创建了一个匿名函数,并且编译器不会报错。

那么这个函数既然没有名字,我们又该怎么调用它呢?这时只需要使用一个小括号包裹住整个函数,再在函数体的末尾添加一个小括号就可以在创建函数之后立即执行这个函数。

这种写法,也叫作 匿名函数的自运行

其与直接在外部书写函数体内部的语句相比,优点就是不会造成变量污染,会在匿名函数内形成一个 封闭的作用域

小括号的作用

在匿名函数的外部加上一个小括号,实际的作用是 将该函数的声明变成了一个优先计算的表达式

( function(){...} )()

而表达式的运算结果就是这个 匿名函数 本身。拿到了函数本身之后,就可以在其后面加上一个小括号来调用它了。

把函数变成表达式?

既然小括号的作用是将函数的声明变成表达式,那么在函数周围加上运算符会不会有同样的效果呢?

+function(){...}()
!function(){...}()
~function(){...}()
void function(){...}()
delete function(){...}()

以上的几种写法都可以成功执行匿名函数,而且使用 +function(){...}() 这种方式执行函数自运行的效率是最高的。

递归函数

递归函数 是指一个函数直接或间接的调用自身,并在特定的情况下结束并放回运行结果

这里我们举一个 阶乘 的例子:

function F(N) {
return N * F(N - 1);
}

表面看上去,这个函数可以接收一个参数,并计算出这个数的阶乘。但是仔细想想就会发现不对劲,当 N = 1 时函数并没有停止自身的继续传递,也就是说这个函数没有停止条件,最终便会陷入一个死循环。结果就是 会在某一时刻,大量的函数将内存空间占满导致内存溢出。

也就是说我们上面写的这个函数,只有 没有

改造递归

我们尝试改变一下上面的 递归函数

首先要弄清楚,我们需要计算的是一个数 它的阶乘是多少。计算一个数字的阶乘便是让这个数每次乘以比他自身小 1 的数,直到乘到1。(说得不是很清楚,大家自行理解)

那么关键点就在于这个 直到

我们不能让它无止境的传递下去,在上面的例子中,参与递归的 N 为 1 时还在继续向内传递,0, -1, -2, -3... 我们所要做的就是当函数传递到 N = 1 时停止向内传递,直接返回 1 自身,将其自己交给外部的函数来调用,代码更改如下:

function F(N) {
if (N == 1) return 1;
return N * F(N - 1);
}

上面 if 语句的作用是:当 N 为 1 时,直接返回 1

这时运行一下就会发现,函数不报错了,而且也得到了我们想要的结果。

回调函数

回调函数,并不是指一种特殊的函数,而是指函数的使用方式

看一下下面的代码:

function f1(){
console.log(111);
}
function f2(){
console.log(222);
}
f1();
f2();

输出结果的顺序自然是先输出 111,再输出 222

但是如果我们给 f1() 添加一个定时器呢?

function f1(){
setTimeout(function(){
console.log(111);
}, 1000)
}
function f2(){
console.log(222);
}
f1();
f2();

这时便会先输出 222,一秒后输出 111。这种含有异步操作的函数就被称为 异步函数 ,异步函数最大的特点就是 后续的代码不需要排队,异步函数时可以和后续的代码并行的。f1() 就是一个典型的异步函数,你无法知道 f1()f2() 哪一个会先结束。

回调函数引出

那么在有异步函数的情况下,如果我希望先输出 111,再输出222,要怎么做呢?

目前看来,唯一的办法是 把函数 f2() 放在 f1() 的内部调用

function f1(){
setTimeout(function(){
console.log(111);
f2();
}, 1000)
}
function f2(){
console.log(222);
}
f1();

假设有这样一个场景,项目组里有小白、小黄、小绿三个人,有一个工具函数 getToken()

function getToken(){
//异步函数......
}

它是一个异步函数,大家都在使用这个函数完成自己的业务,并且每个人都希望在 getToken() 结束后执行自己的代码,于是它们将函数写成了下面这样:

但是这种写法显然是错误的,因为异步函数保证不了函数的执行顺序。那么现在只能想办法将自己所写的函数放在异步函数内部,才有机会在其后面执行。

首先,我们给 getToken() 函数增加一个参数 callback

function getToken(callback){
//异步函数......
}

之后,三个人的代码就可以改成这样:

把自己的函数传进去,最后在 getToken() 的最后调用这个 callback

function getToken(callback){
//异步函数......
callback();
}

现在,所有人的代码都会在异步函数最后执行,这极大的提高了代码的可复用性,降低了开发维护的成本。

这种函数调用的方式就叫回调

字面意思就是:把自己的函数交给别人,回头再调。

构造函数

  • 这一节需要理解 什么是面向对象

一个函数除了可以被当作函数,还可以被当作 class

function fn(){

}
let obj = new fn();
console.log( typeof obj );

我们可以直接使用 new 关键字来声明一个对象,这个时候,我们就说 fn() 是一个构造函数

那么 fn() 明明是一个空函数,这个对象是怎么来的呢?

构造函数的执行流程

问题的关键就在于这个 new 关键字。当你调用函数时在前面加上了 new 关键字,浏览器就会启动 构造函数 的执行流程:

function fn(){
this = {}
// 创建一个空对象,将其保存在this关键字中 ...... //your code return this;
}
let obj = new fn();

当然了,上面部分代码是不可见的。一个函数到底是普通函数还是构造函数,取决于你来怎么使用它。

但是通常,按照习惯,我们会将构造函数的首字母大写,普通函数的首字母小写。也就是说,如果你看到一个函数的首字母是大写的,在绝大多数的时候,它不应该被直接调用。

function User() {
......
} let user = User(); ×
let user = new User(); √

在最新版的 JavaScript 已经支持了 class 关键字,你可以像 Java 一样定义一个类,并通过构造方法来生成对象。

闭包函数

function a(){
let x = 1;
function b(){
console.log(x);
}
}

函数 b() 是一个定义在函数 a() 内部的函数,所以其可以访问到变量 x ,变量 x 相对于函数 b() 来说就是一个全局变量。

如果我们把函数 b() 作为函数 a() 的返回值:

function a(){
let x = 1;
return function b(){
console.log(x);
}
}
let c = a();
c();

我们已知,函数 c() 就是函数 b() ,有由于函数 c() 是全局变量,因此,相当于在全局范围调用了函数 b() ,打破了函数 b() 只能在局部使用的限制,最终我们打印出了变量 x

在这里,函数 a() 所形成的作用域,叫做 闭包,函数 b() 被称作 闭包函数

函数的柯里化

这一节来源于知乎:https://zhuanlan.zhihu.com/p/163838720#:~:text=函数柯里化,就是,后,才执行原函数

function add(a, b) {
return a + b
} function curry(fn) {
return function (a) {
return function (b) {
return fn(a, b)
}
}
}
let fn = curry(add)(1)(2)

关于 JS 函数的一切的更多相关文章

  1. 3.3 js函数

    1.函数语法: 函数声明的方式:function 函数名(参数1,参数2-){//函数体;}函数调用:函数名(参数1,参数2-); 函数内不一定都指定返回值. 如果需要指定返回值,可用 return ...

  2. Js函数function基础理解

    正文:我们知道,在js中,函数实际上是一个对象,每个函数都是Function类型的实例,并且都与其他引用类型一样具有属性和方法.因此,函数名实际上是指向函数对象的指针,不与某个函数绑定.在常见的两种定 ...

  3. js函数表达式和函数声明的区别

    我们已经知道,在任意代码片段外部添加包装函数,可以将内部的变量和函数定义"隐 藏"起来,外部作用域无法访问包装函数内部的任何内容. 例如: var a = 2; function ...

  4. 通用js函数集锦<来源于网络> 【二】

    通用js函数集锦<来源于网络> [二] 1.数组方法集2.cookie方法集3.url方法集4.正则表达式方法集5.字符串方法集6.加密方法集7.日期方法集8.浏览器检测方法集9.json ...

  5. 通用js函数集锦<来源于网络/自己> 【一】

    通用js函数集锦<来源于网络/自己>[一] 1.返回一个全地址2.cookie3.验证用户浏览器是否是微信浏览器4.验证用户浏览器是否是微博内置浏览器5.query string6.验证用 ...

  6. 100多个基础常用JS函数和语法集合大全

    网站特效离不开脚本,javascript是最常用的脚本语言,我们归纳一下常用的基础函数和语法: 1.输出语句:document.write(""); 2.JS中的注释为//3.传统 ...

  7. JS函数

    1.document.write(""); 输出语句2.JS中的注释为//3.传统的HTML文档顺序是:document->html->(head,body)4.一个浏 ...

  8. js函数和运算符

    函数是由事件驱动或者它被调用时执行可重复使用的代码块. <script> function myFunction(){ Alert(“hello World!”): } </scri ...

  9. JavaScript学习03 JS函数

    JavaScript学习03 JS函数 函数就是包裹在花括号中的代码块,前面使用了关键词function: function functionName() { 这里是要执行的代码 } 函数参数 函数的 ...

  10. JSF页面中使用js函数回调后台bean方法并获取返回值的方法

    由于primefaces在国内使用的并不是太多,因此,国内对jsf做系统.详细的介绍的资料很少,即使有一些资料,也仅仅是对国外资料的简单翻译或者是仅仅讲表面现象(皮毛而已),它们的语句甚至还是错误的, ...

随机推荐

  1. 游戏开发进行中UE5引擎打不开后续

    游戏每次启动都有个问题: 之前我实现了插件里的接口,但是已启动,关于接口这一块的就消失了,有些函数还在但是却是自定义事件,不是接口里的,Class Settings里面也提了 然后我把他改成了新的ch ...

  2. elementui中实现loding实现局部加载,以el-dialog为例

    效果 封装loading加载(也可以直接使用,封装为了方便多次调用) 组件定义:loadDiy.js import { Loading } from "element-ui"; e ...

  3. SEO初学指南之关键词研究(3) - 关键词分析实战

    经过之前的学习,这次我们开始实战.手把手教大家如何为网站筛选符合条件的关键词. 还不熟练的,建议再反复学习前两篇文章: SEO初学指南之关键词研究 (1) - 入门 SEO初学指南之关键词研究 (2) ...

  4. 3、SpringBoot2之配置文件

    3.1.环境搭建 3.1.1.在project创建新module 3.1.2.选择maven 3.1.3.设置module名称和路径 3.1.4.module初始状态 3.1.5.引入springbo ...

  5. 【Windows】(USB热点连接)使用手机给主机提供热点连网

    1.问题起源 昨天跟和几个哥们一起装机,发现安装好的系统, 直连网卡提示安装成功,但是网络设置显示未连接 找不到其他原因的办法下,我们看能不能使用手机对电脑进行连网 2.解决过程 我想到的是,先从手机 ...

  6. 【SQL】列转字符串函数

    还是这个需求 主界面的列表表格是直接在后台用SQL查出来的 public String getQuerySql(ElemBean condition, List<Object> param ...

  7. 再用国产操作系统deepin出现拖影现象

    问题如题,使用deepin系统后发现不论是网页的拖动.滑动都会出现明显拖影现象,最神奇的是使用爱奇艺的客户端播放器时同样出现拖影现象. 不过这个拖影现象截图还体现不出来这个拖影的效果,估计只有录屏才可 ...

  8. 在python中numpy.sum的性能真的好吗

    首先我们应该知道np.sum是用C语言写的矢量计算,应用场景为规模较大的numpy数组求和.本文要说的就是numpy.sum是不是对规模较小的numpy数组求和也同样会有不错的性能? 代码: impo ...

  9. 2021 CCPC 威海

    gym 知乎 确定了我先写缺省源,gjk 正开,zsy 倒开的策略 先读了 EFGH,发现是概率.博弈.计数,只能做 H,感觉我已经到点了.队友签了 AJ zsy 说 M 是多项式快速幂并准备开冲,看 ...

  10. ZABBIX Maps(拓扑图) 数据可视化

    本篇文章将介绍如何利用zabbix内置 Maps模块展示主机数据指标以及如何关联触发器 构建业务地图让异常指标更加直观呈现 下面我将从网络设备.服务器和vmware esxi和IP主机去为大家解析za ...