JavaScript 函数全面解析

一、函数的概念

在 JavaScript 编程中,常常会出现大量重复或功能相似的代码片段。为了提高代码的复用性与可维护性,函数应运而生。函数本质上是一段封装好的可重复调用执行的代码块,通过它能够实现特定功能的复用。当使用typeof操作符检查一个函数对象时,会返回function。例如著名的 jQuery 库,它将众多功能封装成函数,对外仅暴露一个顶级对象$,这便是函数封装的典型应用。可以将函数的封装理解为把诸多衣物规整地打包到行李箱中,方便随时取用。

二、函数的使用

(一)声明函数

  1. 构造函数方式:使用构造函数创建函数对象,即new Function()。此方法将封装的代码以字符串形式传递给构造函数,但在实际开发中较少使用。因为通过构造函数创建函数,会导致代码被解析两次,影响性能。第一次解析常规 JavaScript 代码,第二次解析传入构造函数的字符串。例如:

var fun = new Function("console.log('hello 这是我的第一个函数')");

console.log(typeof fun); // function

fun();

  1. 函数声明方式:这是最常用的声明函数的方法,语法为function 函数名([形参1,形参2,形参3,形参4....形参n]){执行语句.....}。函数声明会被 JavaScript 编译器提升到作用域的最前面,因此无论在代码的何处调用该函数,都能正常执行。例如:

function fun2() {

    console.log("这是我的第二个函数~~~");

    alert("hahahaha");

    document.write("wuwuwuwu");

}

  1. 函数表达式方式:也叫匿名函数,语法为var 变量名 = function([形参1,形参2,形参3,形参4....形参n]){语句.....}。需要注意的是,变量名并非真正的函数名。与函数声明不同,函数表达式必须在定义之后才能调用,因为在解析到函数表达式之前,变量仅被声明为undefined。例如:

var fun3 = function () {

    console.log("我是匿名函数中的封装的代码");

}; // 相当于赋值语句

fun3(); // 调用函数

由于函数通常用于实现特定功能,所以函数名一般使用动词命名,例如getSum,这样能使代码的意图更加清晰。

(二)调用函数

调用函数的语法为变量名/函数名()。当函数被调用时,其中封装的代码会按照顺序依次执行。例如,利用函数计算 1 - 100 之间的累加和:

function getSum() {

    var sum = 0;

    for (var i = 1; i <= 100; i++) {

        sum += i;

    }

    return sum;

}

var result = getSum();

console.log(result);

三、函数的参数

(一)参数的基本概念

在声明函数时,函数名后的小括号内定义的参数为形参,调用函数时传递的参数则是实参。形参在函数定义阶段仅是占位符,用于接收实参的值,类似于声明但未赋值的变量,多个形参之间用逗号分隔。实参则是在函数调用时实际传递给形参的值,相当于给形参赋值。参数的作用在于,当函数内部某些值不确定时,可通过传递不同的实参来实现函数功能的多样化。例如:

function addNumbers(num1, num2) {

    return num1 + num2;

}

var sum = addNumbers(3, 5);

console.log(sum);

(二)形参和实参匹配问题

  1. 个数一致:当形参和实参的个数相等时,函数能正常输出结果。
  2. 实参多于形参:若实参的个数多于形参,函数仅会取用与形参个数对应的实参值,多余的实参将被忽略。
  3. 实参少于形参:当实参个数少于形参时,未被赋值的形参默认被定义为undefined

调用函数时,JavaScript 解析器不会检查实参的类型,因此需要注意可能接收到非法参数的情况。为保证函数的稳定性和可预测性,建议形参和实参的个数保持一致。

(三)实参的类型

实参可以是任意数据类型,包括对象和函数。当参数较多时,将参数封装到对象中传递是一种良好的实践方式。例如:

function printInfo(person) {

    console.log(`姓名:${person.name},年龄:${person.age},性别:${person.gender}`);

}

var personObj = {

    name: "张三",

    age: 25,

    gender: "男"

};

printInfo(personObj);

实参也可以是一个函数,例如:

function executeFunction(func) {

    func();

}

function sayHello() {

    console.log("Hello!");

}

executeFunction(sayHello);

四、函数的返回值 return

(一)返回值语法结构

函数通过return语句返回结果,语法为function 函数名(){return 需要返回的结果}。例如,输入一个数,求 1 到该数的和,并在此基础上进行简单运算:

var num = +prompt('输入一个数');

function getSum(num) {

    var sum = 0;

    for (var i = 1; i <= num; i++) {

        sum += i;

    }

    console.log(sum);

    return sum;

}

var res = getSum(num);

console.log(res + 1);

(二)返回值注意事项

  1. 结果反馈:函数实现特定功能后,通过return将结果返回给调用者,即函数名() = return后面的结果。也可定义变量接收该返回值。
  2. 终止函数:函数执行到return语句后,后续代码将不再执行,return具有终止函数的作用。
  3. 单一值返回return只能返回一个值,若有多个值,仅返回最后一个。如需返回多个值,可将其放入数组或对象中。
  4. 返回值类型return后可跟任意类型的值。若return后不跟任何值,相当于返回undefined;若函数中未写return,同样返回undefined。例如:

