JS 入门之函数


JS 入门章节目录


第六章:函数

文章の目录

函数

函数的定义

为何使用函数?

函数的声明

函数的调用

带参数的函数

形参和实参

实参变量的传递

带返回值的函数

用作变量值的函数

变量的作用域

局部变量

全局变量

声明提升

递归函数

什么是递归函数

利用递归实现 n 的阶乘

匿名函数和立即执行函数

匿名函数

立即执行函数

Arguments 对象

描述

遍历参数求和

函数的注释

使用 JSDoc

闭包


正文

JavaScript 函数是被设计为执行特定任务的代码块。

JavaScript 函数会在某代码调用它时被执行。

函数

函数的定义

函数(function),也可以被称之为方法(method)。

是一段预定义好,并且可以被反复使用的代码块,其中可以包含多条可执行语句。

注:

  • 预定义好:事先声明好,但不被执行
  • 反复使用:允许被多个地方(元素,函数中)所应用
  • 代码块:允许包含多条可执行的代码

函数本质上是功能完整的对象。

为何使用函数?

能够对代码进行复用:只要定义一次代码,就可以多次使用它。

能够多次向同一函数传递不同的参数,以产生不同的结果。

函数的声明

JavaScript 函数通过 function 关键词进行定义,其后是函数名和括号。

函数名可包含字母、数字、下划线和美元符号(规则与变量名相同)。

语法:

function 函数名(){
    // 可执行语句;
}

// 也可以通过函数表达式来创建函数
var 函数名 = function(){
    // 可执行语句;
};

函数的调用

任何 JS 的合法位置处,都允许调用函数。

函数中的代码将在其他代码调用该函数时执行:

  • 当事件发生时
  • 当 JavaScript 代码调用时
  • 自动的(自调用)

语法:

函数名();

注:

  • 访问没有 () 的函数将返回函数定义。

带参数的函数

语法:

function 函数名(参数列表声明){
    // 代码块(函数体,功能体,方法体)
}

// 参数列表:由逗号分隔的参数,由一个或多个变量名称组成

形参和实参

声明函数时定义的参数,可以称之为“形参”(形式参数)。

调用函数时实际传递的参数值,被称之为“实参”(实际参数)。

// 实参和形参需要一一对应

function sum(num1,num2){
    console.log(num1);
    console.log(num2);
    console.log(num1+num2);
};

sum(5,6);

// 特殊情况:
// 实参可以传入任意数据类型

sum(5,true);    // 6 (做 + 运算时,true 会被默认当作 1 参加运算)
sum(5,"li");    // "5li" (字符串拼接)

// 实参个数多于形参个数

sum(5,6,7,8);    // 11 (多余的参数不参与函数的执行)

// 形参个数多于实参个数
sum(5);    // NaN (num1 = 5,num2 没有赋值,为 undefined。所以结果为:NaN)(5 + undefined 的结果为 NaN)

实参变量的传递

传参时,实际上是将实参复制了一份副本传给了函数。

  • 当实参为基本数据类型时:将实参变量保存的复制了一份副本传递给形参,在函数体内对变量进行修改,实际上是不会影响到外部的实参变量的。
  • 当实参为引用数据类型时:将实参变量保存的引用类型的地址复制了一份副本传递给形参,它们本质上指向同一块堆内存中存储的变量,所以对变量进行修改时,会影响到实参变量的。

