递归函数
、在代码中调用自身的函数
、函数里再调用函数
-
什么是递归?
就是在函数体内调用本函数。是一种调用模式,是一种逻辑程序基础的体现。递归会消耗大量内存,在实际开发中很少使用
注意:递归最重要的是终止条件。
function fact(num){
if (num<=1){
return 1;
}else{
return num*fact(num-1);
}
}
function recursion(x){
if(x>0){
document.write(x+'<hr/>');
recursion(x-1);
}
}
recursion(10);
回调函数
、异步编程的直接体现就是回调
、异步编程依托回调实现
、回调函数在完成任务后会被调用
、例如,一边读取文件,一边执行其他命令,文件读取完之后,可以将文件内容作为回调函数的参数返回,这样在执行代码的时候就没有阻塞或等待文件操作,提高了node.js性能,可以处理大量的并发请求
、回调函数一般作为函数的最后一个参数出现
、语法:
function foo1(name, age, callback) { }
function foo2(value, callback1, callback2) { }
箭头函数
、箭头函数表达式语法比普通函数表达式语法简介,并且没有自己的this,arguments
、基础语法:
(参数1, 参数2, …, 参数N) => { 函数声明 }
//相当于:(参数1, 参数2, …, 参数N) =>{ return 表达式; }
(参数1, 参数2, …, 参数N) => 表达式(单一)
// 当只有一个参数时,圆括号是可选的:
(单一参数) => {函数声明}
单一参数 => {函数声明}
// 没有参数的函数应该写成一对圆括号。
() => {函数声明}
、高级语法
//加括号的函数体返回对象字面表达式:
参数=> ({foo: bar})
//支持剩余参数和默认参数
(参数1, 参数2, ...rest) => {函数声明}
(参数1 = 默认值1,参数2, …, 参数N = 默认值N) => {函数声明}
//同样支持参数列表解构
let f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); // 6
、引入箭头函数有两个方面的作用:更简短的函数并且不绑定this
、不用绑定this
在箭头函数出现之前,每个新定义的函数都有它自己的 this值(在构造函数的情况下是一个新对象,在严格模式的函数调用中为 undefined,如果该函数被作为“对象方法”调用则为基础对象等)。This被证明是令人厌烦的面向对象风格的编程
function Person() {
// Person() 构造函数定义 `this`作为它自己的实例.
this.age = 0;
setInterval(function growUp() {
// 在非严格模式, growUp()函数定义 `this`作为全局对象,
// 与在 Person()构造函数中定义的 `this`并不相同.
this.age++;
}, 1000);
}
var p = new Person();
在ECMAScript 3/5中,通过将this值分配给封闭的变量,可以解决this问题
function Person() {
var that = this;
that.age = 0;
setInterval(function growUp() {
// 回调引用的是`that`变量, 其值是预期的对象.
that.age++;
}, 1000);
}
箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。因此,在下面的代码中,传递给setInterval的函数内的this与封闭函数中的this值相同
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| 正确地指向 p 实例
}, 1000);
}
var p = new Person();
、因为箭头函数没有自己的this指针,
通过 call() 或 apply() 方法调用一个函数时,只能传递参数(不能绑定this),他们的第一个参数会被忽略
、箭头函数不能用作构造器,和 new一起用会抛出错误
、箭头函数没有prototype属性
、函数体语法:
var func = x => x * x;
// 简写函数 省略return
var func = (x, y) => { return x + y; };
//常规编写 明确的返回值
、圆括号把对象字面量包起来
var func = () => ({foo: 1});
、箭头函数也可以使用条件(三元)运算符
var simple = a => a > 15 ? 15 : a;
simple(16); // 15
simple(10); // 10
let max = (a, b) => a > b ? a : b;
箭头函数也可以使用闭包
// 标准的闭包函数
function A(){
var i=0;
return function b(){
return (++i);
};
};
var v=A();
v(); //1
v(); //2
//箭头函数体的闭包( i=0 是默认参数)
var Add = (i=0) => {return (() => (++i) )};
var v = Add();
v(); //1
v(); //2
//因为仅有一个返回,return 及括号()也可以省略
var Add = (i=0)=> ()=> (++i);
箭头函数递归
var fact = (x) => ( x==0 ? 1 : x*fact(x-1) );
fact(5); // 120
闭包函数
https://blog.csdn.net/qq_21132509/article/details/80694517
https://www.cnblogs.com/baqiphp/p/6238556.html
https://www.jianshu.com/p/2fb8a9f26589
、闭包是指可以访问另一个函数作用域变量的函数,一般是定义在外层函数中的内层函数
、为什么需要闭包?
局部变量无法共享和长久的保存,而全局变量可能造成变量污染,所以我们希望有一种机制既可以长久的保存变量又不会造成全局污染
、特点:
占用更多内存,不容易被释放
、什么时候使用?变量既想反复使用,又想避免全局污染
、如何使用?
定义外层函数,封装被保护的局部变量。
定义内层函数,执行对外部函数变量的操作。
外层函数返回内层函数的对象,并且外层函数被调用,结果保存在一个全局的变量中
、js中作用域链的概念,子作用域可以根据作用域链访问父作用域中的变量,
相反,父作用域想访问子作用域中的变量,就需要通过闭包实现
、闭包就是跨作用域访问变量 —— 内部作用域可以保持对外部作用域中变量的引用从而使得(更)外部作用域可以访问内部作用域中的变量
function user () {
var name = 'wangxi'
return function getName () {
return name
}
}
var userName = user()()
console.log(userName) // wangxi
分析代码我们知道,name 是存在于 user 函数作用域内的局部变量,正常情况下,在外部作用域(这里是全局)中是无法访问到 name 变量的,但是通过闭包(返回一个包含变量的函数,这里是 getName 函数),可以实现跨作用域访问变量了(外部访问内部)
匿名函数
、没有函数名,直接赋值给一个变量,通过变量调用
var obj1 = function(){
alert(‘通过变量调用’)
}
obj1();
、直接调用
(function(){
alert(‘直接调用’)
})()
## 构造函数与普通函数
、构造函数首字母大写
、调用方式不同,
普通函数调用:函数名();
构造函数调用:new 大写首字母的函数名();
、构造函数内部用this来构造属性和方法
、执行流程:
在堆内存中创建一个新对象
将新对象设置为函数中的this===也就是构造函数中的this指向new出来的对象(实例)
执行函数中的代码
将新对象作为返回值