闭包
-
闭包就是函数(简单理解为定义在一个函数内部的函数); 内层函数可以访问外层函数里面的变量
-
正常情况下, 函数调用结束后,函数内部的局部变量就会被销毁,但闭包不会销毁
-
闭包的作用,1. 可以在函数外面读取函数内部成员, 2. 让函数内成员始终存活在内存中
<button>点击</button> <script> var button = document.querySelector('button'); function fn() { var num = 10; return function () { num++; console.log(num); } } // fn() 调用结束后 内部的局部变量num应该被销毁 // 但是这里产生了闭包, 让变量num一直保存在内存中,所以打印了10 // 正常的情况下,函数一调用结束,里面的变量都会销毁,但闭包可以讲变量保存在内存里面 // 学会调试功能, 看到clouser闭包的产生 var f = fn(); f(); button.addEventListener('click', function(){ f(); })
// 闭包应用-点击li输出当前li的索引号 // 1. 我们可以利用动态添加属性的方式 // 我们之前是利用自定义属性的发送 setAttribute('data-index', i) var lis = document.querySelector('.nav').querySelectorAll('li'); for (var i = 0; i < lis.length; i++) { lis[i].index = i; lis[i].onclick = function() { // console.log(i); console.log(this.index); } } // 2.1 利用闭包的方式得到当前小li 的索引号 for (var i = 0; i < lis.length; i++) { // 利用for循环创建了4个立即执行函数 // 立即执行函数也产生了闭包,因为立即执行函数里面的任何一个函数都可以使用它的i这变量 (function(i) { // console.log(i); lis[i].onclick = function() { console.log(i); } })(i); }
//闭包在定时器中的应用 for (var i = 0; i < 3; i++) { setTimeout(function () { console.log(i) }, 0) } for (var i = 0; i < 3; i++) { (function (index) { setTimeout(function () { console.log(index) }, 0) })(i) }
递归
-
函数内部自己调用自己, 这个函数就是递归函数
-
递归函数的作用和循环效果类似, 由于递归容易发生"栈溢出(stack overflow)"的错误, 所以一定注意加上退出条件
// 利用递归函数求1~n的阶乘 1 * 2 * 3 * 4 * ..n function fn(n) { if (n == 1) { return 1; } return n * fn(n - 1); } console.log(fn(3));
//利用递归求斐波那契数列 1、1、2、3、5、8、13、21... function fb(n) { if (n === 1 || n === 2) { return 1; } return fb(n - 1) + fb(n - 2); } console.log(fb(3));
递归遍历数据,常用!!! 在一些框架的组件化开发中, 树形控件必须使用这种递归的写法
扩展—自己封装判断数据类型函数
var oP = Object.prototype,
toString = oP.toString;
function typeOf(value) {
if (null === value) {
return 'null';
}
var type = typeof value;
if ('undefined' === type || 'string' === type) {
return type;
}
var typeString = Object.prototype.toString.call(value);
switch (typeString) {
case '[object Array]':
return 'array';
case '[object Date]':
return 'date';
case '[object Boolean]':
return 'boolean';
case '[object Number]':
return 'number';
case '[object Function]':
return 'function';
case '[object RegExp]':
return 'regexp';
case '[object Object]':
if (undefined !== value.nodeType) {
if (3 == value.nodeType) {
return (/\S/).test(value.nodeValue) ? 'textnode': 'whitespace';
} else {
return 'element';
}
} else {
return 'object';
}
default:
return 'unknow';
}
}