JavaScript(7) | JS函数基础

254 阅读13分钟

函数

1. 函数简介

1、对象

概念: 把现实中的「概念」投影到计算机世界(编程)中。

所以想要理解对象,首先要能在生活中寻找实现的「概念」,这取决于「人」的认知。

具体的实体: 日常生活中的物体,猫,狗,桌子,凳子,房子,车子...

一般是「静态」的,名词

2、函数

概念: 将现实世界中的事物及其事物之间的关系构建模型,关注 因果关系,即 输入和输出。创建数学模型。

3、方法

概念: 方法是解决一个问题的方式,有着若干步骤。方法这个词 是 针对 「人」的思维来讲的,而 函数是抽象的概念,有明确的输入输出。

解释:

image.png

4、函数的理解

想要理解函数,首先要知道「非函数」

不管是函数还是非函数,都需要知道现实世界中人们如何处理问题,「算法」是什么?

编程是用于解决问题的,根据不同的需求就会产生不同的问题 !

典型的 “把大象放进冰箱,总共有几步?”

实际上,可以直接说“夏天,为了放置西瓜腐败变坏,需要放入冰箱,共有几步?”这个切合实际需求的例子可能比较好理解

比较理性的分析:

1、找到西瓜
2、拿起西瓜
3、找到冰箱
4、走向冰箱
5、打开冰箱门
6、打开冰箱抽屉
7、关闭冰箱抽屉
8、放入西瓜
9、关上冰箱门

为什么说「理性」的分析呢,因为实际生活中,并不会有人有如此复杂的思维过程,显然这种过程是给计算机「看的」,像这样有着严格的套路,步骤能解决一个实际问题的「语句」称作解决问题的「算法」

⚠️ 上述只是个人的浅薄的看法😅

倘若上述的一个问题叫做: 「如何把西瓜放入冰箱」

假设「张三」不知道这个概念(什么叫做把西瓜放入冰箱),就不得不需要解释,解释的过程就是算法的「演示」

像上述9个步骤能解决实际问题的「算法」,如果每次都需要向「张三」解释说明,这样实在是太愚蠢了,效率很低、所以只需要告诉张三

image.png

这个问题 = 这个步骤 或 这些步骤 = 这个问题的答案

这样当需要把西瓜放入冰箱,就不需要展示出 这些「长长」的步骤

而只需告诉「张三」“张三,把西瓜放入冰箱”

这个「告诉」就是 「命令」order,command

假如需要放进冰箱的不是 西瓜而是...冰激凌怎么办?

只需要将「西瓜」改为「冰激凌」不就好了

5、JavaSript中的函数

在javascript中,所有的元素都是对象

函数可以是对象

函数中可以封装一些代码,功能,需要的时候可以调用函数

比如

console.log( "我是一个one"  )
console.log( "我是一个two"  )
console.log( "我是一个three")

//console output:
我是一个one
我是一个two
我是一个three

我需要把它作为一个具有完成固定功能的函数,就要封装它 实际上可以简单封装

// 封装成 一个函数叫做 PrintToConsole
function PrintToconsole(){
    console.log( "我是一个one"  );
    console.log( "我是一个two"  );
    console.log( "我是一个three");
}
//调用函数
PrintToConsole(); 


//console output:
我是一个one
我是一个two
我是一个three

使用函数最大目的是为了复用,以及减少耦合性,方便以后修改 把上面封装好的内容存放到函数里头,就相当于存放在一个变量里头 (记得 变量 的概念,变量也相当与一个 容器)。


2. 创建函数对象

创建函数的方式:

1、普通创建: 面向对象

2、使用函数声明: 函数式

3、函数表达式: 变量式

2.1. 普通创建

语法:

var 函数名 = new Function();

实例:

// 创建一个函数对象 fun
var fun = new Function();
// 测试 其类型
console.log("fun的类型=" + typeof(fun));

// console output:
fun的类型=function

⚠️ 说明用Function创建的对象fun,类型是 function, 说明这个"变量"的类型是函数

▶Example: 使用普通创建方式,向控制台输入信息

var fun = new Function("console.log('Hello 这是我的第一个函数');");
fun();

//console output:
Hello 这是我的第一个函数

注意事项和说明:

  • 封装到函数中的代码不会立即执行,只是存放到里头
  • 要想执行,必须调用函数对象,调用函数对象语法: 函数对象名()
  • 当调用函数时,函数中被封装的代码会顺序执行调用几次,执行几次

函数因为也是对象,所以可以当作对象使用,函数对象具有所有不同对象具有的功能,但是比普通功能更强大

/*
    fun.hello就相当于这个函数对象的 属性
    但是这个样子声明函数不好,使用专门的声明函数方式
*/

var fun = new Function("console.log('HEllo 这是我的第一个函数');");

// 函数因为也是对象,所以可以当作对象使用
fun.hello = "你好";
console.log( fun.hello) ;

// console output:
你好

2.2. 使用函数声明

语法:

