一文秒懂JavaScript函数,手册级详细解读

1 定义

1.1 MDN解释

一般来说,一个函数是可以通过外部代码调用的一个“子程序”(或在递归的情况下由内部函数调用)。像程序本身一样,一个函数由称为函数体的一系列语句组成。值可以传递给一个函数,函数将返回一个值。
风安的理解就是一个工具,可以将代码块包裹在里面,并且对里面的代码进行一遍加工,再进行输出。

1.2 作用

1)函数可以减少代码量,消除冗余的代码
2)对代码进行模块化“加工”
3)封装代码,可以使函数内部的代码对外不可见

2 组成

  • 函数名
  • 函数体
  • 参数
  • 返回值

3 定义函数

  • function字面量方式
function 函数名(参数) {

}
  • 表达式方式
var 函数名 = function (参数) {

};
  • Function构造函数方式
var 函数名 = new Function ('参数', '函数体') ;

4 调用函数

函数名加()就可以调用函数,并执行函数内的语句。

5 函数的返回值

  • 函数名() 为函数调用表达式,表达式的值就是函数的返回值
  • 函数内return 可以返回函数的返回值,可以是表达式、变量、直接量
  • 函数体内没有return,则返回默认为undefied

6 函数的参数

6.1 形参和实参

形参:声明函数的时候,给的参数, 类似于变量名;在声明函数的时候,参数是没有值。
实参:调用函数是给的参数; 实参会按照顺序赋值给形参。

6.2 形参和实参的数量问题

  • 一般来书形参数量和实参数量应该相等
  • 如果实参大于形参数量,会忽略多出来的参数
  • 如果实参小于形参数量,形参取值时为undefined

6.3 形参的默认值

function demo(a, b=默认值) {

}

有默认值的形参一定要放后面!

6.4 arguments

  • arguments 只能在函数中使用
  • arguments 是一个类数组对象,并有数组的特性
  • arguments 能获取所有实参
    因此,可以定义可变参数数量的函数:如计算所有参数和、取参数中的最大值、求所有参数的平均数
// 求参数的和
        function fn() {
            let sum = 0;
            for (let i = 0; i < arguments.length; i++) {
                sum += arguments[i];
            }
            return sum;
        }
        let sum = fn(12, 13, 14, 23, 35, 16);
        console.log(sum);

        // 求参数的成积
        function product() {
            let res = 1;
            for (let i = 0; i < arguments.length; i++) {
                res *= arguments[i];
            }
            return res;
        }
        let result = product(12, 13, 14, 23, 35, 16);
        console.log(result);

        // 求参数的平均数
        function average() {
            let add = 0;
            let averNum = 0;
            for (let i = 0; i < arguments.length; i++) {
                add += arguments[i];
                averNum = parseInt(add / arguments.length);
            }
            return averNum;
        }
        let result1 = average(12, 13, 14, 23, 35, 16);
        console.log(result1);


        function average1() { // 调用上面的求和结果
            return sum / arguments.length;
        }
        let result2 = average1(12, 13, 14, 23, 35, 16);
        console.log(result2);

        // 求参数的最大、最小值
        function num() {
            let a = arguments[0]; //假设最大值a我arguments的第一个
            let b = arguments[0];
            for (let i = 0; i < arguments.length; i++) {
                if (a < arguments[i]) {
                    a = arguments[i];
                }
            }
            return a;
        }
        let max = num(12, 13, 14, 23, 35, 16);
        console.log(max);

7 函数的嵌套

  • 冒泡排序 arrSolt函数中嵌套一个exchange函数
// 冒泡排序  将数组从小到大排列
        function arrSolt(arr) {
            // 遍历数组
            for (var i = 0; i < arr.length; i++) {
                // 开始比较大小  将最大的元素放到最后
                for (var j = 0; j < arr.length - 1 - i; j++) {
                    // 如果前面的元素比后面的小,就交换位置
                    if (arr[j + 1] < arr[j]) {
                        exchange();
                    }

                }
            }
            return arr;

            // 交换函数 设置第三个变量用于交换时存放
            function exchange() {
                let temp = arr[j + 1];
                arr[j + 1] = arr[j];
                arr[j] = temp;
            }
        }
        console.log(arrSolt(arr = [1, 13, 0, 999, 38, 620, 43, 186, 80, 29, 290]));

8 作用域

8.1 变量的作用域

作用域是变量的可作用范围,变量只有在自己的作用域下才会生效。

8.2 作用域分类

局部作用域:函数内部定义的变量和形参的作用域就是局本部作用域,这样的变量为局部变量。
全局作用域:在函数外面定义的变量的作用域是全局作用域,这样的变量为全局变量。
块级作用域:在代码块中定义的变量的作用域为块级作用域,这样的变量为块级变量,ES6及以上才支持

