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代码是由于没有真正 ...
随机推荐
- @Conditional系列注解例子
1. @Conditional 说明:指定的Condition实现类,matches方法返回true则注入bean,false则不注入 @Configuration public class Bean ...
- 解决vi显示文件不能全屏的问题
https://blog.csdn.net/ly890700/article/details/52735092 docker外: vi ~/.vimrc
- CSIC_716_20191127【组合,封装、类的私有属性方法、property装饰器】
组合 what? 组合是指一个对象中,包含另一个或多个对象. why? 减少代码的冗余. How? 在类中加入其他类的对象,实现跨类对象之间的联动. 耦合度 软件设计要 高内聚 ...
- quartz的使用(二.基本过程)
1.关于各个要素的创建,SchedulerFactoryBean,CronTriggerFactoryBean及JobDetailFactoryBean全部实现spring中的FactoryBean& ...
- Spring,SpringMVC,SpringBoot,SpringCloud有什么区别和联系?
简单介绍 Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架.Spring使你能够编写更干净.更可管理.并且更易于测试的代码. Spring MVC是Spring的一个模块,一 ...
- C++ 数组作为参数的传递
//#include <iostream> //#include <conio.h> //using namespace std; // // //void are7(int( ...
- 7.12模拟T2(套路容斥+多项式求逆)
Description: \(n<=10,max(w)<=1e6\) 题解: 考虑暴力,相当于走多维格子图,不能走有些点. 套路就是设\(f[i]\)表示第一次走到i的方案数 \(f[i] ...
- JavaScript学习笔记之CSS-DOM
HTML负责结构层,网页的结构层由HTML或者XHTML之类的标记语言负责构建 CSS负责表示层,描述页面内容应该如何呈现. JavaScript负责行为层,负责内容应该如何响应事件这一问题. 能利用 ...
- NX二次开发-UFUN获取当前所在的模块UF_ask_application_module
NX9+VS2012 #include <uf.h> #include <NXOpen/UI.hxx> #include <NXOpen/MenuBar_MenuBarM ...
- ShellExecute打开文件打开文件夹的用法
1 #include <uf.h> 2 #include <uf_part.h> 3 #include <atlstr.h> 4 #include <iost ...