function 函数名 ([形参1,形参2,形参3...形参N]) {
   语句...
}

实例:

// 使用函数声明 来创建一个函数 ( 就像 一般编程语言声明函数一样)

function fun2() {

}
console.log( fun2 );
// console.log(fun2()); // undefined

控制台输出:

image.png

⚠️ 注意: 这里的fun2fun2()区别,前者是fun2函数对象,这个对象的结构是

f fun2(){
}

而 fun2() 表示函数的函数体,此时没有写内容所以是undefined

此时因为刚声明的函数 没有添加任何内容所以没有内容

下面的就是一个封装好的形式,也包含语句

function fun2() {
  console.log("这是我的第二个函数~~~");
}

控制台输出结果:

image.png

🙋‍♂️ 为什么没有返回结果呢?同样的,封装好的函数还需要调用啊!

function fun2() {
	console.log("这是我的第二个函数~~~");
}
fun2(); // 函数调用

⚠️ 注意: 函数调用需要加 ( )

image.png


2.3. 使用函数表达式

语法:

var 函数名 = function ([形参1,形参2,形参3...形参N]) {
   语句...
}

实例:

// 使用函数表达式 创建函数

// 使用函数表达式 就是写一个匿名函数,把他赋给一个函数名为某某某的变量
var fun3 = function (){
  console.log("我是匿名函数里面封装的的代码");
};

fun3();

//console output:
我是匿名函数里面封装的的代码

image.png

小结

创建函数的方式
//1、普通形式:
var fun = new Function();
//2、函数声明
function fun2() {
   
}
//3、 函数表达式
var fun3 = function(){
   
}; 

⚠️ 注意事项

var fun = new Function("console.log('HEllo 这是我的第一个函数');");
fun();
// --------------------

// 对于Function("xxx"); 其中xxx是向控制台输出的命令
// 对于这个,因为console.log()是一个函数,返回字符串,就相当于
function fun2() {
 console.log("这是我的第二个函数~~~");
}
fun2();
// 函数声明
function fun01() {
    console.log("console.log('这是用函数声明创建的函数');");
}
fun01();
//  函数表达式
var fun02 = function () {
    console.log("console.log('这是用函数表达式创建的函数')");
};
fun02();
// 函数对象
var fun = new Function("console.log('这是使用函数对象创建的函数');");
fun();

控制台结果:

console.log('这是用函数声明创建的函数');
console.log('这是用函数表达式创建的函数')
这是使用函数对象创建的函数

⚠️ 使用函数声明函数表达式的区别可以简单理解为 函数声明是 函数,而 函数表达式是将函数「赋值」给变量。


3. 函数使用

一、函数参数

🚀T-定义一个求两个数和的函数。

// 使用函数式 创建函数
function sum(a,b){
    console.log(a + b);
}

// 调用函数
sum(1,2); // 3

分析: 可以在函数的 () 中定义一个或多个形参(形式参数,没有表现出及具体的值,只是为了占据位置),形参之间用,隔开,声明形参就相当于函数体内,声明对应的变量, 但是没有赋值,具体的赋值依靠调用函数时,实际传递的实参值。

注意:

  • 在调用函数/使用函数,时可以在() 中指定实参(实际参数)。
  • 调用后,会一一对应的赋值给形参。

使用说明:

  • 调用函数解析器时不会检查实参的类型
  • 调用函数时,解析器也不会检查实参的数量

🚀T-测试调用函数解析器时不会检查实参的类型

// 定义
function sum(a, b) {
    console.log(a + b);
}

// 调用
sum(123, "hello"); // 123hello
sum(true, false); // 1

分析: 由于解析器不检查实参的类型,所以随意组合。对于第一个调用结果好理解。第二个 0 + 1 = 1 (这里进行的是算术运算)

🚀T-调用函数时,解析器也不会检查实参的数量

// 定义
function sum(a, b) {
    console.log(a + b);
}

// 调用
// 传递实参个数 少于 形参个数时, 没有对应实参的形参将是undefined
sum(123); // NaN
// 传递实参个数 多于 形参个数时, 多余的实参不会检查
sum(false, true,1); // 1

分析: 形参数量和实参对应,传递的实参有就传递,没有就没有。对于 123 + b,由于b没有传递值,所以是undefined,+运算后的结果是123 + undefiend = NaN。 注意 number + Undefined = NaN

(完)

二、函数返回值

概念: 函数的特点是输入决定输出,返回值就是需要输出的值。

原因: 需要将某个函数的执行结果作为一个中间值以待备用 或 作为其他函数的输入参数。

1、函数返回值演示

🚀T-创建一个函数 ,计算三个数的和。

function sum(a,b,c){
    alert(a+b+c);
}
sum(1,2,3); // 6

2、函数返回值的使用

可以使用return作为函数的返回值

格式:

{
    // 函数体
    return 值 ;
}

实例:

function sum(a,b,c){
    var d = a + b + c;
    return d;
}
// 调用函数
//sum(1,2,3)作为函数的返回值,赋值给result
var result = sum(1,2,3); 