function sum(a, b, c) {

    var d = a + b + c;

    return d;

}

var result = sum(4, 7, 8);

console.log("result=" + result);

(三)返回值类型

返回值可以是任意数据类型,包括对象和函数。例如返回值为对象:

function fun2() {

    var obj = { name: "沙和尚" };

    return obj;

}

var a = fun2();

console.log("a=" + a);

返回值为函数:

function fun3() {

    function fun4() {

        alert("我是fun4");

    }

    return fun4;

}

var a = fun3();

a();

(四)breakcontinuereturn的区别

  1. break:用于结束当前循环体(如forwhile循环)。
  2. continue:跳出本次循环,继续执行下次循环。
  3. return:不仅能退出循环,还可返回return语句中的值,并结束当前函数的执行。例如:

function fun() {

    alert("函数要执行了~~~");

    for (var i = 0; i < 5; i++) {

        if (i == 2) {

            break; // 退出当前的循环

            continue; // 用于跳过当次循环

            return; // 使用return可以结束整个函数

        }

        console.log(i);

    }

    alert("函数执行完了~~~");

}

// fun();

五、arguments的使用

在调用函数时,浏览器会自动传递两个隐含参数:函数的上下文对象this和封装实参的对象arguments。当不确定传递参数的个数时,可借助arguments获取所有实参。arguments是当前函数的内置对象,所有函数都具备,它存储了调用函数时传递的所有实参。

(一)arguments的特性

  1. 伪类数组性质arguments是一个伪类数组对象,它具有数组的length属性,可通过索引操作数据,但不具备真正数组的一些方法,如pushpop等。
  2. 实参存储:调用函数时传递的所有实参都保存在arguments中。
  3. 访问实参:即使函数未定义形参,也能通过arguments访问实参,arguments[0]表示第一个实参,arguments[1]表示第二个实参,以此类推。
  4. arguments.calleearguments对象有一个callee属性,它指向当前正在执行的函数对象。例如:

function fun() {

    console.log(arguments.callee);

}

fun();

例如,利用函数求任意个数的最大值:

function getMax() {

    var max = arguments[0];

    for (var i = 0; i < arguments.length; i++) {

        if (max < arguments[i]) {

            max = arguments[i];

        }

    }

    return max;

}

var num = getMax(1, 2, 3, 33, 111);

console.log(num);

六、函数方法call()apply() ,bind()

call()apply()bind()均为函数对象的方法,需通过函数对象调用。调用call()apply()方法时,函数会立即执行,并且可将一个对象指定为第一个参数,该对象将成为函数执行时的this

  1. call()方法:可在指定对象之后依次传递实参。例如:

var name = "我是window";

function fun(a) {

    console.log("a=", a);

    alert(this.name);

}

var obj = {

    name: "我是obj1",

    sayName: function () {

        alert(this.name);

    }

};

var obj2 = {

    name: "我是obj2"

};

fun.call(obj, 2);

  1. apply()方法:需要将实参封装到一个数组中统一传递。例如:

fun.apply(obj2, [2, 3]);

  1. bind()方法bind()方法与call()apply()不同,它不会立即执行函数,而是返回一个新的函数,新函数的this被绑定为指定的对象。例如:

function greet() {

    console.log(`Hello, ${this.name}`);

}

var obj = { name: "Alice" };

var boundGreet = greet.bind(obj);

boundGreet();

总结this的指向情况:

  1. 以函数形式调用时,this永远指向window(在严格模式下为undefined)。
  2. 以方法的形式调用时,this是调用方法的对象。
  3. 以构造函数的形式调用时,this是新创建的实例对象。
  4. 使用callapply调用时,this是指定的对象;若不写第一个参数,默认指向window(严格模式下为undefined)。

七、函数调用函数

每个函数都是独立的代码块,用于完成特定任务,因此函数相互调用的情况十分常见。一般而言,一个函数应专注于完成一件事,以提高代码的可读性和可维护性。例如:

function fn1() {

    console.log(111);

    fn2();

    console.log('fn1');

}

function fn2() {

    console.log(222);

    console.log('fn2');

}

fn1();

八、立即执行函数

立即执行函数的语法结构为(function() { /* 函数体 */ })(); 或 function() { /* 函数体 */ }(); 。函数定义完成后立即被调用,且通常只会执行一次。例如:

// 第一种写法

(function () {

    alert("我是一个匿名函数~~~");

})();

// 第二种写法

(function () {

    alert('匿名函数执行方式二');

}());

// 匿名函数传参

(function (a, b) {

    console.log("a=" + a);

    console.log("b=" + b);

})(123, 456);

立即执行函数常用于创建独立的作用域,避免变量污染全局作用域,同时可用于初始化一些一次性执行的代码逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值