函数进阶
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递归函数this
递归函数是一个一直直接或者间接调用它本身自己,直到知足某个条件才会退出的函数。spa
let numCalc = function(i){
if(i == 1)
{
return 1;
}
else{
return i * numCalc(i-1);
}
}
console.log(numCalc(4));//24prototype
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.使用定时器 触发事件时,设置一个定时器,再触发事件的时候,若是定时器存在,就不执行,直到定时器执 行,而后执行函数,清空定时器,这样就能够设置下个定时器。