递归
- 什么是递归?
在程序中,递归就是函数自己直接或间接的调用自己。
-
递归的要素?
1 自己调用自己
2 要有结束条件
-
化归思想
将一个问题由难化易,由繁化简,由复杂化简单的过程称为化归,它是转化和归结的简称。
这里更多的是根据一些例子来体会和感受递归的思想,让我们开始吧!
栗子1: 求1~100之和
// 将求100转换为求99
// 将求99转换为求98
// ...
// 将求2转换为求1
// 求1结果就是1
// 即:sum(1)是1
function sum(n){
if(n == 1){
return 1;
}
return sum(n - 1) + n;
}
var num = sum(100);
console.log(num); // 5050
栗子2: 求阶乘
// 1! 1
// 2! 1! * 2
// 3! 2! * 3
// ...
// n! (n-1)! * n
function factorial(n){
if( n == 1){
return 1;
}
return factorial(n - 1) * n;
}
// 5! = 1 * 2 * 3 * 4 * 5
console.log(factorial(5)); // 120
栗子3: 求幂
// 1 的 m 次方 1 * 1^(m - 1) = 1^m = 1
// 2 的 m 次方 m 个 2 相乘 2 * 2^(m - 1) = 2^m
// ...
// n 的 m 次方 m 个 n 相乘 即 n * n^(m - 1) = n^m
// 每个数的 1 次方都等于它本身,如2^1 = 2; 3^1 = 3 等
function power(n, m){
if(m == 1){
return n;
}
return power(n, m-1) * n;
}
console.log(power(4,3)); // 48 //4*4*4=48
栗子4: 斐波那契数列
// 斐波那契数列: 1 1 2 3 5 8 13 21 34 ...
// 从第三项开始,后面一项的值为前面两项相加之和
// 第一项 1
// 第二项 1
// 第三项 1 + 1 = 2
// 第四项 1 + 2 = 3
// ...
// 第n项 (n - 2) + (n - 1) = n
function fibonacci(n){
if(n <= 2){
return 1;
}
return fibonacci(n - 2) + fibonacci(n - 1);
}
console.log(fibonacci(10)); //55
栗子5: 给页面中的所有元素添加边框
// DOM中没有直接获取后代元素的API
// 可以通过chaildNodes来获取所有的子节点
function getChildNodes(node){
// 先找子元素
var nodeList = node.childNodes;
// 再用子元素找子元素(递归)
// for循环中的条件,就充当了结束条件
for(var i = 0; i < nodeList.length; i++){
// childNode获取到的节点包含了各种类型的节点
// 只需要元素节点 通过nodeType判断当前节点是否为元素节点
// 节点.nodeType == 1 元素节点/2 属性节点/3 文本节点
var childNode = nodeList[i];
// 判断是否为元素节点
if(childNode.nodeType == 1){
childNode.style.border = '1px solid red';
getChildNodes(childNode);
}
}
}
getChildNode(document.body);
代码优化升级:
function getChildNode(node){
var nodeList = node.childNodes;
var res = [];
for(var i = 0; i < nodeList.length; i++){
var childNode = nodeList[i];
if(childNode.nodeType ==1){
res.push(childNode);
var temp = getChildNode(childNode0;
res = res.concat(temp);
}
}
return res;
}
// 1. 第一次调用时获取body的所有子元素,会把所有的子元素全部放到res里面
// 2. 每放进去一个就找这个子元素的所有子元素 有返回值
// 3. 把这个返回值和存当前子元素的数组拼接起来,就变成子元素和孙子元素的集合
var arr = getChildNode(document.body);
for(var i = 0; i < arr.length; i++){
var child = arr[i];
child.style.border = '1px solid red';
}
效果如下图:
闭包
概念
- 什么是闭包?
函数中的函数,里面的函数可以访问外面函数的变量,外面的变量是这个内部函数的一部分。
function outer(){
var num = 0; // 内部变量
return function add(){ // 通过返回add函数,即可在outer外访问
num++; // 内部函数引用,作为add函数的一部分了
console.log(num);
}
}
var func = outer();
func(); // 1
func(); // 2
- 闭包的原理?
作用域访问原则: 上级作用域无法直接访问下级作用域中的变量
- 闭包解决什么问题?
1)闭包内的数据不允许外界访问
2)要解决的问题就是间接访问该数据
function foo(){
var num = 123;
return num;
}
var x = foo(); // 使用return关键字将函数内部的数据返回,这个数据只能被使用一次
console.log(x); // 123
// 上述代码在函数外部访问到了内部变量
// 再定义一个y,x 是否和y相等
var y = foo();
console.log(y); // 123
console.log(x === y); // true
// 因为都是数值类型所以肯定两者是相等的,那如果是引用类型呢?
function foo(){
var obj = {
name: '张三';
}
return obj;
}
var o1 = foo();
var o2 = foo();
console.log(o1 == o2); // false
// 所以可知函数的每次调用,返回的对象都是新的,每次都不一样
- 闭包的基本模式
function outer(){
var num = 123;
return function inner(a){
// 若传参数,a肯定不是undefined,所以条件判断为true
if(a !== undefined){
num = a;
}else{ // 若不传参,代表获取值直接return
return num;
}
}
}
var func = outer();
func(456); // 456
1)在外部函数(outer)内创建函数(inner),在这个内部函数(inner)中,可以操作外部函数(outer)中的数据
2)将外部函数(outer)的返回值设置为内部函数(inner)
3)在外部调用外部函数(outer),就可以接收到返回值(内部函数)
4)使用这个内部函数(inner),就可以在外部对内部函数(inner)里的变量进行修改
使用闭包获取多个数据
function bar(){
var name = '张三';
var age = 18;
// 使用对象返回多个方法,获取并设置值
return {
getName: function(){
return name;
},
getAge: function(){
return age;
},
// 还可以添加方法,设置值的方法
setName: function(value){
name = value;
return name; // 可省略
},
setAge: function(value){
age = value;
return age; // 可省略
}
}
}
var obj = bar();
console.log(obj.getName()); // 张三
console.log(obj.getAge()); // 18
console.log(obj.setName('李四')); // 李四
console.log(obj.setAge('20')); // 20
闭包的作用
function bar(){
var name = '张三';
var age = 18;
return {
getName: function(){
return name;
},
setName: function(value){
name = value;
return name; // 可省略
}
}
}
var obj = bar();
obj.name('李四');
作用:
最基本的作用: 可以通过闭包返回函数或者方法,用来修改函数内部的数据。
创建一个私有的空间,保护数据;外部想要访问数据,只能通过函数提高的方法,在提供的方法中,可以设置一些校验逻辑,让数据变得更加安全。
闭包的练习
线程: 一个线程一次只能处理一件事情,多个线程就可以同时执行多个事情
Javascript是单线程的!!!
Javascript分了三个任务:
1)渲染任务
2)js的代码执行任务
3)事件处理任务
Javascript代码的执行任务:
1) 先把主任务(代码任务)执行完毕
2)再去执行次要的任务(包括setTimeout和setInterval中的回调函数中的代码)
setTimeout功能:至少在指定时间后执行指定回调函数,因为要等主任务中的代码执行完毕之后,才回去检查setTimeout的会带函数,有没有到执行时间。
如问题代码:
for(var i = 0 ; i < 10; i++){
setTimeout(function(){
console.log(j); // 输出10次10
},0);
}
解决问题代码:
for(var i = 0; i < 10; i++){
function bar(j){
return function(){
console.log(i); // 0 1 2 3 4 5 6 7 8 9
};
}
var f = bar(i);
setTimeout(f, 0);
}
栗子: 获取div,点击打印对应的div序号
var divs =document.getElemetsByTagNmae('div');
for(var i = 0; i < divs.length; i++){
var div = divs[i];
div.onclick = function(j){
return function(){
console.log('我是第' + (j + 1) + '个div');
}
}(i);
}
// 立即执行函数表达式
(funciton(){
console.log('xxx');
}());
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!