分析: return后面的值会作为函数的执行结果返回值, 也就是说return 返回值的意思是先记录这个函数功能的结果, 需要使用这个值的时候再使用

注意事项和说明:

  1. return后面的语句都不执行。
  2. 如果 return后不跟任何值,相当于返回undefined
  3. 不写return 也会返回undefined
  4. return 可以返回任意类型的值,这个值将作为整个函数的返回值

三、实参类型可是任意值

1、基本类型参数

🚀T-定义一个函数,可以根据半径计算一个圆的面积,并返回返回值。

// 3.14*r*r
function area(r){
    return 3.14*r*r;
}
result = area(2);
console.log("result = " + result); // result = 12.56

2、引用类型参数

🚀T-创建一个函数,可以在控制台中输出人的信息

1)、普通方式

// 可以输出name, age ,gender ,address
function sayHello(name , age, gender , address){
    console.log("我是"+name,"今年"+age+"岁","性别"+gender,"家住在"+address);
}
sayHello("孙悟空", 18 ,"男" ,"花果山");

分析: 使用这种方式,如果参数个数比较少还好说,如果参数的个数比较多,则顺序容易乱,修改起来麻烦。

2)、使用对象作为参数

改进后

function sayHello(o){
    console.log("我是"+o.name,"今年"+o.age+"岁","性别"+o.gender,"家住在"+o.address);
}
// 创建一个对象
var obj = {
    name:"孙悟空",
    age:18,
    gender:"男",
    address:"花果山",
};
sayHello(obj); //这里把对象当作一个参数,体现参数可以是任意类型

注: 在编程中使用变量来表示值可以使得程序更加灵活。

3、延申拓展

// 定义求和函数sum
function sum(a){
   return a+a;
}
// 定义 函数 fun
function fun(a){
   console.log("a = " + a);
}
// 调用fun函数
fun(sum);

调用 fun(sum)结果:

a = function sum(a) {
    return a + a;
}

分析: 没有传递参数给sum函数,传递的就是sum函数对象,效果上就是把sum对象打印出来

function sum(a){
   return a*a;
}
function fun(a){
   console.log("a = " + a);
}
fun(sum(6));

传递参数,就会返回返回值

注意下两者区别:

  • 函数对象 : sum
  • 函数返回值 : sum()

授人以鱼和授人以渔区别

4. 立即执行函数

概念: 立即执行函数就是及时使用。认为函数对象或函数名用于标识代表此函数。而函数体才是函数真正的功能部分。函数的理解顺序: 先有函数功能,后有函数名,名者,唤而使之,名之唤,侯此待彼。能否用一次,或者不动。像这样的特点的函数,在其他编程语言中也称为 匿名函数

格式:

 ( function() {函数体} ) () ;

实例:

(function(){
    console.log("hello");
} ) ();

控制台打印结果:

hello

分析: 普通创建函数方式,①是先定义函数部分(函数名,形参列表,函数体),②后使用函数名来调用函数。而 立即执行函数将 ①和②结合起来。形式是() (),第一个()是为了将函数定义部分包裹起来 作为一个 “函数名”,第二个()是函数的调用,类比 普通方式①定义function test(){},②调用test()。注意函数名要用括号括起来,不然会报错。

Q: 为什么函数需要函数名?

A: 其实函数名并非是必须的,使用函数的目的是为了执行函数的内容部分,实现某种功能,达到某种目的。而使用函数名主要是为了方面“使用”函数,可以多次调用,在其他位置调用。由此可见“函数名”的作用起到了代替 繁重的函数体,函数本身的作用。

打印一下“ 函数名 ”就是调用函数时省略掉(),结果就是函数体。

🚀T-测试函数对象名就是函数本身。

function test() {
    console.log("我是函数体中的内容");
}

// // // 使用函数名调用函数
test();

// // // 打印输出 test()
console.log("打印test()函数: " + test() );
// // // 打印输出 test
console.log("打印test: \n" + test);

控制台输出结果:

我是函数体中的内容
我是函数体中的内容
打印test()函数: undefined
打印test: 
function test() {
    console.log("我是函数体中的内容");
}

分析: 会发现,只调用 test一次,却打印了两次,为什么?⭐⭐⭐ 现象是当使用console.log()打印函数时,实际上执行了两个过程: ①打印输出函数体内容,②返回函数返回值。由于上面 test函数没有返回值,也没有return,所以返回值为undefined。两次输出结果指的是test()console.log("打印test()函数: " + test() );

根据上述的 console.log("打印test: \n" + test);可知道函数名 test实际上是函数体(定义部分)。

总结函数的核心必须部分:

1)、函数的定义

function   ()         { }           ;
函数声明  参数列表   函数功能体   函数结束标志

2)、函数的调用

( function () {}; )       ()        ; 
      函数本身            形式      结束标志

而函数名只是为了方便调用而产生的,就像“人名”。

(完)