函数
函数的意义在于封装:把实现某一个功能的代码封装在一起,后期在想实现这个功能,只需要执行函数即可,不需要重新编写这些代码了。
“低耦合、高内聚”:减少代码的冗余,提高代码使用率。
1.创建函数
function 函数名(形参1,…){
//=>函数体:实现具体功能的代码
}*
2.执行函数:
让函数执行,从而实现具体的功能
函数名(实参1,…);
函数名(实参1,…);
// 1.创建函数
function func() {
console.log('我会玩函数了!');
}
// 2.执行函数
func();
func();
形参和实参
形参:生产一个函数,想要实现一些功能,但是实现功能,需要的原材料不确定,需要用户执行它的时候给我,我才知道,此时我们就提供入口 => 形参(变量)
实参:执行函数的时候,给指定的入口(形参变量)传递的具体值(值)
function sum(x, y) {
// 创建函数的时候,并不知道要求哪两个数字的和,此时可以定义形参变量
// =>x和y就是形参变量
let total = x + y;
console.log(total);
}
sum(10, 20); //=>x=10 y=20是实参(给形参变量传递的具体值)
sum(1, 10); //=>x=1 y=10
sum(10); //=>x=10 y=undefined 定义了形参,但是执行的时候不给传递实参,则形参默认值undefined
return 返回值
return是函数的返回值机制【出口】 return后面放的是”值”
函数里面return 多少,这个函数的返回值就是多少,如果没有返回值,就是undefined;
如果形参数量为两个 实参传递为1个 则不传递的那个值为undefined
return会打断函数执行
function sum(x, y) {
return x + y;
console.log(123);
}
sum(1,2);//返回值为3,但是不会输出123
arguments实参合集
arguments函数内置的实参集合:不管我们设置与否形参,再或者是否传递了实参
ARGUMENTS始终都会存在(ES6箭头函数中没有ARGUMENTS)
arguments是一个类数组集合(类似数组,但是不是数组)
根据索引记录了每一个传递进来的实参信息(和是否定义形参变量没有关系,ARGUMENTS中包含了所有传递进来的实参信息)
length属性代表传递实参的个数
求两个数的之和
函数执行的时候:
- 形参赋值
- 变量提升
- 代码从上往下执行
无返回值:
/* 求两个数的和 */
/* function sum(n,m){
//n/m:形参[变量] 用来接收后期执行时候,传递进来的实参值
//需求:如果n/m 的值是非有有效数字,我们让其为0
n=+n; //默认转Number数字
m=+m;
if(isNaN(n)){//只有一行的时候可以把大括号省略 判断n是否是有效数字
n=0;
};
isNaN(m)?m=0:null;
var total=n+m;
console.log(total);
}
sum(10,"20");//n=10 m=20
sum(10);
// n=10 m=undefined 设置形参 但是不传递实参,默认值是undefined */
有返回值
function sum(n,m){
n=+n;
m=+m;
isNaN(n)?n=0:null;
isNaN(m)?m=0:null;
var total=n+m;
// console.log(total);//里面用total肯定可以 因为是自己家的【大括号/函数体相当于单独的一家人】
//return是函数的返回值机制【出口】 return后面放的是"值",所以此处“return total;->return 30;”
// +如果不写return ,我们默认返回值是undefined
// +在函数体中遇到return 直接返回结果即可,后面的代码则不再执行了
return total; //私有变量
}
// 外面叫做total,和里面的不是一个变量,没啥直接的关系
// +sum();把函数执行 代表的是函数执行后的返回值[RETURN]
// +sum:变量/函数名,代表的创建函数本身[堆内存地址]
var total=sum(10,"20");
console.log(total);
不知道要传递多少个参数,求所有数之和
【arguments】:内置实参集合 【包含了传递进来的所有实参值 “类数组集合”】
function total(){
console.log(arguments)
}
total(3,4,5,6)
利用arguments求和
function total(){
var res=null;
for(var i=0;i<arguments.length;i++){
res+=arguments[i];
}
return res;
}
var res= total(3,4,5,6);
console.log(res);
求所有数之和(考虑非有效字符)
function total(){
var res=null;
for(var i=0;i<arguments.length;i++){
//var item=Number(arguments[i]);
var item= +arguments[i];
if(isNaN(item)){
item=0;
}
res=res+item;
}
return res;
}
var result1=total("1",2,"16px",3);
console.log(result1);
[升级版2]
如 需求:任意数求和:不论传递多少实参值,都可以求和
+传递的是非有效数字,则按照0处理 或者不是处理
+传递的是字符串,需要先变为数字在求和,避免字符串拼接
function sum(){
//arguments:内置实参集合 【包含了传递进来的所有实参值 “类数组集合”】
// console.log(arguments);
var total=0;
for(var i=0;i<arguments.length;i++){
// 获取当前的循环中的集合的这一项,并且把其变为数字
var item= +arguments[i];
// 如果item不是一个有效数字,则结束当前这轮循环[不求和了] 继续下一轮即可
if(isNaN(item)) continue;
total+=item;
}
return total;
}
console.log(sum(10,20,'30','AA',40));
console.log(sum(10,20,30));
console.log(sum(10));
console.log(sum());
函数创建的具体过程
1.创建函数
@1 开辟了一个堆内存空间[16进制的内存地址]
@2 向空间中存储内容
作用域
函数体重的代码字符串
键值对
name:函数名
length形参个数
@3 把地址放在栈中,供变量调用
注:只创建函数 但是不执行,函数没有任何意义,因为它只是开了堆内存 存储一堆破字符串而已
函数执行的具体过程
- 创建一个全新的执行上下文,把执行上下文压缩到栈内存中去执行(⇒进栈执行)
- 在这个上下文中,也存在一个变量对象,用来存储当前上下文代码中所创建的变量
- 代码执行
- 当上下文中的代码都执行完后,如果该上下文中的信息没有被外面占用的情况,则执行完出栈(释放内存)
如果,外面想用当前上下文中的一些私有信息,则需要函数提供对应的出口,把信息提供给外面使用,而这个出口在JS函数中被称为“返回值 return”
匿名函数
没有名字的函数
• 实名函数:就是有名字的函数
• 匿名函数:没有名字的函数,比较常见的有
• 函数表达式:把一个匿名函数赋值给一个变量或者事件
• 自执行函数:创建和执行一起完成。(()、+、~、!)
1.匿名函数——-【事件绑定】
var btn=document.querySelector("#btn");
btn.οnclick=function(){
// alert("document");
}
2匿名函数——-【定时器】
//定时器
//setTimeout(函数体,时间(单位:毫秒)) 多少毫秒之后执行(只执行一次)
//setInerval(函数体,时间(单位:毫秒)) 每隔多少毫秒一次
//清定时器用clearInterval(timer);
setTimeout(function(){
console.log("只执行一次呀");
},1000);
var timer=setInterval(function(){
console.log("每隔两秒执行一次");
},2000);
//10秒停止 清空定时器
setTimeout(function(){
clearInterval(timer);
},10000);
3. 匿名函数——-【匿名函数具名化】
var fn = function () {};
fn();
4. 匿名函数——-【作为对象中的一个属性】
var obj={
name:"dddd",
say:function(){
alert(this.name);
}
}
obj.say();
5.自执行函数
一个函数在定义后立即执行
创建和执行都一起完成的[用小括号包起来,或者在前面加入“~/+/!” 等都是为了保证语法不出错]
var a = (function (i) {
console.log(123);
//可以拿到返回值
return 1;
})(10);
var b = ~ function () {
console.log(123);
//拿不到返回值
return 2;
}();
console.log(a, b);//=>1 -3
/* +function(){}();
~function(){}();
!function(){}(); */
6.回调函数callback
把函数体作为参数,传到另一个函数中去执行
什么情况用:
大多数是内置方法需要自己的某项特殊功能的时候 如Sort forEach
function fn(){
alert("setTimeout");
}
setTimeout(fn, 1000);
//回调函数例子
function fn(callbak){
// callbak:传递进来的匿名函数
callbak();
}
fn(function(){
})
forEach传递进来的参数也叫做回调函数
传递进的参数也叫做匿名函数 回调函数
/*
把数组的forEach方法执行,传递一个匿名函数@A[回调函数] 那么在forEach内部,就可以获取到这个@A
接下来forEach内部干了点事情,循环数组中的每一项,每循环一次都把@A 执行一次【数组有多少项 回调函数@A就要被执行多次】
并且把每次循环得到的当前项和当前项索引,传递给@A的item/index...
->@A:function(item,index)
*/
var arr=[1,11,2,34,24];
arr.forEach(function(item,index){
//item当前项
//index 当前项的索引
})
箭头函数
与普通函数的区别:
1.没有arguments
2.没有自己的this,this是执行上下文的this
let fn = () => {};
//如果箭头函数只有一个参数,可省略小括号,只写形参
let fn2 = str => {};
//如果大括号内,除了return没有多余语句,可省略大括号和return
let fn3 = num => num + 1;
// 写全=>let fn3 = (num) => {return num + 1};
//箭头函数和普通函数的区别
// 1、箭头函数没有arguments;arguments只能在普通函数用;箭头函数想要拿到所有的实参需要用...展开运算符
// 2. this 不一样
var fn5=(...arg)=>{
//console.log(arguments); //箭头函数练习.html:37 Uncaught ReferenceError: arguments is not defined
console.log(arg);
}
fn5(2,3,5);
/* this不一样 */
var btn=document.getElementById("btn");
btn.onclick=function(){
console.log(this);
};
//箭头函数
btn.onclick=()=>{
console.log(this);
}
递归
函数自己调用自己,叫做递归
//求1-100的累加结果
function sum(n) {
//边界:停止条件
if(n<0) {
return 0
}
return n+=sum(n-1);
}
sum(100)