JavaScript函数(定义、调用、参数、返回值等)、进阶(匿名、回调、递归函数)、作用域、闭包函数及预解析

文章目录

  • 函数
    • 定义函数
    • 调用函数
    • 函数的参数
    • 函数的返回值
    • 函数的内置对象arguments
    • 函数练习题
      • 计算n!
      • 求数组中的最大值
      • 数组排序
      • 找出100以内素数
      • 将字符串中的空格替换
  • 函数的进阶
    • 函数表达式(匿名函数)
    • 回调函数
    • 递归函数
      • 递归计算输入的n!
      • 递归计算1+2+3+...n
      • 递归输出斐波那契数列前20项
  • 作用域
    • 变量的作用域
    • 作用域链
  • 闭包函数
  • 预解析

函数

在编写代码时,可能会出现非常多的相同代码,或者功能类似的代码,这些代码可能需要大量重复使用,此时就可以使用JavaScript中的函数

定义函数

function 函数名([参数]{
      //[]表示可有可无,可选的含义   
	函数体语句
}
  • function是一个关键字,全部小写
  • 函数名:是一个标识符(按照标识符的命名规则),建议使用驼峰命名,做到见名知意
  • 函数可以有参数也可以没有参数,可以有多个参数,若有多个参数,参数之间用逗号分隔
  • "{ }"表示函数的控制范围,不能省略
  • 函数体语句可以是一条也可以是多条,通常建议一个函数只完成一个功能即可
  • ”高内聚,低耦合“

内聚:模块内部结合的紧密程度
耦合:模块之间结合的紧密程度

调用函数

  • 函数名([参数])
  • 事件名 = 函数名([参数])

函数的参数

  • 形参(形式参数):在定义函数时出现在函数首部的参数,在定义函数时形参只是一个占位符,没有确定的值
  • 实参(实在参数):函数调用时出现在函数首部的参数,是实际的值 参数的传递方式:实参将数据传递给形参(单向传递)
  • 当形参的个数比实参的个数多时,函数不会报错,多出的形参会是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返回一个值给调用者
}

函数的内置对象arguments

当不确定函数中接收到了多少个实参的时候,可以用arguments来获取实参。这是因为arguments是当前函数的一个内置对象,所有函数都内置了一个arguments对象,该对象保存了函数调用时传递的所有的实参

function fn(){
     
    console.log(arguments)
    console.log(arguments.length)
    console.log(arguments[1])
}
fn(1,2,3)

函数练习题

计算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)

求数组中的最大值

function getArrMax(arr) {
     
  var max = arr[0];
  for (var i = 1; i <= arr.length; i++) {
     
    if (arr[i] > max) {
        max = arr[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))

回调函数

将一个函数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))
}

作用域

变量的作用域

  • 全局变量:在函数外部定义的变量(显示定义)或在内部不用var定义的变量(隐式定义) 在浏览器页面关闭后才销毁,比较占空间
  • 局部变量:在函数内部利用var关键字定义的变量 函数调用结束后就销毁,节省内存资源
  • 块级变量:ES6中使用let关键字在语句块中定义的变量 当语句块结束就销毁,更节省内存空间

作用域链

在一个函数内部声明另一个函数时,内层函数只能在外层函数作用域内执行,在内层函数执行过程中,若引入某个变量,先在当前作用域中寻找,若未找到,则继续向上一层级作用域中寻找,直到全局作用域

采取就近原则的方式来查找变量最终的值。

闭包函数

有权访问另一函数作用域内变量(局部变量)的函数

function fn() {
     
    var times=0
    var c=function(){
     
        return ++times
    }
    return c
}
//js中对闭包的语法规范
//在函数外部访问函数内部的变量
var count=fn()
//js解析器使得times不再初始化,给它一个空间存储
console.log(fn)
console.log(fn())
console.log(count())
console.log(count())
console.log(count())

JavaScript函数(定义、调用、参数、返回值等)、进阶(匿名、回调、递归函数)、作用域、闭包函数及预解析_第1张图片

两点用途

  • 在函数外部读取函数内部的变量
  • 让变量的值始终保持在内存中

注意:由于闭包会使得函数中变量一直被保存在内存中,内存消耗很大,所以闭包的滥用可能会降低程序的处理速度,造成内存损耗等问题

预解析

JavaScript解析器在运行JavaScript代码的时候会进行预解析,也就是提前对代码中的var变量声明和function函数声明进行解析,然后再去执行其他的代码。

你可能感兴趣的:(JavaScript,javascript,js,函数闭包,递归法)