#函数的概念及优势
概念:简单来说就是封装了一段可被重复执行调用的代码块,是JavaScript编程的基础。
优势:让大量代码重复使用,减少重复,同时使子程序间相互隔离。
#函数的使用(声明、调用)
一. 函数的声明:(两种)
1.function 函数名(){
函数体代码
}
2.var 函数名 = function(){
函数体代码
}
注:1.function为函数关键词,小写
2.函数名一般命名为动词,如getResult
3.括号内为形参,若有多个用逗号分开
二 .函数的调用:
函数名( );
注:1.只有调用函数才会执行函数体代码
2.括号内为实参,若有多个用逗号分开
函数的封装:
把一个或者多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口
(简单理解:将电脑配件整合组装到机箱中)
#函数的参数,return,arguments
一: 函数的参数(形参,实参)
形参:形式上的参数(声明函数时),是接收实参的,类似于一个不用声明的变量,默认undefined
实参:实际上的参数(函数调用时)
形参、实参的匹配问题:
形参>实参:NaN,被赋值为undefined
形参<实参:忽略额外的实参
注:1.函数可为无参数
2.若多余的形参后面写=运算符,后跟一个表达式,那么将在未给出某参数时用此表达式的值替换该参数。
function getsum(a,b=2){
let sum=1;
for(let counter=0;counter<b;counter++){
sum=sum*a;
}
return sum;
}
console.log(getsum(2));//4
console.log(getsum(2,4));//16
二:返回值return
1.在函数体内部,return后面的代码不执行
2.return只能返回一个值,若需要返回多个值可包含在一个数组内
3.函数若无return,则返回undefined
4.区分break,continue,return
break:跳出循环体
continue:跳出本次循环体,进行下一次
return:退出循环,返回值,结束后面的代码
三:arguments(函数内置的)
arguments存储了传递过来的所有实参,以伪数组形式可进行遍历
#作用域(变量在某个范围内起作用)
一. 全局作用域、局部作用域(函数作用域)、块级作用域(ES6新增)
全局作用域:整个script标签内,或单个js文件
函数作用域:顾名思义,只在函数内部起作用效果
块级作用域:由 { } 包括,if语句和for语句里面的{ }也属于块作用域
注:词法作用域,就是在写代码时将变量和块作用域写在哪里来决定,也就是词法作用域是静态的作用域,在书写代码时就确定了。
二. 作用域链
概念:根据内部函数可以访问外部函数变量的这种作用机制,用链式查找决定哪些数据能被内部访问
注:站在目标出发,一层层往外查找(类似就近原则)
function f1(){
var num =1;
function f2(){
var num=0;//*
console.log(num);//目标
}
f2();
}
var num =3;
f1();
//结果是0 如果去掉*行,结果是1
#箭头函数
概念:函数的第三种表示方法,由 => 代替function关键字,便于以较简明方式编写小型函数表达式
const square1 = (x)=> {return x*x};
const horn = ()=> {
cosole.log(“toot”);
}
注:1.箭头位于参数列表之后,后接函数体,表达类似“这个输入(参数)产生这个结果的意思”
2.如果没有参数或有两个及以上,不能省略括号;有一个参数,可以省略
3.如果函数体是单个表达式,而不是{ }中的块,函数将返回这个表达式
4.箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种只包含一个表达式,省略掉了{ … }和return。还有一种可以包含多条语句,这时候就不能省略{ … }和return
5.用小括号包含大括号则是对象的定义,而非函数主体
x => {key: x} // 报错
x => ({key: x}) // 正确
6.箭头函数内部的this是词法作用域,由上下文确定。
7.var、const、let区别
var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。
let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。
const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。
#调用栈(call stack)
概念:一种栈结构,它用来存储计算机程序执行时候其活跃子程序的信息。(比如什么函数正在执行,什么函数正在被这个函数调用等等信息)
栈:动态分配的空间,维护函数调用的上下文。只有一个口可供进出,先入在底,后入在顶,先进后出。
堆:队列优先,先进先出。
栈帧:每次函数调用后,都会在调用栈上维护一个独立的栈帧。
function boo (a) {
return a * 3
}
function foo (b) {
return boo(4) * 2
}
console.log(foo(3))
过程:先形成一个栈帧,调用foo函数,又形成一个栈帧,新形成的栈帧压在之前栈帧的上面。由于foo函数里面又调用了boo函数,则又形成一个新的栈帧。当boo函数执行完后,返回值给foo函数,boo被推出调用栈。之后foo函数继续执行,返回值给console.log后被推出调用栈,直至最后console.log也被推出栈,程序执行完毕。
#递归
概念:在程序中函数直接或间接调用自身。将一个问题由难化易,由繁化简,由复杂化简单的过程称为化归,它是转化和归结的简称。
function fun(n) {
…
fun(n-1);
}
注:由于递归里面很容易发生“栈溢出”,所以必须加退出条件return。
#闭包(closure)
概念:引用了自由变量的函数。指一个函数与周围状态(词法环境)的引用捆绑在一起(封闭)的组合,在JavaScript中,每次创建函数时,都会同时创建闭包。
闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰,即形成一个不销毁的栈环境。
function a(){
var i=0;
function b(){
alert(++i);
}
return b;
}
var c = a();
c();
当函数a的内部函数b,被函数a外一个变量引用时,就创建了一个闭包。
#添加函数的时机
1.当多次编写类似的代码时,可以把重复的功能提取出来,找到一个好名称,并将其放入一个函数中。
2.需要一些尚未编写的功能,并且似乎它应该有自己的函数。于是从命名函数开始,然后编写函数体。
注:具有简单明了的好名字函数,使读代码的人更容易清楚它们的功能,并且函数能在更多情况下使用。
#副作用与纯函数
一 .函数副作用
当调用函数时,除了返回函数值之外,还对主调用函数产生附加的影响。(如修改了一个变量、改变数据结构、出现异常或终止、读取一个文件等)
这会降低程序可行性,带来不必要的麻烦。
二 .纯函数
一种特定的产生值的函数。函数与外界交换数据只有一个唯一渠道——参数和返回值
优势:1.无副作用,不依赖于其他代码产生的副作用
2.当使用相同参数调用时,总是生成相同的值(只要参数不变,函数的值始终不变)
3.可以通过简单的调用来测试它