## 函数
**函数的三要素**
是指函数的功能,函数的参数,以及函数的返回值。
函数的最大好处就是可以对代码实现复用,相同的功能不用再次书写,而是只用书写依次就够了。
**声明函数的方式**
1·字面量声明函数
使用关键子function来创建一个函数;具体语法:
function 函数名(形式参数){//函数体}
函数名:就是我们调用函数时需要书写的标识符
形式参数:简称形参,是调用函数时需要接收的参数
实际参数:简称实参,是调用函数时实际传递过去的参数
2·函数表达式声明函数
语法:
let 变量 = function(){//函数体}
3·构造器声明函数
又被称之为通过对象的方式来声明函数
语法:
let 变量 = new Function("参数","参数","参数");
**函数的调用**
就是写上函数名或者变量名,后面加上一对括号。
如果要调用函数,那么必须要有大括号。这个括号要么在函数名后面,要么在变量名后面,这样才能够将调用的函数后执行的结果返回,如果缺了括号,那就只是引用函数本身。
**函数的返回值**
函数的返回值的关键字为return。待变要从函数体内部返回给外部的值
即使不写return,函数本身也会有返回值 undefined
注意的是:return后面的代码是不会执行的,因为在函数黎明一旦执行到return,整个函数的执行就结束了。
return关键字只能返回一个值,如果想要返回多个值,可以考虑返回一个数组。
示例
//1-60的安全数,7的倍数或者以7结尾的数 let test = function(){ let arr = []; for(let i=1;i<=60;i++) { if(i%10==7 || i%7==0) { arr.push(i); } } return arr; } console.log(test()); //[ 7, 14, 17, 21, 27, 28, 35, 37, 42, 47, 49, 56, 57 ]
**函数的参数**
分为实际参数,形式参数
形式参数,简称形参,就是一种变量,但是这个变量只能函数体内的语句使用,并在函数调用时被赋值。
关于形参注意点:
1·参数名可以重复,同名的参数取最后一个参数值
2·即使函数声明了参数,调用时也可以不传递参数值
3·调用函数时可以传递若干个参数值给函数,而不管函数声明时有几个参数
**不定参数**
是从ES6新添加的功能,在最后一个形式参数前面添加3个点,会将所有的实参放到一个数组里面。
示例:
function test(a,...b){ console.log(a);//1 console.log(b);//[2,3] } test(1,2,3); 不定参数就是一个真正的数组,可以使用数组的相关方法 function test(a,...b){ console.log(a);//1 console.log(b);//[2,3] b.push(100); console.log(b);//[ 2, 3, 100 ] } test(1,2,3);
不定参数都是放在形式参数的最后面,如果不是放置最后,则会报错。
**默认参数**
从ES6开始,书写函数的时候可以给函数的形式参数一个默认值,如果在调用函数时没有传递相应的实际参数,就使用默认值,如果传递了相应的实际参数,则使用传过去的参数。
示例:
function test(name = "world"){ console.log("Hello,"+name); } test("xiejie");//Hello,xiejie test();//Hello,world 如果参数时一个数组,要为这个数组设置默认值的话, 示例: let fn = function([a = 1,b = 2] = []){ console.log(a,b); } fn(); // 1 2 fn([3,4]); // 3 4
**函数的属性和方法**
1·name属性:表示函数的函数名
2·length属性:表示形式参数的个数
注意的是:函数名.length与arguments.length的区别:
函数对象的length属性是表示形式参数的个数
arguments伪数组对象的length属性是带哦用函数时实际参数的个数
3·caller属性:
caller属性并不是arguments对象的,而是函数对象本身的属性,它显示了函数的调用者,如果函数是在全局执行环境中(浏览器中)被调用,那么它的值为null,如果在另一个函数中被调用,它的 值就是那个函数。
全局执行环境中被调用:
浏览器中 <body> <script> let test = function(){ console.log(test.caller); } test();//null </script> </body> node 中 let test = function(){ console.log(test.caller); } test();//[Function] 被一个函数所调用: let test = function(){ let test2 = function(){ console.log(test2.caller); //[Function: test] //因为这个函数的调用者就是test函数 } test2(); } test();
4·callee属性:
callee是arguments对象的一个属性,该属性是一个指针,指向拥有这个arguments对象的函数
let test = function(){ let test2 = function(){ let test3 = function(){ console.log(arguments.callee); //[Function: test3] } test3(); } test2(); } test();
callee的作用在于能够找到arguments对象所属的函数,不让函数的执行和函数名仅仅的关联在 —起,我们来看下面这个例子:
//计算阶乘的递归函数 let test = function(i){ if(i == 1){ return 1; }else{ return i * test(i-1); //这里就和函数名紧紧的关联了起来 } } console.log(test(3)); 如果我们把上面的写法稍作修改,就可以看到上面写法的缺陷 //计算阶乘的递归函数 let test = function(i){ if(i == 1){ return 1; }else{ return i * test(i-1); //这里就和函数名紧紧的关联了起来 } } let test2 = test; //将阶乘函数赋值给test2 / /改变test这个阶乘函数的函数体 test = function(){ console.log("我已经改变了"); console.log(test2(3)); //我已经改变了 // NaN 所以,这个时候就可以使用arguments对象的callee属性来降低这种关联 //计算阶乘的递归函数 let test = function(i){ if(i == 1){ return 1; }else{ return i * ar guments.callee(i-l); //callee 指向拥有arguments 对象的函数 } } let test2 = test;//将阶乘函数赋值给test2 / /改变test这个阶乘函数的函数体 test = function(){ console.log("我已经改变了"); } console.log(test2(3));//6
**箭头函数**
是ES6新添加的一种声明函数的方式。特点是不需要function关键字,使用一个=>来表示
语法:
let 变量 = (形式参数)=>{//函数体}
其他几种书写方法;
没有参数:let 变量 = ()=>{}
一个形式参数:let 变量 = 形参 =>{}
函数只有一个返回值:let 变量 = 形参 =>expression
示例:书写求立方根的箭头函数
let test = x => x*x*x; console.log(test(3));//27
**箭头函数的优点**
- 比普通函数声明更简洁
- 只有一个形参就不需要用括号括起来
- 如果函数体只有一行,就不需要放到一个块中
- 如果return语句时函数体内唯一的语句,就不需要return关键字
- 不会把自己的this值绑定到函数上
## 提升
**作用域**
*全局作用域*:这是默认的代码运行环境,一旦代码被载入,引擎最先进入的就是这个环境。
*函数作用域*:当进入一个函数的时候,就会产生一个函数的作用域
*eval作用域*:当调用eval()函数的时候,就会产生一个eval作用域(很少用了)
函数作用域:在内层函数作用域里面可以访问全局作用域或者外层函数作用域里面的变量或者函数。但是反过来全局作用域或者外层函数作用域里面的不能访问内部函数作用域里面的变量或者函数。
**变量提升**
就是使用var关键字进行变量声明的时候,默认会将声明变量的部分提升至当前作用域的最顶上,注意提升的只有变量声明部分,赋值是不会提升的
只有var声明的变量才具有这种特性,let和const不存在变量提升
**函数提升**
是指当我们使用字面量方式来声明一个函数的时候,此函数的声明会提升到当前作用域的最顶端,意味着我们可以将函数的电泳书写在函数的声明之前。
示例:
test();//Hello! function test(){ console.log("Hello!"); } // 等价于 // test : pointer to test() // test() // function test() // { // console.log("Hello!"); // }
注意的是:仅仅只有普通的函数声明才存在函数提升,如果使用函数表达式来进行的函数声明,不存在有汗提升的情况
变量提升和函数提升是可以同时存在的。
示例:
console.log(test);//undefined var test = function(){ console.log("Hello!"); } console.log(test);//[Function: test]
## 回调函数
就是将一个函数作为参数传递给灵位一个函数,然后再另一个函数里面执行传递过去的函数
常见的回调函数:
sort(),forEach(),map(),every(),some()
**迭代方法**
every():对数组的每一项运行给指定的函数,如果该函数每一项都返回true,则返回true
some():对数组的每一项运行指定的函数,如果该函数只要有一项返回true则返回true
filter():过滤,返回一个数组,数组里面是返回true的元素。
forEach():将数组的每一项传入函数,执行该函数的代码,该回调函数没有返回值。
map():对数组的每一项运行test函数,返回一个数组,之歌数组是每次调用函数后的运行结果
示例:
let arr = [1,2,3,4,5,6,7,8,9,10]; //将数组的每一项传入到回调函数,然后将返回的结果组成一个新的数组返回 let i = arr.map(function(item){ if(item % 2 == 0){ return true; }else{ return false; } }); console.log(i); //[ false, true, false, true, false, true, false, true, false, true ]