php 闭包函数递归,闭包和递归

js变量的作用域:

全局作用域(全局变量) : 在函数外面声明的变量

**生命周期(变量从声明到销毁): 页面从打开到关闭.

局部作用域(局部变量) : 在函数里面声明的变量

**生命周: 开始调用函数到函数执行完毕

1.闭包使用介绍

1.闭包介绍(closure)

1.1 闭包 : 是一个可以在函数外部访问函数内部变量的函数->闭包是函数

1.2 闭包作用: 可以在函数外部访问函数内部变量->延长局部变量的生命周期

1.3 闭包语法 :

--->a. 在外部函数outer的内部声明了一个闭包函数closure

--->b. 在闭包函数内部 返回想要访问的局部变量

--->c. 在外部函数中返回闭包函数

1.4 闭包本质:是一个沟通函数内部(局部作用域)与函数外部(全局作用域)的桥梁

//1.需求:在函数外部访问函数内部的变量

// function fn(){

// var zhangsan = {

// name:'张三',

// age:34

// };

// };

// fn();

// 函数里面的局部变量在函数之后完毕之后自动被系统回收

// console.log(zhangsan);

// 2. return返回值

// 弊端 :浪费内存资源。 每调用一次函数,就生成了一个新的对象

// function fn(){

// var zhangsan = {

// name:'张三',

// age:34

// };

// return zhangsan;

// };

// var a = fn();

// console.log(a);

// var b = fn();

// console.log(b);

// //a和b是同一个对象吗?

// //每调用一次函数,就生成了一个新的对象。两个对象虽然数据是一样,但是在堆中两个不同的地址

// console.log(a == b);

//3.使用闭包实现在函数内部访问函数外部的变量

//声明外部函数

function fn(){

var zhangsan = {

name:'张三',

age:34

};

//闭包函数

function closure(){

// console.log(canglaoshi);

return zhangsan;

};

return closure;

};

//调用fn, (1)声明了一个对象张三(0xaaaa) (2)声明了一个闭包函数closure(0xbbbb) (3)返回闭包函数

var bibao = fn();

//调用闭包函数:得到fn中的局部变量

var a = bibao();

console.log(a);

var b = bibao();

console.log(b);

console.log(a == b);//true

2.闭包函数的使用步骤和注意点

1.复习闭包的语法步骤(3个步骤)

--->a.在外部函数outer中声明一个函数closure

--->b.在闭包函数中返回想要访问的变量

--->c.返回闭包函数

2.了解闭包语法的注意点

--->a. 如果希望访问同一个变量,外部函数只能调用一次

--->b. 如果希望访问不同的变量,外部函数可以调用多次

每调用一次生成一个新的局部变量和新的闭包函数

function outer(){

var num = Math.floor(Math.random()*100);

console.log(num);

//1.声明闭包函数

function closure(){

console.log(num);

//2.在闭包函数中返回想要访问的变量

return num;

};

//3.返回闭包函数

return closure;

};

//第一个注意点: 如果希望闭包访问的是同一个变量,外部函数只能调用一次

//1.调用outer : 声明局部变量,声明闭包函数

//获取闭包函数

var bibao = outer();

//2.调用闭包函数

bibao();

bibao();

bibao();

//第二个注意点: 如果希望闭包访问的是不同的变量,外部函数需要调用多次

// var bibao1 = outer();

// bibao1();

outer()();

// var bibao2 = outer();

// bibao2();

outer()();

// var bibao3 = outer();

// bibao3();

outer()();

//2。示例 投票机

function vouter(){

var num = 10;

function closure(){

num++;

console.log(num);

return num;

};

return closure;

};

//2.1 一台投票机,投3票

var bb = vouter();

bb();//11

bb();//12

bb();//13

//2.2 三台投票机,各投1票

var bb1 = vouter();

bb1();//11

// var bb2 = vouter();

// bb2();//11

vouter()();

// var bb3 = vouter();

// bb3();//11

vouter()();

3.由一个练习题看闭包的本质

//1.

var name = 'My Window';

var obj = {

name:'My Object',

getFunction:function(){

return function(){

console.log(this.name);

};

}

};

//(1) var fn = obj.getFunction() (2)fn() // window.fn()

// (1)当调用obj.getFunction()的时候返回一个匿名函数 (返回到全局作用域)

//(2)调用匿名函数,由于全局的所以函数指向window

obj.getFunction()();//'My Window';

//2.

var name = 'My Window';

var obj = {

name:'My Object',

getFunction:function(){

var that = this;

return function(){

console.log(that.name);

};

}

};

//(1)调用obj.getFunction() : 这个函数中this是obj ,声明了一个局部变量that存储this

//(2)调用闭包函数,由于闭包函数延长了that的生命周期,所以会打印obj.name属性值

console.log(obj.getFunction()()); //My Object

4.闭包的经典使用场景

/*

1.沙箱模式:是js的一种设计模式。 一个独立的作用域完成独立的功能,通常是一个匿名函数自调用

2.沙箱模式好处

a. 封闭的空间,避免全局变量污染

b. 模块化开发(一个功能模块对应一个作用域)

*/

