一、函数的概念函数是一段可以反复调用的代码块。接受输入的参数,不同的参数会返回不同的值。1.函数的定义ECMAScript中是使用function关键字来声明,后面跟一组参数以及函数体。1) 声明函数 function sum (num1,num2){ return num1 + num2; } //函数声明提升(是预编译吗?)-可以把函数声明放在调用她的语句后面(可以先使用后定义)2) 函数表达式:将一个匿名函数赋值给一个变量 var sum = function (num1,num2){ console.log(num1+num2); } //必须定义后使用(否则会报错)3) 构造函数(几乎不用)var sum = new Funtion( ’num1’, ’num2’, ‘return num1 + num2’) //等同于上面的声明函数2.函数的调用(括号运算符)函数可以通过其函数名调用,后面还要加上一对圆括号和参数(如果有多个参数,用逗号隔开)function sum(num1, num2) { return num1 + num2;}sum(1, 1) //2 3.函数的参数函数运行的时候,有时需要提供外部数据,不同的外部数据会得到不同的结果,这种外部数据就叫参数。 2.参数的概念,参数的省略,参数的传递方式,同名参数 1.arguments对象 由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。这就是arguments对象的由来。命名参数:4. 函数的返回值(return)函数可以通过return语句跟要返回的值来实现返回值。函数在执行完return语句之后停止并立即退出。因此,在return语句之后的任何代码永远都会回执行。function sum(num1, num2) { return num1 + num2; alert(‘Hello world’) //永远不会执行}return语句不是必须的,如果没有的话,该函数就不会返回任何值,或者说返undefined;function sum(num1, num2) { alert (num1 + num2) } //undefined5.函数没有重载(函数的重复声明)函数重载:在其他语言(Java)中可以为一个函数体编写两个定义,只要定义的签名(接收的参数的类型和参数不同即可)) 在ECMASctipt中如果同一个函数被多次声明,后面的声明就会覆盖前面的声明。function f(){ console.log(1);}f() //1function f(){ console.log(2);}f() //26.函数的属性和方法(1) name属性(返回name的名字) function sum (){} sum.name // ‘sum’ (2) length 属性函数的length属性返回函数预期传入的参数个数,即函数定义之中的参数个数。function f(a,b){ return f.length }f(1,2,3,4) //2 ==> length属性就是定义是的参数个数。不管调用时传入了多少参数,length属性的始终等于2 (3)apply()和call() 每个函数都包含两个非继承而来的方法:apply()和和call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。 apply()方法接收两个参数,一个是在其运行函数体内的作用域,另一个是参数数组。其中第二个参数可以是Array的实例,也可以是arguments对象。call()方法和apply()的作用相同,它们的区别在仅在于接收参数的方式不同。对于call() 方法而言,第一个参数是this值没有变化,变化的是其余参数都是直接传递给函数。换句话说,在使用call()时,传递给函数的参数必须逐个列举出来,如下面的例子所示: function sum(num,num2){ return num1 + num2; } function callSum(){ return sum.call(this.num1,num2); } 作用: 1.传递参数 2.扩充函数赖以运行的作用域(call、apply、bind)二、函数的作用域和作用域链1.作用域2.作用域链3.延长作用域链三、函数的其他知识点1.闭包函数2.回调函数3.递归函数4.自执行函数一、函数的声明 函数是一段可以反复调用的代码块。函数还能接受输入的参数,不同的参数会返回不同的值。 ECMAScript中是使用function关键字来声明,后面跟一组参数以及函数体。 1.声明函数 function sum (num1,num2){ return num1 + num2; } *函数声明提升(是预编译吗?)-可以把函数声明放在调用她的语句后面(可以先使用后定义) 2.函数表达式(匿名函数或者拉姆达函数):将一个匿名函数赋值给一个变量 var sum = function(num1,num2){ return num1 + num2; } *必须定义后使用(否则会报错) 3.构造函数(几乎不用) var sum = new Funtion( ’num1’, ’num2’, ‘return num1 + num2’ ) //等同于上面的声明函数4.箭头函数(es6) var sum = (num1,num2) => {num1+mum2} 5.调用函数(括号运算符) 函数可以通过其函数名调用,后面还要加上一对圆括号和参数(如果有多个参数,用逗号隔开) function sum(num1, num2) { return num1 + num2; } sum(1, 1) //26.函数的返回值 return 语句 ECMAscript中的函数在定义是不必指定是否返回值。实际上,任何函数在任何时候都可以通过return语句跟要返回的值来实现返回值。 function sum(num1, num2) { return num1 + num2; alert(‘Hello world’) //永远不会执行 } 函数体内的return语句,表示返回。JavaScript引擎遇到return语句,就直接返回return后面的那个表达式的值,后面及时还有语句,也不会得到执行。也就是说,return语句所带的那个表达式,就是函数的返回值。return语句不是必须的,如果没有的话,该函数就不会返回任何值,或者说返undefined; 函数体中的return语句,表示返回该函数会返回一个值,并且会在执行完return语句之后停止并立即退出,因此,在return语句之后的任何代码永远都会回执行。 5.函数没有重载(函数的重复声明) 函数重载:在其他语言(Java)中可以为一个函数体编写两个定义,只要定义的签名(接收的参数的类型和参数不同即可)) 在ECMASctipt中如果同一个函数被多次声明,后面的声明就会覆盖前面的声明。 function f(){ console.log(1); } f() //1 function f(){ console.log(2); } f() //24.函数的内部属性(arguments、this,eval) arguments.callee5.函数的属性和方法(1)name属性(返回name的名字) function sum (){} sum.name // ‘sum’ (2)length 属性 函数的length属性返回函数预期传入的参数个数,即函数定义之中的参数个数。 function f(a,b){ return f.length } f(1,2,3,4) //2 ==> length属性就是定义是的参数个数。不管调用时传入了多少参数,length属性的始终等于2 (3)toString() (返回一个字符串,内容是函数的源码) (4)apply()和call() 每个函数都包含两个非继承而来的方法:apply()和和call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。 apply()方法接收两个参数,一个是在其运行函数体内的作用域,另一个是参数数组。其中第二个参数可以是Array的实例,也可以是arguments对象。 call()方法和apply()的作用相同,它们的区别在仅在于接收参数的方式不同。对于call() 方法而言,第一个参数是this值没有变化,变化的是其余参数都是直接传递给函数。换句话说,在使用call()时,传递给函数的参数必须逐个列举出来,如下面的例子所示 function sum(num,num2){ return num1 + num2; } function callSum(){ return sum.call(this.num1,num2); } 作用: 1.传递参数 2.扩充函数赖以运行的作用域(call、apply、bind) 二、函数的参数和理解参数1.arguments对象 由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。这就是arguments对象的由来。2.参数的概念,参数的省略,参数的传递方式,同名参数二、作用域1.什么是作用域 作用域(scope)指的是变量存在的范围。 在es5中的,Javascript只有两种作用域:一种是全局作用域,变量在整个程序中一直存在, 所有地方都可以读取;另一种是函数作用域,变量只在函数内部存在。(es6中又新增了块级作用域) 三、作用域链标示符:指变量、函数、属性的名字,或者函数的参数。作用域链的用途:是为了保证对执行环境有权访问的所有变量和函数的有序的访问。标示符的解析是沿着作用域链一级一级的搜索标示符的过程。所搜过程始终是从作用域链的前端开始,然后逐级的内部环境可以通过作用域链访问所有外部环境,但是外部环境不能访问内部环境中的任何变量和函数。这些环境之间的联系是线性、有序的。每个环境都可以向上搜索作用域链,以查询变量和函数名;但任何环境都不能通过向下搜索作用域链而进入另一个执行环境。延长作用域链四、回调函数五、闭包函数1.什么是闭包函数 闭包函数是指有权访问另一个函数作用域中的变量的函数 2.闭包会把函数中变量的值保存下来,供其他函数使用,这些变量会一直保存在内存当中,这样占用大量的内存,使用不当很可能造成内存泄漏,故要及时清除,清楚方法有两种,一是标记清除,二便是引用计数清除。3.闭包的常用场景有一是函数作为返回值,二是函数作为参数来传递。不适用于返回闭包的函数是个特别大的函数,很多高级应用都要依靠闭包实现.4.使用闭包的好处是不会污染全局环境,方便进行模块化开发,减少形参个数,延长了形参的生命周期,坏处就是不恰当使用会造成内存泄漏六、匿名函数七、递归函数1.什么是递归函数? 递归函数是一个在函数通过名字调用自身的情况下构成的 function factorial(num){ if(num <= 1){ return 1 }else { return num * factorial(num - 1); } } 2.arguments.calls()是一个指向正在执行的函数指针 (严格模式下不支持) function factorial(num){ if(num == 1){ return 1; } else { return num * arguments.callee(num-1) } }3.严格和非严格都有效 var factorial = (function f (num){ if(num == 1){ return 1; } else { return num * arguments.callee(num-1) } }) 八、立即执行函数!function(a){ console.log(a); //firebug输出12345,使用!运算符}(12345);+function(a){ console.log(a); //firebug输出123456,使用+运算符}(123456);-function(a){ console.log(a); //firebug输出1234567,使用-运算符}(1234567);var fn=function(a){ console.log(a); //firebug输出12345678,使用=运算符}(12345678)()、!、+、-、=等运算符,都将函数声明转换成函数表达式,消除了javascript引擎识别函数表达式和函数声明的歧义,告诉JavaScript引擎这是一个函数表达式,不是函数声明,可以在后面加括号,并立即执行函数代码。小结:在JavaScript编程中,函数表达式是一种非常有用的技术。使用函数表达式可以无需对函数命名,从而实现动态编程。匿名函数,也称之为拉姆达函数,是一种使用JavaScript函数的强大方式。以下总结了函数表达式的特点函数表达式不同于函数声明。函数声明要求有名字,但函数表达式不需要。没有名字的函数表达式也叫匿名函数。在无法确定如何引用函数的情况下,递归函数也会变得比较复杂递归函数应该始终使用arguments.callee来递归地调用本身,不使用函数名–函数名可能发生变化 在函数内部定义了其他函数时,就创建了闭包。闭包有权访问包含函数内部的所有变量,原理如下:在后台执行环境环境中,闭包的作用域包含着它自己的作用域、包含函数的作用域和全局作用域。通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。但是,当函数返回一个闭包时,这个函数的作用域将会一直在内存中保存到闭包不存在为止。 使用闭包可以JavaScript中模仿块级作用域(JavaScript本身没有块级作用域的概念),要点如下:创建并立即调用一个函数,这样就既可以执行其中的代码,又不会再内存中留下对该函数的引用。结果就是函数内部的所有便令都会被立即销毁–除非将某些变量赋值给了包含作用域(即外部作用域)中的变量。 闭包还可以用于在对象中创建私有变量,相关概念和要点如下:即时JavaScript中没有正式的私有对象属性的概念,但可以使用闭包来实现公有方法,而通过公有方法可以访问在包含作用域中定义的变量。有权访问私有变量的公有方法叫做特权方法。可以使用构造函数模式、原型模式来实现自定义实现的自定义类型的特权方法,也可以使用模块模式来实现单例的特权方法。 JavaScript中的函数表达式和闭包都是极其有用的特性,利用他们可以实现很多功能。不过,因为创建闭包必须维护额外的作用域,所以过度的使用它们可能会占用大量内存。参考:https://www.cnblogs.com/chenh… http://javascript.ruanyifeng....https://wangdoc.com/javascript/https://www.cnblogs.com/caoru…https://www.cnblogs.com/ukerx… 作用域和作用域链https://www.cnblogs.com/bucho…