1.4.2.4 函数 function
1. 函数概念
- 什么是函数?
函数就是一个方法或者一个功能体
封装: 函数就是把实现某个功能的代码放到一起进行封装(不执行)
封装: 低耦合高内聚
减少页面中的冗余代码,提高代码重复使用率
调用: 想要操作实现这个功能只需调用执行函数 (函数不能自然而然的执行,需要调用才能执行)
理解
洗衣机就是一个函数,生成洗衣机就是封装一个函数(把实现功能的代码封装进去)
生产的时候不知道用户放什么水 衣服 洗衣剂,我们需要提供出入口
提供的入口叫做形参
执行的时候放入的具体东西叫做实参
出口在函数中叫返回值,把函数处理后的结果能够返回给外面用
- 学习函数要点
-
创建函数
-
形参
-
返回值
-
-
执行函数
- 实参
-
arguments
-
函数底层运行机制
-
...
2. 函数基础语法与形参
2.1 函数基础语法
- 语法
<script>
// =================ES5 老方式============
// 创建函数
function [函数名]([形参变量 1], ...){
// 函数体 基于 JS 完成需要实现的功能
return [处理后的结果];
}
// 执行函数
[函数名]([实参 1], ...);
</script>
- 应用例
- 求两个数的和,算完和以后乘以 10,然后除以 2...
<script>
// sum 是函数名,代表这个函数
// sum()是让函数执行,代表函数执行返回的结果
// n m 是形参,是变量,用来存储执行函数时传递的实参
function sum(n, m) {
let result = n + m;
result *= 10;
result /= 2;
console.log(result);
}
console.log(sum); // sum 代表函数本身
// 10 20 25 都是传递给形参变量的值
sum(10, 20);
sum(25, 20);
</script>
2.2 形参的细节
- 创建函数的时候我们设置了形参变量 , 但如果执行的时候并没有传递对应的实参值,那形参变量默认的值是 undefined
<script>
function sum(n, m) {
console.log(n , m); // 见'控制台打印结果 图 1'
let result = n + m;
result *= 10;
result /= 2;
console.log(result); // 见图 2
}
sum();
sum(10);
sum(10,20);
sum(10,20,30);
</script>
控制台打印结果 图 1
图 2
- 形参默认值处理 : 不想要 undefined 作为默认值,如果没有给予实参值,给予一个默认值
<script>
function sum(n, m) {
// 形参默认值处理 两种方法
if(n === undefined){
// 必须要用 ===
// 如果用 == , null == undefined 为 true
n = 0 ;
}
if(typeof m === 'undefined'){
// 也可以用 ==
m = 0 ;
}
console.log(n , m);
let result = n + m;
result *= 10;
result /= 2;
console.log(result);
}
sum();
sum(10);
sum(10,20);
sum(10,20,30);
</script>
3. 函数的返回值
背景介绍
<script>
function sum(n, m) {
let result = n + m;
console.log(result); // => 30
}
sum(10,20);
console.log(result); // 报错 引用错误 见图 3
</script>
图 3
函数执行的时候,函数体内部创建的变量我们在外部无法获取和操作的(闭包 作用域)(所以报错)
- 如果想要获取内部的信息,我们需要基于 return 返回值机制,把信息返回才能拿到
<script>
function sum(n, m) {
let result = n + m;
// 2.return 一定是值,此处把 result 变量存储的值返回给外面
return result // => return 30
}
sum(10,20);
let AA = sum(10,20);
console.log(AA);// => 30
console.log(result); // 报错 引用错误,见图 3
</script>
</body>
-
return 的一定是值: 此处是把 result 变量存储的值返回给外面 不是变量(代码见上)
函数名() 代表函数返回的结果,用来接 return 的东西
retunr 与 函数名() 搭配使用
对比 形参用来接实参,参与计算处理
return 用来把函数执行结果给外面
-
没有写 return,函数默认返回值的 undefined(代码见下)写了return没有给值,返回undefined
<script>
function sum(n, m) {
let result = n + m;
}
let AA = sum(10,20);
console.log(AA); // => undefined
</script>
注意:
1.console.log是函数
2.console.log(1) 是函数执行
3.undefined 是因为函数没有 return
4.1能打印出来是因为函数的功能
- 不需要返回值,但是仍旧写了 return,因为函数体中遇到 return,后面代码则不再执行了(代码见下)
<script>
function sum(n, m) {
//函数体中遇到 return,后面代码则不再执行了
if(n === undefined || m === undefined){
return
}
let result = n + m;
}
sum(10,20);
</script>
复习:
一个知识点,另一个知识点,几句话将两个知识点关联起来且不牵强
continue break return
4. 匿名函数
ES5 规范里的函数 : 匿名函数
-
什么是匿名函数 ? 没有函数名的函数
-
两种写法
- 匿名函数之函数表达式,把一个匿名函数本身作为值赋值给其他东西
这种函数一般不是手动触发执行(函数名()),而是靠其他程序驱动触发执行(例如 : 触发其他事件的时候 把它执行)
<script>
document.body.onclick = function(){}
setTimeout(function(){},1000);
let fun = function(){};
</script>
- 匿名函数之自执行函数 : 创建完一个匿名函数,紧接着就把当前函数加小括号执行
(function(n){
// n => 100
})(100);
5.首次了解函数的底层运行机制
执行下列代码
// 创建函数
function fn(n,m) {
var res =null ;
res = n + m;
return res;
}
// 执行函数
var AA = fn(10,20);
console.log(AA);
-
创建函数,开辟的
堆内存中存储的是函数题中的代码,但是是按照字符串的格式存储的.仅此而已.-
函数名代表函数
-
函数名() 代表函数返回值 return右侧的内容
- 类与实例 返回值return有不同情况
-
-
执行函数,先执行函数,再把返回值和变量(AA = fn())相关联.
函数的返回值只看return 后面时啥就返回啥,没有就是UNDEFINDE.
-
每次执行函数的目的,都是把函数体中的代码(先从字符串变为代码)执行
形成一个
全新的私有栈内存(私有上下文) -
执行时,在私有栈内存中进行变量存储和值存储,并关联,然后运算.
-
res只能在上述私有栈内存中使用,如果想要在外界拿到,需要return返回给外面.
-
每次执行函数都会开辟一个私有栈内存(每次执行都另开一个),容易造成栈溢出,由此引出执行销毁的问题.JS的编译过程VO AO ...
... 未完待续
6. 函数中的ARGUMENTS (任意数求和应用)
思考: 任意数求和如何实现 ? (执行函数的时候 , 传递 N 个值求和)
任意数求和:
1. 传递实参的个数不定
2. 传递的值是否为有效数字不定
要求: 把传递的有效数字进行相加求和
问题: 无法确定要传多少个行参接实参, 进而也无法进行挨个相加求和
6.1 arguments 是函数内置的实参集合
1. 类数组集合,集合中存储着所有函数执行时,传递的实参信息
2. 内置: 无论是否设置行参,argumwnts仍存在
3. 内置: 无论是否传递实参,argumwnts仍存在,只不过是一个空的类数组
- 空表现为argumwnts的length属性值为0
4. arguments.callee : arguments的 callee属性, 存储的是当前函数本身
- 一般不使用,JS严格模式下禁止使用这个属性
6.2 任意数求和
- 使用for循环
未处理非有效数字
function sum() {
let total = null;
for (let i = 0; i < arguments.length; i++) {
let item = arguments[i];
total += item ;
}
return total
}
let total = sum(10,20,30,40) // => 100
total = sum(10,20) // => 30
total = sum(10,20,'30') // => '3030'
total = sum(10,'AA') // => '10AA'
function sum() {
let total = null;
for (let i = 0; i < arguments.length; i++) {
// 获取的每一项结果都先转换为数字(数学运算)
let item = Number(arguments[i]);
// 非有效数字不加
if(isNaN(item)){
continue;
}
total += item ;
}
return total
}
let total = sum(10,20,30,40) // => 100
total = sum(10,20) // => 30
total = sum(10,20,'30') // => 60
total = sum(10,'AA') // => 10
7. 箭头函数 ARROW FUNCTION (ES6+)
(this部分会详细补充)
7.1 箭头函数改写
-
语法:
let 函数名 = ( 形参 ) => { 函数体 } ;
如果函数体中只有一行 return的代码 , 可以省略return以及大括号 .
let 函数名 = ( 形参 ) => 函数体 ;
多行不可以 .
<script>
function sum(n,m){
return n + m;
}
// 改成箭头函数
let sum = (n,m) => {
return n + m;
}
let sum1 = (n,m) => n + m;
</script>
- 箭头函数在高阶函数的应用(柯里化函数)
function fn(n) {
return function (m) {
return n + m;
}
}
// 改写
let fn = n => m => n + m;
第一步 改写最外侧的函数fn拿到箭头
第二步 改写小函数变为箭头
第三步 简化最里面的return 一行
第四步 简化剩余的return 一行
7.2 箭头函数的优点
-
写法简化
-
形参赋值默认值
当没有给形参传递实参的时候,执行默认值
这种写法也可以在非箭头函数中使用 ,但是更常用于ES6箭头函数中
function sum(n, m) { if (typeof n === 'undefined') { n = 0 } return n + m; } // 改写成箭头函数 let sum = (n = 0, m = 0) => n + m; -
箭头函数没有ARGUMENTS
-
箭头函数中的THIS也稍有不同
7.3 箭头函数没有ARGUMENTS
let sum = () =>{
console.log(arguments); // => arguments is not defined
}
sum(1,2,3,4)
使用扩展运算符... 来获取预算福获取到传递的实参集合
- 该实参集合数据类型是数组
其中arg是自定义参数,可以随意写
let sum = (...arg) =>{
console.log(arg); // => [1,2,3,4]
}
sum(1,2,3,4)
想要实现任意数求和功能
let sum = (...arg) =>{
return eval(arg.join('+'))
}
sum(1,2,3,4)
====================
另外一种写法
let sum = (...arg) => eval(arg.join('+'))
sum(1,2,3,4)
eval()的参数是一个字符串。如果字符串表示的是表达式,eval()会对表达式进行求值。如果参数表示一个或多个 JavaScript 语句,那么eval()就会执行这些语句。
7.4 箭头函数中的THIS与普通函数也不同
...待补充