函数浅析

首先我们要思考,为什么需要函数这个东西。函数的出现涉及一个编程原则:高内聚 低耦合。

低耦合是指降低代码的重复率,不要写冗余的代码。高内聚是指代码紧密联系性强,独立性强。使得代码能够实现模块的单一责任制,一个模块负责一个功能,各司其职,然后组合在一起。

当代码耦合性过高时,就需要解耦合,JS中解耦的常用方法就是抽离成函数,定义函数,是一个固定的功能或者程序段被封装的过程。实现这个过程需要在这个封装体中设置一个入口和一个出口,入口就是参数,出口就是返回(值)。

定义函数

定义函数的方式有两种:

函数声明 该方式定义的函数,函数名变成了一个变量,这个变量的值就是函数本身。

scss 复制代码
function test(){
    console.log('HelloWorld');
}
test(); // 'HelloWorld'

函数表达式 看起来像函数声明,但它的函数名是可选的,大部分情况下是不写的(即匿名函数)。除非函数执行过程中需要引用自身,比如阶乘函数。如果函数表达式包含名字,则该函数的局部作用域中会包含一个该名字与函数对象的绑定。

javascript 复制代码
const test = function(){
    console.log('HelloWorld');
}
test(); // 'HelloWorld'

函数属性

函数是一种特殊对象,它也有自己的属性,其中有些常用的属性。

name属性 可以获得函数的名字。

javascript 复制代码
function test(){
    console.log('HelloWorld');
}
console.log(test.name); // 'test'
javascript 复制代码
const test = function(){
    console.log('HelloWorld');
}
console.log(test.name); // 'test'

length属性 可以获得函数形参的数量。

javascript 复制代码
function test(a, b, c){
    console.log(a, b, c);
}
console.log(test.length); // 3

函数形参与实参

形参与默认值

调用函数时,如果没有给形参设定默认值,并且也没有传入实参,那么参数的默认值是undefined。

scss 复制代码
function test(a, b){
    console.log(a); // 1
    console.log(b); // undefined
}

test(1);

如果需要给参数指定默认值,可以在定义函数时给形参设定默认值,注意这种方式是ES6的写法。

scss 复制代码
function test(a = 1, b = 2){
    console.log(a); // 1
    console.log(b); // 2
}

test();

如果形参设定了默认值,实参也进行了传值,那么就需要分为多种情况:

  • 第一种是形参默认值是undefined,实参是有效值。这种和形参不设定默认值的效果是一样的,输出结果是实参的值。
scss 复制代码
function test(a = undefined, b){
    console.log(a);
    console.log(b);
}

test(1, 2); // 1 2
  • 第二种是形参默认值是有效值,实参是undefined。此时会选择形参的默认值使用,这种形式通常是为了方便给后面的形参传值。
scss 复制代码
function test(a = 1, b){
    console.log(a);
    console.log(b);
}

test(undefined, 2);  // 1 2
  • 第三种就不用说了,形参和实参都是undefined,那结果自然是undefined。

arguments对象

在ES5中,并没有直接给形参设定默认值的写法,所以如果需要设定默认值,需要使用arguments对象,它是所有(非箭头)函数中都可用的局部变量,此对象包含传递给函数的每个实参,可以通过它在函数中引用函数的实参,它是一个类数组,第一个实参位于索引0处。

css 复制代码
function test(a, b){
// 这种方式也是变相的实现了为参数设定默认值
    var a = arguments[0] || 1;
    var b = arguments[1] || 2;
    console.log(a);
    console.log(b);
}

test(3); // 3 2

函数递归

函数递归就是函数自己调用自己,比如不用for循环,实现n的阶乘。要注意,递归一定要有一个出口,不然就会无限递归下去,比如以下代码中fact(1)就是出口,因为当n为1时,会返回一个确定值,这样就可以开始计算之前排队等着的运算。

scss 复制代码
function fact(n){
    if(n === 1){
        return 1;
    }else{
        return n * fact(n - 1);
    }
}
console.log(fact(5)); // 120

函数递归实现斐波那契数列。

scss 复制代码
// 规律:n3 = n2 + n1;
// 出口:n <= 0    n <= 2;
function fb(n){
    if(n <= 2){
        if(n <= 0){
            return 0;
        }else{
            return 1;
        }
    }else{
        return fb(n - 1) + fb(n - 2);
    }
}
console.log(fb(10)); // 55
相关推荐
李纲明6 分钟前
WordPress 站点变慢:按 TTFB → 缓存 → 查询 → 前端 分层排查(含配置注意)
前端·缓存·性能优化·wordpress·后端开发
程序人生88815 分钟前
PDF 转 Word 版式错乱、表格丢失?DocConverter Web 格式互转引擎的保真实践
前端·人工智能·opencv·机器学习·pdf·word
粥里有勺糖1 小时前
安利一下最近用的桌面“Agent” | T3 Code
前端·github·ai编程
xy34531 小时前
Axure 9.0 动态面板基本操作
前端·ui·html·axure·原型·产品设计
不停喝水2 小时前
【前端转全栈java速通课】 项目实战④7-11节 操作数据库-登录-注册-修改密码-注销-mubatis-plus简化crud-
java·前端·数据库
一水鉴天2 小时前
统一对象拓扑(UOT)设计全链定稿:从三件事分离到三继承 之1 20261010(豆包“查看聊天内容”继续)
前端·css
杨杰3982 小时前
我给嵌入式设备写了个 6MB 的 JavaScript 运行时(xuan)
javascript
栖凤3 小时前
Java 的 try-catch 在 Agent 里失效了,我用了 5 个模式才兜住
java·前端·python
粥里有勺糖3 小时前
视野修炼第136期 | 前端小恐龙"Deno"被收购
前端·github·ai编程
修炼的dance3 小时前
页面塞了13.88 MB字体,导出的PDF只有71 KB
前端