函数的核心内容
-
函数有哪几种定义和调用方式
-
this:函数内部的 this 指向、如何改变 this 的指向。
-
函数的严格模式
-
高阶函数:函数作为参数传递、函数作为返回值传递
-
闭包:闭包的作用
-
递归:递归的两个条件
-
深拷贝和浅拷贝的区别
函数的介绍
- 函数,就是将一些功能或语句进行封装,在需要的时候,通过调用的形式,执行这些语句
- 所有的函数,都是
Fuction
的"实例对象",函数本质上都是通过new Function
得到的 - 函数是
Fuction
的"实例对象",也就是说函数是"对象"
函数的作用
-
将大量重复的语句抽取出来,写在函数里,以后需要这些语句的时候,可以直接调用函数,避免重复劳动。
-
简化编程,让编程模块化。高内聚、低耦合。
函数的定义
function 关键字
function 函数名([形参1,形参2...形参N]){ // 备注:语法中的中括号,表示“可选”
语句...
}
函数名()
函数表达式(匿名函数)
var 变量名 = function([形参1,形参2...形参N]){
语句....
}
变量名()
使用构造函数 new Function()
- 使用构造函数
new Function()
来创建一个对象,用的少,了解即可 - 前面两种方式本质上都是调用构造函数
new Function()
来创建对象的
var 变量名/函数名 = new Function('形参1', '形参2', '函数体');
立即执行函数
- 立即执行函数,函数定义完,立即被调用,只会执行一次
- 立即执行函数其实就是匿名函数函数体直接执行
(function() {
console.log('我是立即执行函数');
})();
// 立即执行函数传参
(function (a, b) {
console.log(a+b);
})(1, 2); // 3
方式5:绑定事件函数
代码举例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="btn">我是按钮,请点击我</div>
<script>
var btn = document.getElementById('btn');
//2.绑定事件
btn.onclick = function() {
console.log('点击按钮后,要做的事情');
};
</script>
</body>
</html>
这里涉及到DOM操作和事件的知识点,后续再讲。
方式6:定时器函数
代码举例:(每间隔一秒,将 数字 加1)
let num = 1;
setInterval(function () {
num ++;
console.log(num);
}, 1000);
这里涉及到定时器的知识点。
函数的参数
形参
- 概念:形式上的参数。定义函数时传递的参数,当时并不知道是什么值。
- 定义函数时,可以在函数的
()
中来指定一个或多个形参。 - 多个形参之间使用
,
隔开,声明形参就相当于在函数内部声明了对应的变量,但是并不赋值。
实参
- 概念:实际上的参数。调用函数时传递的参数,实参将会传递给函数中对应的形参
- 在调用函数时,可以在函数的
()
中指定实参
实参的类型
- 函数的实参可以是任意的数据类型
- 调用函数时,解析器不会检查实参的类型,如求和函数中传字符串实参,运算结果是字符串,可以先进行类型转换
var obj = {
name:'zy',
age:'18'
};
/*
// 用匿名函数也可以
var sayHello = function () {
return 'hello';
};
*/
// js中函数名可以直接当参数传 php只能用匿名函数或者把函数名赋值给变量传
function sayHello() {
return 'hello';
}
function test(o, s) { // 相当于 var o,s;
console.log('我叫'+o.name+',今年'+o.age);
return s();
}
var res = test(obj, sayHello); // 我叫zy,今年18
console.log(res); // hello
实参的数量(实参和形参的个数不匹配时)
- 调用函数时,解析器也不会检查实参的数量
- 如果实参的数量多余形参的数量,多余实参不会被赋值
- 如果实参的数量少于形参的数量,多余的形参会被定义为 undefined。表达式的运行结果为 NaN
注意:在 JS 中,形参的默认值是 undefined
function sum(a, b) {
console.log(a + b);
}
sum(1, 2); // 3
sum(1, 2, 3); // 3
sum(1); // NaN
函数的返回值
使用细节
- return 的值将会作为函数的执行结果返回,可以定义一个变量,来接收该结果
- 函数在执行完 return 语句之后停止并立即退出函数,return后的语句都不会执行
- 函数必有返回值,如果不写则默认
return undefined
- 返回值可以是任意的数据类型,可以是对象,也可以是函数
- return 只能返回一个值,如果用逗号隔开多个值,则以最后一个为准
代码示例
//函数:求和
function sum(a, b) {
return a + b;
alert('hello') // 不执行
}
var res = sum(3, 4);
console.log('res=' + res)
函数名、函数体和函数加载问题(重要,请记住)
我们要记住:函数名 == 整个函数。举例:
console.log(fn) == console.log(function fn(){alert(1)});
//定义fn方法
function fn(){
alert(1)
};
我们知道,当我们在调用一个函数时,通常使用函数()
这种格式;可如果,我们是直接使用函数
这种格式,它的作用相当于整个函数。
函数的加载问题:JS加载的时候,只加载函数名,不加载函数体。所以如果想使用内部的成员变量,需要调用函数。
函数对象的方法
call()和apply()指定调用函数时的this
- 这两个方法都是函数对象的方法,需要通过函数对象来调用
- 当对函数调用call()和apply()都会调用函数执行
- 当调用call() 和apply() 可以将一个对象指定为第一个参数,此时这个对象将会成为函数执行时的this
function fun() {
alert(this);
}
fun(); // [object Window]
fun.call(); // [object Window]
fun.apply(); // [object Window]
var obj = {};
// 这种方式可以指定调用函数时的this 参数是谁this就是谁
fun.call(obj); // [object Object]
fun.apply(obj); // [object Object]
call()和apply()传参
- call() 方法可以将实参在对象之后依次传递
- apply() 方法需要将实参封装到一个数组中统一传递
function fun(a, b) {
alert(a + b);
}
var obj = {};
// call 和 apply 传参
fun.call(obj, 1, 2); // 3
fun.apply(obj, [2, 3]); // 5
arguments 的使用
使用场景
不确定参数个数时使用arguments
调用函数时的隐含参数
在调用函数时,浏览器每次都会传递进两个隐含的参数
- 函数的上下文对象 this
- 封装实参的对象 arguments, arguments是一个类数组对象(伪数组)
arguments
- arguments是一个类数组对象,调用函数时,所有实参都会在arguments中保存
- 所以即使不定义形参,也可以通过arguments来使用实参
arguments是一个伪数组,具有以下特点:
- 可以通过索引来操作数据,可以进行遍历;
- 具有数组的 length 属性,
arguments.length
来获取实参长度 - 不具有数组的 push()、pop() 等方法
arguments中有一个属性callee表示当前执行的函数对象
function fun() {
console.log(arguments.callee == fun);
}
fun(); // true
利用 arguments 求函数n个实参中的最大值
function getMaxValue() {
var max = arguments[0];
// 通过 arguments 遍历实参
for (var i = 0; i < arguments.length; i++) {
if (max < arguments[i]) {
max = arguments[i];
}
}
return max;
}
console.log(getMaxValue(1, 3, 7, 5));