(function(w){

var person = {

name:'张三',

age:18

};

person.eat = function(){

console.log('今天吃米粉');

};

person.play = function(){

console.log('大吉大利,今晚吃鸡');

};

/*

1.外部如何访问沙箱中的变量?

2.使用参数

为什么不直接使用window?

a.沙箱里面不能直接访问外部变量,破坏封装性

b.以后实际开发代码会压缩,可能会把window压缩成w。直接使用无法获取的

*/

w.person = person;

})(window);

console.log(person);

person.eat();

递归

1.递归函数: 函数自己调用自己

2.递归函数的特点

a.能用递归实现的功能就一定可以使用循环调用函数来实现,只是语法简洁性与性能不同而已

b.一定要有结束条件,否则会导致死循环

注意:递归不可以乱用,因为在有些时候性能不好

1.递归的简使用

//递归

var i = 1;

function fn(){

console.log('吾日三省吾身');

i++;

if(i<=3){

fn();

};

};

fn();

// 循环

for(var i = 1;i<=3;i++){

fn();

}

function fn(){

console.log('吾日三省吾身');

};

2.递归的使用场景

//1.求1-n的累加和

//递归实现

function getSum(n) {

if (n == 1) {

return 1;

} else {

return getSum(n - 1) + n;

};

//递归分析

// if(n == 1){

// return 1;

// }else if(n == 2){

// return getSum(n-1) + n;

// }else if(n == 3){

// return getSum(2) + 3;

// }else if(n == 4){

// return getSum(3) + 4;

// }else if(n == 5){

// return getSum(4) + 5;

// }

// ***

// else if(n == n){

// return getSum(n-1) + n

// }

};

console.log(getSum(5));//1+ 2 + 3 + 4 + 5 = 15

//循环实现

// function getSum(n){

// //求和:箩筐思想三步法

// var sum = 0;

// for(var i = 1; i<=n;i++){

// sum+=i;

// };

// return sum;

// };

// console.log(getSum(100));

//2.求阶乘(*)

/*阶乘:

5! = 5 * 4 * 3 * 2 * 1

6! = 6 * 5 * 4 * 3 * 2 * 1

*/

//递归实现

function jieChen(n) {

return n == 1 ? 1 : jieChen(n - 1) * n;

// if(n == 1){

// return 1;

// }else{

// return jieChen(n-1) * n;

// };

//递归分析

// if(n == 1){

// return 1;

// }else if(n == 2){

// return jieChen(1) * 2;

// }else if(n == 3){

// return jieChen(2) * 3

// }else if(n == n){

// return jieChen(n-1) * n;

// }

};

console.log(jieChen(5));// 5 * 4 * 3 * 2 * 1 = 120

//阶乘奇葩面试题 arguments.callee 得到的是函数本身

var num = (function (n) { return n == 1 ? 1 : arguments.callee(n - 1) * n })(6);

console.log(num);

// //循环实现

// function jieChen(n){

// var sum = 1;

// for(var i = 1 ;i<=n;i++){

// sum *= i;

// };

// return sum;

// };

// console.log(jieChen(6));// 5 * 4 * 3 * 2 * 1 = 120

//3.斐波那契数列

//了解: 递归函数虽然语法简洁,但是性能不是一定高于循环

//检测递归的性能,递归不可以乱用,因为性能不好

console.time();

//递归实现

function fib(n){

if(n == 1 || n == 2){

return 1;

}else{

return fib(n-2) + fib(n-1);

};

// if(n == 1 || n == 2){

// return 1;

// }else if(n == 3){

// return fib(3-2) + fib(3-1);

// }else if(n == 4){

// return fib(4-1) + fib(4-2)

// }

};

console.log(fib(10));

console.timeEnd();

/* 需求:求斐波那契额数列第十列

1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368........

1.前面两个数字固定 1 , 1

2.第三个数字开始,每一个数字都是前面两个数字的和

*/

function fib(n) {

var arr = [1, 1];

for (var i = 2; i < n; i++) {

arr[i] = arr[i - 2] + arr[i - 1];

};

return arr[arr.length-1];

};

console.log(fib(100));

// arr[2] = arr[2-2] + arr[2-1];

// arr[3] = arr[3-2] + arr[3-1];

// arr[4] = arr[4-2] + arr[4-1];

3.使用递归遍历dom数

/* 递归应用场景:遍历DOM树

1.需求:获取father父元素的所有后代元素

2.DOM的api中有没有直接的方法可以获取呢? 没有

3.递归思路

a。遍历父元素father

b. 遍历每一个子元素,找到子元素的子元素。然后又继续遍历子元素的子元素的子元素,以此类推

形成递归调用

*/

var father = document.getElementById('father');

var list = [];//存储所有的后代元素

function houDai(ele){

for(var i = 0;i

list.push(ele.children[i]);

//递归求子元素的子元素

houDai(ele.children[i]);

};

};

//求父元素的所有后代元素

// houDai(father);

// console.log(list);

//求整颗dom树

houDai(document);

console.log(list);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值