JavaScript的函数进阶
函数进阶
1立即执行函数表达式
立即执行的函数表达式的英文全称为Immediately Invoked Function Expression,简称就为IIFE。这是一个如它名字所示的那样,在定义后就会被立即调用的函数。
使用IIFE来进行初始 化,这样不会污染到全局环境。
通过IIFE,我们可以对我们的代码进行分块。并且块与块之间不会互相影响,哪怕有同名的变量 也没问题,因为IIFE也是函数,在函数内部声明的变量是一个局部变量
全局作用域是指声明的变量可在当前环境的任何地方使用。
函数作用域则只能在当前函数所创造的环境中使用。
块级作用域是指每个代码块也可以有 自己的作用域。
用var声明的变量是不存在块级作用域的,所以即使在if块中用var声明变量,它也能在外 部的函数或者全局作用域中使用
解决这个问题有两种方法,第一:使用ES6中的let关键字声明变量,这样它就有块级作用域。 第二:使用IIFE
2变量初始化
1执行上下文
在ECMAScript中代码的运行环境分为以下三种:
・全局级别的代码:这是默认的代码运行环境,一旦代码被载入,JS引擎最先进入的就是这个环境
・函数级别的代码:当执行一个函数时,运行函数体中的代码。
・EvaI级别的代码:在EvaI函数内运行的代码。
・不管什么情况下,只存在一个全局的上下文,该上下文能被任何其它的上下文所访问到。也 就是说,我们可以在test的上下文中访问到全局上下文中的o ne变量,当然在函数test2或者 test3中同样可以访问到该变量。
・至于函数上下文的个数是没有任何限制的,每到调用执行一个函数时,引擎就会自动新建出 —个函数上下文,换句话说,就是新建一个局部作用域,可以在该局部作用域中声明私有变 量等,在外部的上下文中是无法直接访问到该局部作用域内的元素的。
对于执行上下文这个抽象的概念,可以归纳为以下几点:
・单线程
· 同步执行
・唯一的一个全局上下文
・函数的执行上下文的个数没有限制
・每次某个函数被调用,就会有个新的执行上下文为其创建,即使是调用的自身函数,也是如此。
2函数上下文的建立与激活
每当我们调用一个函数时,一个新的执行上下文就会被创建出来。然而,在 js引擎的内部,这个上下文的创建过程具体分为两个阶段,分别是建立阶段和代码执行阶段。
建立阶段:发生在当调用一个函数,但是在执行函数体内的具体代码之前
•建立变量对象(arguments对象,形式参数,函数和局部变量)
•初始化作用域链
•确定上下文中this的指向对象
代码执行阶段:发生在具体开始执行函数体内的代码的时候
•执行函数体内的每一句代码
我们将建立阶段称之为函数上下文的建立,将代码执行阶段称之为函数上下文的激活。
变量对象
将整个上下 文看做是一个对象以后得到的一个词语。具体来讲,我们可以将整个函数上下文看做是一个对 象,那么既然是对象,对象就应该有相应的属性。对于我们的执行上下文来说,有如下的三个属 性:
变量对象,作用域链以及this
在函数的建立阶段,首先会建立arguments对象。然后确定形式参数,检查当然上下文中的函数 声明,每找到一个函数声明,就在variableObject下面用函数名建立一个属性,属性值就指向该 函数在内存中的地址的一个引用。如果上述函数名已经存在于variableObject(简称V0)下面,那 么对应的属性值会被新的引用给覆盖。最后,是确定当前上下文中的局部变量,如果遇到和函数 名同名的变量,则会忽略该变量。
在建立阶段,除了arguments,函数的声明,以及形式参数被赋予了具体的属性值 外,其它的变量属性默认的都是undefinedo并且普通形式声明的函数的提升是在变量的上面的。
3作用域链
所谓作用域链,就是内部上下文所有变量对象(包括父变量对象)的列表。此链主要是用于变量查 询。
公式作用域链(ScopeChain) = AO + [[scope]]
A0,简单来说就是VO, AO全称为active object(活动对象),对于当前的上下文来讲,一般 将其称之为A0,对于不是当前的上下文,一般被称为V0
[[scope]]:所有父级变量对象的层级列表(也被称之为层级链)
[[scope]],有一个一个非常重要的特性,那就是[[scope]]是在函数创建的时候,就已经被存 储了,是静态的。所谓静态,就是说永远不会变,函数可以永远不被调用,但是[[scope]]在创建 的时候就已经被写入了,并且存储在函数作用域链对象里面。
3闭包
1闭包基本介绍
在一个函数的外部,可以访问并使用它内部的变量
狭义的闭包
・形成闭包环境的函数能够被外部变量引用,这样就算它外部上下文销毁,它依然存在。
・在内部函数中要访问外部函数的局部变量。
优 点
・通过闭包可以让外部环境访问到函数内部的局部变量。
・通过闭包可以让局部变量持续保存下来,不随着它的上下文环境一起销毁。
2闭包的更多作用
1.封装变量
闭包可以帮助把一些不需要暴露在全局的变量封装成"私有变量"。
2.延续局部变量的寿命
3闭包和面向对象设计
过程与数据的结合是形容面向对象中的"对象"时经常使用的表达。对象以属性的形式包含了数 据,以方法的形式包含了过程。而闭包则是在过程中以环境的形式包含了数据。通常用面向对象 思想能实现的功能,用闭包也能够实现,反之亦然。
4递归函数
递归函数是一个一直直接或者间接调用它自己本身,直到满足某个条件才会退出的函数。
let numCalc = function(i){
if(i == 1)
{
return 1;
}
else{
return i * numCalc(i-1);
}
}
console.log(numCalc(4));//24
1•使用递归计算从m加到n
let numCalc = function (m, n) {
if (m === n) {
return m;
}
else {
return n + numCalc(m, m > n ? n + 1 : n - 1);
}
}
console.log(numCalc(100, 1));//5050
2•使用递归计算出某一位的斐波那契数
let numCalc = function (i) {
if (i == 1) {
return 0;
}
else if (i == 2) {
return 1;
else {
return numCalc(i - 1) + numCalc(i - 2); }
} console.log(numCalc(8));//13
3•使用递归打印出多维数组里面的每一个数字
let arr = [1, 2, [3, 4, [5, 6], 7, 8], 9, 10]; let test = function (arr) {
for (let i = 0; i < arr.length; i++) { if (typeof arr[i] == 'object') { test(arr[i]);
}
else { console.log(arr[i]);
}
}
};
test(arr);
5高阶函数
1高阶函数介绍
高阶函数(higher-order-function)指的是操作函数的函数,一般有以下两种情况:
・函数可以作为参数被传递
・函数可以作为返回值输出
2参数传递
1.回调函数
在Ajax异步请求的应用中,回调函数的使用非常频繁。想在Ajax请求返回之后做一些事情,但又 并不知道请求返回的确切时间时,最常见的方案就是把回调函数当作参数传入发起Ajax请求的方 法中,待请求完成之后执行回调函数。
一个函数不适合执行一些请求时,也可以把这些请求封 装成一个函数,并把它作为参数传递给另外一个函数,"委托"给另外一个函数来执行。
2.数组排序
sort()方法 封装了数组元素的排序方法。把可变的部分封装在函数参数里, 动态传入sor t()方法,使sor t()方法方法成为了一个非常灵活的方法。
for Each() , map() , eve ry() , some()等函数,也 是常见的回调函数。
3返回值输出
1.判断数据的类型
使用 Object,prototype.toString 来计算
Object.prototype.toString.call(obj)返回一个字符串
2. getSingle
4面向切面编程
AOP(面向切面编程)的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,这些跟业务 逻辑无关的功能通常包括日志统计、安全控制、异常处理等。把这些功能抽离出来之后,再通 过"动态织入"的方式掺入业务逻辑模块中。这样做的好处首先是可以保持业务逻辑模块的纯净和 高内聚性,其次是可以很方便地复用日志统计等功能模块
在JavaScript中实现AOP, 都是指把一个函数"动态织入"到另外一个函数之中。
6高阶函数的其他应用
函数节流(throttle)或函数去抖(debounce),核心其实就是限制某一 个方法的频繁触发
1函数防抖
函数防抖的原理是将即将被执行的函数用setTimeout延迟一段时间执行。对于正在执行的函数和 新触发的函数冲突问题有两种处理,也分别对应了定时器管理的两种机制。
第一种是只要当前函数没有执行完成,任何新触发的函数都会被忽略
第二种是只要有新触发的函数,就立即停止执行当前函数,转而执行新函数
下面是一 个比较完整的防抖函数(debounce),该函数接受2个参数,第一个参数为需要被延迟执行的函 数,第二个参数为延迟执行的时间
2函数节流
数节流使得连续的函数执行,变为固定时间段间断地执行。关于节流的实现,有两种主流的实 现方式,一种是使用时间戳,一种是设置定时器。
1.使用时间戳
触发事件时,取出当前的时间戳,然后减去之前的时间戳(最一开始值设为0),如果大于设置的 时间周期,就执行函数,然后更新时间戳为当前的时间戳,如果小于,就不执行。
2.使用定时器
触发事件时,设置一个定时器,再触发事件的时候,如果定时器存在,就不执行,直到定时器执 行,然后执行函数,清空定时器,这样就可以设置下个定时器。
JavaScript的函数进阶的更多相关文章
- 深入理解javascript函数进阶系列第一篇——高阶函数
前面的话 前面的函数系列中介绍了函数的基础用法.从本文开始,将介绍javascript函数进阶系列,本文将详细介绍高阶函数 定义 高阶函数(higher-order function)指操作函数的函数 ...
- 带你学习Javascript中的函数进阶(一)
1. 函数的定义和调用 1.1 函数的定义方式 函数声明方式function关键字(命名函数) 函数表达式(匿名函数) new Function() var fn = new Function('参数 ...
- 【转】Python之函数进阶
[转]Python之函数进阶 本节内容 上一篇中介绍了Python中函数的定义.函数的调用.函数的参数以及变量的作用域等内容,现在来说下函数的一些高级特性: 递归函数 嵌套函数与闭包 匿名函数 高阶函 ...
- JavaScript中函数函数的定义与变量的声明<基础知识一>
1.JavaScript中函数的三种构造方式 a.function createFun(){ } b.var createFun=function (){ } c.var createFun=new ...
- 理解 JavaScript 回调函数并使用
JavaScript中,函数是一等(first-class)对象:也就是说,函数是 Object 类型并且可以像其他一等对象(String,Array,Number等)一样使用.它们可以"保 ...
- 5种 JavaScript 调用函数的方法
一次又一次的,我发现,那些有bug的Javascript代码是由于没有真正理解Javascript函数是如何工作而导致的(顺便说一下,许多那样的代码是我写的).JavaScript拥有函数式编程的特性 ...
- 潭州学院-JavaVIP的Javascript的高级进阶-KeKe老师
潭州学院-JavaVIP的Javascript的高级进阶-KeKe老师 讲的不错,可以学习 下面是教程的目录截图: 下载地址:http://www.fu83.cn/thread-283-1-1.htm ...
- javascript escape()函数和unescape()函数
javascript escape()函数和unescape()函数 escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串. 语法: escape(string) stri ...
- JavaScript调用函数的方法
摘要:这篇文章详细的介绍了Javascript中各种函数调用的方法及其原理,对于理解JavaScript的函数有很大的帮助! 一次又一次的,我发现,那些有bug的Javascript代码是由于没有真正 ...
随机推荐
- python——pandas基础
参考: 实验楼:https://www.shiyanlou.com/courses/1091/learning/?id=6138 <利用python进行数据分析> pandas简介 Pan ...
- AWS的lambda和S3之间如何连携
今天正好遇到了这个问题,就在官方文档里查询,然后根据他的说明整理了一下大致的流程,详细的请参考AWS国际版的官方文档,这里只是作者的一个简单的流程展示. Lambda和S3连接 1.在S3的同一区域当 ...
- 线程池 一 ForkJoinPool
java.util.concurrent public class ForkJoinPool extends AbstractExecutorService public abstract class ...
- 【NOI2019模拟2019.6.27】B (生成函数+整数划分dp|多项式exp)
Description: \(1<=n,k<=1e5,mod~1e9+7\) 题解: 考虑最经典的排列dp,每次插入第\(i\)大的数,那么可以增加的逆序对个数是\(0-i-1\). 不难 ...
- 2018阿里云云数据库RDS核心能力演进
摘要: 2018年云数据库RDS发展上,不但针对MySQL.SQL Server.PostgreSQL提供了适合个人入门用户的基础版产品,以实惠的价格普惠广大中小用户.更加入最新的MariaDB TX ...
- thinkphp 数据库缓存
默认的数据库驱动位于Think\Db\Driver命名空间下面,驱动类必须继承Think\Db类,每个数据库驱动必须要实现的接口方法包括(具体参数可以参考现有的数据库驱动类库): 驱动方法 方法说明 ...
- luoguP1415 拆分数列 [dp]
题目描述 给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数.如果有多组解,则输出使得最后一个数最小的同时,字典序最大的解(即先要满足最后一个数最小:如果有多组解,则使得第一个数尽量大:如 ...
- delphi Sqlite
Delphi中SQLite如何读写二进制字段(Blob类型) 在Delphi中,有大量的组件可以操作SQLite数据库,如UniDAC就是其中一个比较优秀的,当然还有ASQLite3Component ...
- NX二次开发-创建直线(起点-向量方向-长度)UF_CURVE_create_line
NX9+VS2012 #include <uf.h> #include <uf_curve.h> #include <uf_csys.h> #include < ...
- mysql函数操作-增加自定义函数
#首先执行看mysql是否开启函数SHOW VARIABLES LIKE '%func%';------------------------------------------------------ ...