(如需了解基本数据类型和引用数据类型的变量在内存中的存储方式,请阅读笔者另一篇文章:JavaScript 中变量在内存中的存储方式

var n = 100;    // 全局变量 n
function fun(n){    // 参数变量(形参)也是局部变量
    n-=3;    // 修改的是局部变量 n
    console.log(n);    // 输出的是局部变量 n
}
fun(n);    // 按值传递,方法内输出 97
console.log(n);    // 输出全局变量的值:100

// 

var arr1 = [2,6,4,8,1,9,5,3,7];

function bubbleSort(arr){
    for(var i = 0;i < arr.length-1;i++){
        for(var j = 0;j < arr.length-1-i;j++){
            if(arr[j] > arr[j+1]){
                var temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
    console.log(arr);
}

bubbleSort(arr1);    // [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(arr1);    // [1, 2, 3, 4, 5, 6, 7, 8, 9]

// 传参时,将全局变量 arr1 的地址赋给了 arr (实参,局部变量),所以函数内的 arr 和 全局变量 arr1 指向同一块堆内存中的数据,所以函数内对数组进行冒泡排序,也会改变全局变量 arr1 的值。

带返回值的函数

如需返回一个返回值给调用者,请使用 return 关键词。

声明:

function 函数名( 0 或多个参数){
    // 代码块;
    return 值;
}

注:

  • 当 JavaScript 到达 return 语句,函数将停止执行(return; 语句没有返回值(undefined),但是会立即停止执行函数)。

用作变量值的函数

函数的使用方法与变量一致,在所有类型的公式,赋值和计算中。

// 使用变量来存储函数的值:
var num = sum(1,2,3);

// 把函数当做变量值直接使用:
console.log("和 = " + sum(1,2,3));

变量的作用域

作用域就是变量或函数的可访问范围。它控制着变量或函数的可见性和生命周期。

在 JS 中,变量或函数的作用域可分为:

  • 函数作用域 —— 只在当前函数内可访问
  • 全局作用域 —— 一经定义,代码的任何位置都可以访问

局部变量

在 JavaScript 函数中声明的变量,会成为函数的局部变量(拥有函数作用域)。

函数作用域中的变量(局部变量)只在当前函数内可访问到,离开此范围就无法访问了。

局部变量在函数开始时创建,在函数完成时被删除。

全局变量

全局(在函数之外)声明的变量,会成为全局变量(拥有全局作用域)。

全局作用域中的变量,称之为“全局变量”,在代码的任何位置都能访问。

声明提升

JS 在正式执行之前,会将所有 var 声明的变量和 function 声明的函数,预读到所在作用域的顶部。

但是,对变量的赋值,还保留在原来的位置处。

console.log(a);//不会出错,输出undefined
var a = 100;
console.log(a);//100

//等同于

var a;//仅声明提前
console.log(a);//undefined
a=100;//赋值仍保留在原位置
console.log(a);//100

递归函数

什么是递归函数

如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。

简单理解:函数内部自己调用自己。

注:

  • 递归函数的作用和循环效果类似。能用循环解决的问题,尽量不用递归。
  • 递归很容易发生“栈溢出”(stack overflow)错误,所以必须要有退出条件 return。

利用递归实现 n 的阶乘

// n! = n * (n-1)!

function factorial(n){
    if(n == 1){
        return 1;
    }else{
        return n * factorial(n-1);
    }
}

factorial(5);

匿名函数和立即执行函数

匿名函数

没有函数名的函数。

匿名函数不能单独定义与使用。

匿名函数的应用场景:

  • 用于函数表达式
  • 作为返回值
  • 用于定义对象方法
  • 作为回调函数
  • 用于立即执行函数
  • 用于DOM元素注册事件
  • 其他 ...

立即执行函数

立即执行函数是一种在定义后就会立即执行的函数,其实质是一种语法。

立即执行函数的形式:

  • 常用形式一:将匿名函数包裹在一个括号运算符中,后面再跟一个括号。
  • 常用形式二:匿名函数后面跟一个括号,再将整个包裹在一个括号运算符中。
  • 其他形式:可以用 !、+、-、~ 运算符替代常用形式一中的第一个括号。

立即执行函数的作用:

立即执行函数最本质的作用是:创建一个独立的作用域。利用这一功能,可以:

  • 初始化数据和页面(只执行一次)
  • 模块化开发中,定义私有变量,防止污染全局(独立作用域)
  • 解决闭包中的状态保存问题(常见的一个函数内部返回多个函数,调用这些函数,打印父函数内部变量的问题)

Arguments 对象

描述

arguments 是一个对应于传递给函数的参数的类数组对象。

如果调用的参数多于正式声明接受的参数,则可以使用 arguments 对象。这种技术对于可以传递可变数量的参数的函数很有用。使用 arguments.length 来确定传递给函数参数的个数,然后使用 arguments 对象来处理每个参数。

arguments 对象是所有(非箭头)函数中都可用的局部变量(arguments 对象只能在函数内使用)。你可以使用 arguments 对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引 0 处。

注:

  • “类数组”(不是一个 Array 但类似于 Array)意味着 arguments 有长度(length)属性,并且属性的索引是从零开始的,但是它没有 Array 的内置方法。
  • typeof arguments 返回 'object'。

遍历参数求和

// 求 n 个数相加的和

function add(){
    var sum = 0;
    for(var i=0; i<arguments.length; i++){
        sum += arguments[i];
    }
    return sum;
}

函数的注释

使用 JSDoc

(如需了解有关 JSDoc 更多内容,请阅读笔者另一篇文章:JSDoc

/**
 * @author li
 * @version 1.01.1
 * @description 求两数之和
 * @param {Number} num1 操作数1
 * @param {Number} num2 操作数2
 * @return {Number} num1 和 num2 的和
 * @example add(5,6)
 */

function add(num1,num2){
	var sum = num1 + num2;
	return sum;
}

闭包

(如需了解闭包相关内容,请阅读笔者另一篇文章:闭包

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值