函数
函数的意义在于封装:把实现某一个功能的代码封装在一起,后期在想这个功能,只需要执行函数即可,不需要重新编写这些代码“低耦合,高内聚”
- 1.创建函数:把实现某个功能的代码封装在一起
function 函数名(形参1,...){
//=> 函数体:实现具体功能的代码
}
- 2.执行函数:让函数执行,从而实现具体的功能
- 函数名(实参1,...)
- 3.创建一个函数:把时间格式化的操作全部封装成为一个函数,代码统一封装起来
function formarTime(time,templete="{0}年{1}月{2}日 {3}时{4}分{5}秒"){
let timeAry=time.match(/\d+/g);
return templete.replace(/\{(\d+)\}/g,(...[,$1])=>{
let time=timeAry[$1]||"00";
return time.length<2?"0"+time:time;
})
}
let time1='2020/03/07 11:37:00';
let time2='1998-12-18 00:00:00';
console.log(formatTime(time1,'{0}年{1}月{2}日'));//=>2020年03月07日
console.log(formatTime(time2,'{1}-{2} {3}-{4}'));//=>12-18 00-00
console.log(formatTime(time1));//=>2020年03月07日 11时37分
- 4.项目中,发现一个功能要重新运行两次及两次以上,此时我们就把这个功能封装成为一个函数,以后再想实现整个功能,直接吧函数执行即可
//1.创建函数
function func(){
console.log('我会玩函数了!')
}
//2.执行函数:需要几次就执行几次
func();
func();
- 5.两个数的求和 封装
函数中有一个形参和实参的概念
- 形参:生产一个函数,想要实现一些功能,但是实现功能,需要的原材料不确定,需要用户执行时候给我,我才知道,此时我们就提供入口=>形参(变量)
- 实参:执行函数的额时候,给指定的入口(形参变量)床底的具体值(值)
function sum(x,y){
//创建函数的时候,并不知道要求那两个数字的和,此时可以定义形参变量
// x和y就是形参变量
let total=x+y;
console.log(total);
}
//1.x=10 y=20是实参变量传递的具体值
sum(10,20);//=>3
//2.x=1 y=10
sum(1,10);//=>11
//=>3.x=10 y=undefined 定义了形参,但是执行的时候不给传递实参,则形参morenzhindefined
sum(10);//=>NaN
//4.第三个实参并没有对应的形参来接收(但是传递给函数了)
sum(10, 20, 30); //=> x=10 y=20
//5.形参永远是一个结果,所以x=30
sum(10 + 20); //=> x=30 y=undefined
//6.也需要把三元表达式运算的结果作为实参传递给形参
sum(1 === 1 ? 'OK' : 'NO');//=>Ok
//7.实参永远都应该是值,此处虽然写的AGE,但是会把AGE变量的值拿到,然后传递给形参x,而不是把AGE本身传递过去
let age = 20;
sum(age); //=> x=20
- 6.任意数求和,不管传递几个实参值进来,我们都能求出对应的和
有一个具体的问题:基于形参变量来接收求和的数字已经不现实了,因为我们也不知道要传递多少个值,也就无法确定要定义多少个形参变量了
- 1)arguments函数内置的实参集合:不管我们设置与否形参,再或者是否传递了实参,ARGUMENTS始终都会存在(ES6箭头函数中没有ARGUMENTS) =>只能出现在函数体中
function sum() {
/*
* ARGUMENTS是一个类数组集合(类似数组,但是不是数组,和元素集合HTMLCollection类似)
* =>根据索引记录了每一个传递进来的实参信息(和是否定义形参变量没有关系,
* ARGUMENTS中包含了所有传递进来的实参信
* =>LENGTH属性代表传递实参的个数
*/
//循环ARGUMENTS中的每一项(每一个传递进来的实参),都累加给TOTAL,最后就能求出和了
let total = 0;
for (let i = 0; i < arguments.length; i++) {
// 把传递进来的实参信息都转换为数字:排除掉非有效数字或者字符串
let item = Number(arguments[i]);
if (!isNaN(item)) {
// 有效数字
total += item;
}
}
console.log(total);
}
sum(); //=>0
sum(10); //=>10
sum(10, 20); //=>30
sum(10, 20, 30, 40); //=>100
sum(10, 20, 'AA'); //=>30 过滤掉非有效的数字
sum(10, '20'); //=>30 如果是字符串,不能是字符串拼接,还应该是数学相加
- 2)使用ES6中的剩余运算符
function sum(...args) {
// ...args:ES6中的剩余运算符,把传递进来的实参信息,
//都已数组的形式保存到ARGS变量中
let total = 0;
for (let i = 0; i < args.length; i++) {
let item = Number(args[i]);
if (!isNaN(item)) {
total += item;
}
}
console.log(total);
}
sum(10, 20, 30, 40);
- 7.函数中return
当函数执行的时候,会形成一个全新的执行上下文(函数体中的代码会在这个上下文中运行),代码运行中,会把所有创建的变量存储到当前上下文的AO(变量对象)中,这些变量是“私有变量”:除当前上下文中可以使用这些变量的值,上下文以外的环境不能直接使用私有变量的值
- 如果,外面想用当前上下文中的一些私有信息,则需要函数提供对应的出口,把信息提供给外面使用,而这个出口在JS函数中被称为“返回值 return”
function sum() {
// total:当前上下文中的私有变量
let total = 0;
for (let i = 0; i < arguments.length; i++) {
let item = Number(arguments[i]);
if (isNaN(item)) {
continue;
}
total += item;
}
// 1.基于RETURN把TOTAL暴露给外面使用
// 2.RETURN后面放的一定是值:此处相当于把私有TOTA变量的值返回给外面使用 => RETURN 30;
return total;
}
sum; // 函数本身 sum = 函数
sum()://让函数执行,代表的是函数的返回值
console.log(sum);
console.log(sum());
//3.创建一个变量N,用来接收函数执行完返回的值:RETURN后面的值
//4.如果函数中没有写RETURN,默认的返回值是UNDEFINED
let n = sum(10, '20', 'AA');
console.log(n);
console.log(total); //=>Uncaught ReferenceError: total is not defined
function func(x) {
// 验证X是否为有效数字,如果不是有效数字,则不再继续执行下面的代码
if (isNaN(x)) {
return; //=>RETURN在函数中,除了返回信息外,还有告知函数体中下面代码不再执行的作用
}
let result = x % 2;
return result;
}
console.log(func(10));
2.函数的类型
1实名函数,有名字的函数
function func() {}
2.匿名函数:把一个函数当做值赋值给变量或者事件绑定
document.body.onclick = function () {
// 此处就是匿名函数
};
let fn = function () {
// 也是匿名函数 fn代表这个函数 和 function fn类似
};
3.自执行函数:函数创建完就立即执行了
(function (n) {
// n的值是100
})(100)
4.箭头函数(ES6中新定义的创建函数的方式)
let func = (x, y) => {
// x和y是形参变量
// 大括号中还是函数体
};
func(10, 20);
4.1箭头函数可以简化函数编写的方式:如果函数体中只有一句RETURN,则可以忽略大括号和RETURN
function sum(x, y) {
return x + y;
}
//箭头函数写法:
let sum = (x, y) => x + y;
function func(x) {
return function (y) {
return x + y;
}
}
//箭头函数写法:
let func = x => y => x + y;