8.3 作用域链

8.3.1 定义
  • 函数的层层嵌套就形成了作用域链
  • 作用域链是程序执行过程中寻找变量的过程
8.3.2 通过作用域链查找变量的过程
  • 先在当前作用域查找,如果找不到就去上级作用域查找,直到找到全局作用域中去
  • 往上寻找的过程中,找到了就会停止查找,并使用该变量
  • 寻找的过程中没有找到,就会报错提示**is not defined

变量的作用域只与函数声明的位置有关,与函数调用的位置无关!

8.4 作用域面试题

var num=10;
        function fun(){
            var num=20;
            fun2();
        }
        function fun2(){
            console.log(num);  // 10
        }
        fun();

9 变量提升和函数提升

9.1 变量提升

  • JS会将变量的声明提升到本作用域的最前面。

9.2 函数提升

  • JS会把函数连声明带值提升到本作用域的最前面,函数可以在函数声明之前调用。
  • 只有字面量方式(function关键字方式)声明的函数才能进行函数提升,表达式方式和构造函数方式声明的函数只能提升声明没有值,这一点和变量提升相同。
  • 函数提升的权重比变量提升高(前提是变量和函数名相同的情况)。

9.3 预解析

程序在代码执行前会先进行预解析

  • 预解析先解析函数声明定义的函数,整体会被提升
  • 再解析带var 声明的变量
  • 函数重名会覆盖,变量重名会忽略
  • 变量若不带var关键字,该变量是不会进行预解析的
  • 表达式和构造函数方式定义的函数也是当作变量进行解析

9.4 变量提升面试题

//  题一
alert(a);    
a = 0;
// a is not defined

//  题二
alert(a);
var a = '我是变量';
function a() { alert('我是函数') }
alert(a);
// undefined
// 0

// 题三
alert(a);
var a = '我是变量';
function a() { alert('我是函数') }
alert(a);
// function a() { alert('我是函数') }
// 我是变量

// 题四
alert(a);
a++;
alert(a);
var a = '我是变量';
function a() { alert('我是函数') }
alert(a)
// function a() { alert('我是函数') }
// NaN
// 我是变量

// 题五
alert(a);   
var a = 0;
alert(a);   
function fn(){
  alert(a);    
  var a = 1;
  alert(a);    
}
fn()
alert(a);
// 执行顺序  第一个alert  第二个alert  fn函数内部的代码  第三个alert
// undefined
// 0
// undefined
// 1
// 0

10 子调用函数 IIFE

10.1 匿名函数

function() {
  // 匿名函数
}

匿名函数声明后要立即调用,否则没有意义

10.2 自动调用函数

函数声明完立即调用,称为自调用函数,英文简称IIFE——Immediately Invoked Function Expression

// 自调用函数
(function() {
  console.log('我被调用了');
})();

// 带参数的自调用函数
(function(a, b) {
  console.log(a + b);
})(10,20);

两个连续的自调用函数之间必须加分号,不然会报错

10.3自调用函数的作用

  • 减少全局变量的使用,把自己代码或每个特效的代码写到一个自调用函数中,防止全局变量污染
  • 隐藏内部代码暴露接口,实现模块化开发

11 回调函数

11.1 解释

函数全部满足以下条件就是回调函数:

  1. 函数是我定义的
  2. 我没有调用
  3. 函数被执行了

11.2 用途

  • 事件函数
  • 定时器函数
  • Ajax的回调函数
  • 生命周期钩子函数
    很多时候匿名函数作为回调函数

11.3 举例

function fn(callback) {
  callback();
}
// 调用fn,传匿名函数进去
fn(function() {
  console.log('回调函数被执行了');
});

function progress(num1, num2, call) {
  call(num1, num2);
}
process(100, 200, function(a, b) {console.log(a + b)});

12 递归函数

12.1 概念

一个函数的内部如果再次调用了自己,则称为是函数的递归调用,这样的函数为递归函数

12.2 形成递归函数的条件

  • 必须有明确的结束条件
  • 必须有趋近于结束条件的趋势
// 使用递归求1~100的和
        function fun(n) {
            if (n == 1) return 1;
            return n + fun(n - 1);
        }
        var result = fun(100);
        console.log(result); // 5050

12.3 缺点

  • 递归容易导致内存泄露
  • 函数递归的效率比较低

12.4 应用

  • 删除文件夹中的内容(操作系统的原始接口只能删除文件和空文件夹)
  • 复制文件夹里面的内容
  • 剪切文件夹以及里面的内容
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>