文章目录
函数
在编写代码时,可能会出现非常多的相同代码,或者功能类似的代码,这些代码可能需要大量重复使用,此时就可以使用JavaScript中的函数。
函数的定义与调用
定义函数:
1、function 关键字()
function 函数名([参数]){ //[]表示可有可无,可选的含义
函数体语句
}
- function是一个关键字,全部小写
- 函数名:是一个标识符(按照标识符的命名规则),建议使用驼峰命名,做到见名知意
- 函数可以有参数也可以没有参数,可以有多个参数,若有多个参数,参数之间用逗号分隔
- "{ }"表示函数的控制范围,不能省略
- 函数体语句可以是一条也可以是多条,通常建议一个函数只完成一个功能即可
- ”高内聚,低耦合“
内聚:模块内部结合的紧密程度
耦合:模块之间结合的紧密程度
2、函数表达式
var fun=function(){}
(后面详细讲)
3、利用new Function()
var fn = new Function('参数1','参数2'..., '函数体')
- Function 里面参数都必须是字符串格式 ,参数可省略,函数体必须存在
- new Function() ,执行效率低,也不方便书写,因此较少使用
- 所有函数都是 Function的实例(对象)
- 函数也属于对象
原理:
原型对象那篇详细讲:JavaScript 原型对象、原型链、成员查找机制
调用函数
- 函数名([参数])
- 事件名 = 函数名([参数])
- …等
函数的参数与返回值
函数的参数
- 形参(形式参数):在定义函数时出现在函数首部的参数,在定义函数时形参只是一个占位符,没有确定的值。可以看做是不用声明的变量
- 实参(实在参数):函数调用时出现在函数首部的参数,是实际的值 。参数的传递方式:实参将数据传递给形参(单向传递)
- 当形参的个数比实参的个数多时,函数不会报错,多出的形参会是undefind类型
- 当实参的个数比形参的个数多时,多余的实参会被忽略
- 实参向形参传递数据是单向的,形参的改变不会影响到实参
// 函数的定义
function swap(a, b) {
console.log('形参a和b没有交换之前:' + a + ',' + b)
var t = a
a = b
b = t
console.log('形参a和b没有交换之后:' + a + ',' + b)
}
var m = 15, n = 25
console.log('调用函数之前,实参m和n的值:' + m + ',' + n)
swap(m, n)
console.log('调用函数之后,实参m和n的值:' + m + ',' + n)
函数的返回值
function 函数名() {
return 要返回的值; // 利用return返回一个值给调用者
}
- return 只能返回一个值。如果用逗号隔开多个值,以最后一个为准
- 如果有return 则返回 return 后面的值
- 如果没有return 则返回 undefined
break、continue、return区别:
- break :结束当前的循环体(如 for、while)
- continue :跳出本次循环,继续执行下次循环(如 for、while)
- return :不仅可以退出循环,还能够返回 return 语句中的值,同时还可以结束当前的函数体内的代码
函数的内置对象arguments
当不确定函数中接收到了多少个实参的时候,可以用arguments来获取实参。这是因为arguments是当前函数的一个内置对象,所有函数都内置了一个arguments对象,该对象保存了函数调用时传递的所有的实参
function fn(){
console.log(arguments) //存储所有传递来的实参 输出结果:Arguments(3)[1,2,3...]
console.log(arguments.length) //输出结果:3
console.log(arguments[1]) //输出结果:2
//按照数组方式遍历arguments
for(var i=0;i<arguments.length;i++){
console.log(arguments[i])
}
}
fn(1,2,3)
arguments只有函数才能用,且展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点:
- 具有 length 属性
- 按索引方式储存数据
- 不具有数组的 push , pop 等方法
函数练习题
计算n!
//定义函数用来计算n!
function fun(n) {
var s=1
for(var i=1;i<=n;i++){
s=s*i
}
return s
}
var t=prompt("请输入值:可计算该阶乘为")
var s=fun(t)
console.log(s)
求数组中任意个数的最大值
//利用arguments求解最大值 不需要形参
function getArrMax() {
var max = arguments[0];
for (var i = 1; i <= arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i]
}
}
return max;
}
var arr = getArrMax([5, 2, 99, 101, 67, 77]);
console.log(arr); // 输出结果:101
数组排序
//数组排序
function sort(a) {
for (var i = 0; i < a.length; i++) {
for (var j = 0; j < a.length; j++) {
if (a[j] > a[j + 1]) {
var t = a[j]
a[j] = a[j + 1]
a[j + 1] = t
}
}
}
}
var arr = [89, 66, 45, 98, 12, 6]
console.log('排序前的数组是:')
console.log(arr)
sort(arr)
console.log('排序后的数组是:')
console.log(arr)
找出100以内素数
//定义函数,功能是判断一个数是否是素数 调用该函数找到100以内的素数输出
function fun(i) {
for (var j = 2; j < i; j++) {
if (i % j == 0) {
return false
}
}
return true
}
for (var i = 2; i <= 100; i++) {
if (fun(i)) {
console.log(i + "是素数")
}
}
将字符串中的空格替换
// 请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.
// 则经过替换之后的字符串为We%20Are%20Happy
function fun(s){
var str=""
for(var i=0;i<s.length;i++){
if (s[i]==" ") {
str+="%20"
}
else{
str+=s[i]
}
}
return str
}
var s="We Are Happy"
console.log(fun(s))
函数的进阶
函数表达式(匿名函数)
将声明的函数赋给一个变量,然后由该变量完成函数的调用和参数传递
var 变量名 =function( [参数] ){
函数体
}
//获取数组最大值,并且以字符串形式输出
var getMax=function(arr){
var max=arr[0]
for(var i=0;i<arr.length;i++){
if (max<arr[i]) {
max=arr[i]
}
}
return max
}
var showArray=function(arr){
var str=""
for(var i=0;i<arr.length;i++){
str+=arr[i]+"\t"
}
console.log(str)
}
var arr=[44,55,66,77,88]
showArray(arr)
console.log("Max="+getMax(arr))
回调函数
高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出, 此时 fn 就是一个高阶函数
function fn(callback){
callback&&callback() //函数存在且执行
}
fn(function(){alert('hi')}
function fn(){
return function() {}
}
fn()
函数也是一种数据类型,同样可以作为参数,传递给另外一个参数使用。 最典型的就是作为回调函数。
同理函数也可以作为返回值传递回来
回调函数:将一个函数A作为参数传递给函数B,在函数B内对函数A进行调用,函数A就是回调函数
function fn1(a,b){
return a+b
}
function fn2(a,b){
return a*b
}
function cal(m,n,fn){
return fn(m,n)
}
var s=cal(12,16,fn1)
var x=cal(12,16,fn2)
var l=cal(12,16,function(a,b){
return a-b
})
console.log("s="+s+"\n"+"x="+x+"\n"+l)
递归函数
函数自己调用自己
递归条件:
- 问题可以分解(复杂问题可以逐步分解成简单问题)
- 分解后的新问题和原问题解法一样
- 有明确的终止条件
递归过程:
- 自上而下分解问题
- 自下而上回溯得到问题的解
递归计算输入的n!
//递归计算输入的n!
function fn(n){
if (n==1) { //结束条件
return 1
}
return n*fn(n-1) //调用
}
var n=parseInt(prompt("输入一个整数:"))
if (isNaN(n)) {
console.log("输入的值不合法")
}else{
console.log(n+"的阶乘="+fn(n))
}
递归计算1+2+3+…n
//使用递归计算1+2+3+...n
function getSum(i){
if (i==1) {
return 1
} return getSum(i-1)+i
}
console.log(getSum(100))
递归输出斐波那契数列前20项
//递归输出斐波那契数列前20项
function fib(n){
if (n==1||n==2) {
return 1
}else{
return fib(n-2)+fib(n-1)
}
}
for(var i=1;i<=20;i++){
console.log("第"+i+"项为"+fib(i))
}