JavaScript Function
前言
Js
中的函数其实相较于其他语言是比较复杂的,光函数类型就分了好几种,其中this
指向更是让很多初学者摸不到头脑。
那么本篇文章将着重介绍一下函数的基本使用,关于this
指向的详解将放在下一章。
函数的作用其实就是将一段可重复利用的代码进行整合,方便多次使用。
一定要注意,先声明定义函数而后再进行使用。这是一种规范。
函数定义
实例定义
在Js
中函数是Fuction
类的实例对象,因此我们可以用实例化的方式来定义函数,这也能充分理解函数也是对象这一概念。
<script> "use strict"; // 参数1:形参,参数2:函数代码体 let func = new Function("title","console.log(title)"); func("云崖先生的博客"); </script>
标准定义
使用Function
类的方式定义函数太过麻烦,因此推荐使用function
标准语法进行定义。
<script> "use strict"; function func(title){ console.log(title); } func("云崖先生的博客"); </script>
对象字面量
我们可以在一个对象中定义函数,这通常会被称之为对象方法。
<script>"use strict"; let obj = { description:"这是一个对象属性", show:function(title){ console.log("这是一个对象方法,传入的参数是:",title); }, } obj.show("云崖"); </script>
匿名函数
全局声明的标准定义函数会被存入window
对象中,这样做会产生很多弊端。
因为我们的函数名如果不恰当的话可能造成window
方法缺失。
<script>"use strict"; function func(title){ console.log(title); } func("云崖先生的博客"); console.log(window.func); // 有的 </script>
因此,可以通过赋值来进行匿名函数的定义,定义前使用let/const
进行声明,这样就不会压入至window
对象中,注意后面要以;
结束。 注意:以var
声明的匿名函数会压入至window
对象中
<script>"use strict"; let func = function (title) { console.log(title); }; func("云崖先生的博客"); console.log(window.func); // undefined </script>
函数执行
函数提升
标准定义的函数会进行函数提升,可以先使用后定义,这是不符合规范的。
但是匿名函数不会进行函数提升。
函数的提升是排在var
变量提升之前的,因此如果函数名与用var
定义的变量重复那么该名字会被变量拿到,函数则会被当做垃圾回收。
即使使用了
var
来定义匿名函数,也不会进行函数提升, 但是会将该函数压入window
对象中,所以建议使用let/const
来对匿名函数进行接收。
标准声明函数会进行提升
<script>"use strict"; func("云崖先生的博客"); // 执行了 function func (title) { console.log(title); } console.log(window.func); // 有的 </script>
匿名函数不会进行提升
<script>"use strict"; func("云崖先生的博客"); // Uncaught ReferenceError: Cannot access 'func' before initialization let func = function (title) { console.log(title); } console.log(window.func); </script>
自执行函数
在很早之前,如果你写了一个Js
模块,为了防止全局作用域的污染,你会将代码放入一个自执行函数里面。
但是现在不用了,因为let/const
具有块作用域,它们的出现决定我们今后写的模块不用再拿自执行函数来进行封装了。
首先来看一下自执行函数怎么使用。
<script>"use strict"; (function (title) { console.log(title); // 自己执行 })("云崖先生的博客"); // 这里调用 </script>
自执行函数封装
(function () { function show() { console.log("执行了show功能"); } function test() { console.log("执行了test功能"); } window.module = { show, test }; })();
let
作用域封装
{ let show = function () { console.log("执行了show功能"); } let test = function () { console.log("执行了test功能"); } window.module = { show, test }; };
调用
<script src="JavaScript.js"></script> <script>// 注意上面要引入模块 "use strict"; module.show(); module.test(); </script>
参数相关
形参实参
形参是在函数声明时设置的参数,实参指在调用函数时传递的值,注意,传参时必须一一对应!
形参数量大于实参时,没有传参的形参值为
undefined
实参数量大于形参时,多于的实参将忽略并不会报错
使用
函数名.length
可获取需要传递形参的数量
<script>"use strict"; function test(f1, f2, f3) { console.log(f1); // 第一个 console.log(f2); // 第二个 console.log(f3); // undefined } test("第一个","第二个"); </script>
默认形参
默认形参要放在最后,当没有实参传递时采用默认形参的值,当有实参传递时采用实参传递的值。
<script>"use strict"; function test(f1, f2, f3) { f3 = f3 || "默认形参"; // 老版设置默认形参的方式 console.log(f1); // 第一个 console.log(f2); // 第二个 console.log(f3); // 默认形参 } test("第一个","第二个"); </script>
<script>"use strict"; // 新版设置默认形参的方式 function test(f1, f2, f3="默认形参") { console.log(f1); // 第一个 console.log(f2); // 第二个 console.log(f3); // 默认形参 } test("第一个","第二个"); </script>
函数参数
函数本身也可当做一个参数传递给另一个函数。
<script>"use strict"; function f1(func) { console.log("f1..."); console.log("参数:",func); func("给f2传递的参数"); // 执行f2 } function f2(y) { console.log("f2"); console.log("参数:",y); } f1(f2); </script>
arguments
当某个函数要接收无限多的参数时,可不指定形参,使用arguments
来进行接收(必须是这个名字)。
注意:
arguments
是Arguments
对象,并不是一个数组。但是我们可以将它转换为数组再进行操作
<script>"use strict"; function show() { console.log(arguments ); // Arguments(6) [1, 2, 3, 4, 5, 6, callee: (...), Symbol(Symbol.iterator): ƒ] } show(1,2,3,4,5,6); </script>
...语法
当形参要接收无限多的参数时,可在形参名前加入...
,使用进行接收。该形参会作为一个Array
对象接收无限多的参数。
这个是更推荐使用的方式
<script>"use strict"; function show(...args) { console.log(args ); // (6) [1, 2, 3, 4, 5, 6] } show(1,2,3,4,5,6); </script>
当实参是一个数组或者类数组的数据类型时,可以使用...
语法来为形参一一对应传参。但是要注意,严格模式下不允许这样做。
<script>// "use strict"; 严格模式下不能这么做 function show(f1,f2,f3,f4,f5,f5) { console.log(f1); // 1 console.log(f2); // 2 console.log(f3); // 3 console.log(f4); // 4 console.log(f5); // 5 } show(...[1,2,3,4,5,6]); </script>
箭头函数
箭头函数是函数声明的简写形式,在使用递归调用、构造函数、事件处理器时不建议使用箭头函数。
无参数时使用空扩号即可,代码块过于简短可省略花括号。
函数体为单一表达式时不需要
return
返回处理,系统会自动返回表达式计算结果。多参数传递与普通声明函数一样使用逗号分隔
只有一个参数时可以省略参数括号。
无参数时使用空扩号即可,代码块过于简短可省略花括号。
<script>"use strict"; let show = () => console.log("执行了"); show(); </script>
函数体为单一表达式时不需要 return
返回处理,系统会自动返回表达式计算结果。
<script>"use strict"; let show = () => "你真帅"; const res = show(); console.log(res); // 你真帅 </script>
多参数传递与普通声明函数一样使用逗号分隔
<script>"use strict"; let show = (f1, f2, f3) => { console.log(f1); console.log(f2); console.log(f3); }; // 注意加分号 show("第一", "第二", "第三") </script>
只有一个参数时可以省略参数括号。
<script>"use strict"; let show = f1 => console.log(f1); show("第一") // 第一 </script>
递归调用
递归指函数内部调用自身的方式。
主要用于数量不确定的循环操作
要有退出时机否则会陷入死循环
以下示例将展示使用递归进行累加操作。
<script>"use strict"; function show(num) { if (!num) { return 0; } return num + show(num - 1); } let res = show(100); console.log(res); // 5050 </script>
以下示例将展示使用递归打印倒三角。
<script>"use strict"; function show(num) { if (!num) { return ; } console.log("*".repeat(num)); show(num - 1); } show(5); </script>
回调函数
回调函数是指在某一特定情况下会被其他函数所调用的函数,比如处理鼠标事件,键盘事件的函数都是回调函数。
<script>"use strict"; // 回调函数 document.querySelector("div").addEventListener("click",(event)=> console.log(event.target)); // 由于this指向不同,所以我们使用event.target进行打印 </script>
标签函数
当使用模板字面量对字符串进行格式化时,可指定一个标签函数。第一个参数是字符串值的数组,其余的参数为标签变量。
注意!标签函数会自动执行!
<script>"use strict"; function show(str, ...args) { console.log(str); // (3) ["姓名是:", "↵年龄是:", "", raw: Array(3)] console.log(args); // (2) ["云崖", 18] } let username = "云崖"; let age = 18; let str = show`姓名是:${username}\n年龄是:${age}`; </script>