闭包
指的是一个函数能够使用另一个函数里的变量。
函数嵌套函数,内部函数就是闭包
- 语法
一般是在一个函数里定义一个子函数,并返回子函数。
function father(){
var num=0;
function sun(){
num++;
}
return sun;//闭包函数
}
//外部的访问不到num, 原理:执行上下文栈
正常情况下:函数执行完,内部变量会销毁(释放内存空间)
闭包:内部函数没有执行完,外部函数变量不会被销毁
应用:
- 封装一段代码
- 实现私有变量,节约全局变量
- 实现块级作用域,后期有
let
和const
来代替。
IIFE(立即执行函数)
概念
IIFE(immediately invoked Function Expression)
- 立即调用函数表达式
函数声明
//函数声明式 function text(){ console.log('Function Declaration') } text() //()函数名后面的括号,叫做执行符号
函数表达式
//将一个(匿名)函数(函数声明式) 赋值给一个变量的形式 函数表达式 var text = function(){ console.log('Function Expression'); }
IIFE语法
(function(){
console.log('Function Expression');
})();//这里的分号若有多个立即执行函数,必须添加,否则报错
作用
- 可以创建一个与外界没有任何关联的作用域,独立的作用域
- 执行完成之后,自动销毁
- ES3,ES5没有模块的概念,立即执行函数来模拟模块化(封闭作用域,抛出接口(向外部抛出一系列属性和方法)) window上保存属性和方法
函数的柯里化
概念
- 是把接受多个参数的函数变成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
- 即一个函数只 处理一个参数,剩余的参数就通过返回的函数进行处理
function _add(a) {
return function(b) {
return function(c) {
return a + b + c;
}
}
}
封装正则表达式检验用户输入手机邮箱
var _check = function(check){ return function(text){ return check.test(text); } }; var checkPhone = _check(/^1[34578]\d{9}$/); var checkEmail = _check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/); var s=checkPhone('18388888899'); var t=checkEmail('xxxxx@test.com'); console.log(s,t);
面试题
// 实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;
function add() {
// 第一次执行时,定义一个数组专门用来存储所有的参数
var _args = [].slice.call(arguments);
// 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
var adder = function () {
var _adder = function() {
// [].push.apply(_args, [].slice.call(arguments));
_args.push(...arguments);
return _adder;
};
// 利用隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
_adder.toString = function () {
return _args.reduce(function (a, b) {
return a + b;
});
}
return _adder;
}
// return adder.apply(null, _args);
return adder(..._args);
}
补充
函数的隐式转换。当我们直接将函数参与其他的计算时,函数会默认调用toString方法,直接将函数体转换为字符串参与计算。
递归
- 递归是程序的编程技巧。指函数调用自己。
function 函数名(形式参数){
//需要通过判断来限制出现无限递归
if(条件){
return ; //表示递归结束。
}
//通过调用自己来达到类似于循环的效果
函数名(实际参数);
}
一般流程
确定递归的函数是用来干什么的,功能点在哪?
确定该功能能够被分解成更小的功能
找到结束递归的分界点
作用
- 简化循环代码
- 采用分治算法,让逻辑复杂的情况简单处理(将大问题分解成一个个小的问题)
常见例子
阶乘
//递归案例 function f(n){ if(n==1){ return 1; } return n * f(n-1); }
累计(加减乘除)
斐波那契数列
//斐波那契数列 的第n项 // 0 1 1 2 3 5 8 13 21 34 ... //f(n) = f(n-1) +f(n-2) function f(n){ if(n==1){ return 0; } if(n==2){ return 1; } return f(n-1) + f(n-2); } // f(5): f(1)+f(2)+f(2)+f(1)+f(2) =0+1+1+0+1 = 3
快速排序
核心思想在于将排序过程分为多次,每次会吧一个数(基准数)放在合适的位置,并且该数左边的都小于,右边的都大于该数。
快速排序利用递归来分别对左边和右边也进行排序过程
function quickSort(arr,left,right){ if(left>=right) return; var i =left,j = right; var key = arr[left]; while(i!=j){ while(i<j && arr[j]>=key){ j--; } while(i<j && arr[i]<=key){ i++; } if(i<j){ 3 var temp = arr[i]; arr[i] = arr[j]; arr[j]=temp; } } arr[left]=arr[i]; arr[i]=key; //一次结束 quickSort(arr,left,i-1); quickSort(arr,i+1,right); }