JS-10-函数

本文详细介绍了JavaScript中的函数定义、参数传递、调用方式、属性(如length、name、prototype)、方法(如apply、call、bind、toString)以及arguments关键字、rest参数和return语句的使用。
摘要由CSDN通过智能技术生成

一、函数的定义

function 函数名(参数列表)
{
    // 函数体
}

示例:

function abs(x) {
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
}

请注意,函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回

如果没有return语句,函数执行完毕后也会返回结果,只是结果为undefined

由于JavaScript的函数也是一个对象,上述定义的abs()函数实际上是一个函数对象,而函数名abs可以视为指向该函数的变量。

因此,第二种定义函数的方式如下:

var 变量名 = function (参数列表)
{
    // 函数体
};

示例:

var abs = function (x) {
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
};

在这种方式下,function (x) { ... }是一个匿名函数,它没有函数名。但是,这个匿名函数赋值给了变量abs,所以,通过变量abs就可以调用该函数。

上述两种定义完全等价,注意第二种方式按照完整语法需要在函数体末尾加一个;,表示赋值语句结束。

二、函数的调用

调用函数时,按顺序传入参数即可:

abs(10); // 返回10
abs(-9); // 返回9

1、传入的参数比定义的参数多也没有问题

abs(10, 'blablabla'); // 返回10
abs(-9, 'haha', 'hehe', null); // 返回9

2、传入的参数比定义的少也没有问题:

abs(); // 返回NaN

此时abs(x)函数的参数x将收到undefined,计算结果为NaN。

要避免收到undefined,可以对参数进行检查:

function abs(x) {
    if (typeof x !== 'number') {
        throw 'Not a number';
    }
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
}

JavaScript函数允许接收任意个参数

三、函数的属性、方法

在JavaScript中,函数是第一类对象,这意味着函数具有属性和方法,就像其他对象一样。

3-1、函数的属性

1、length属性

这个属性表示函数期望的参数个数。对于非函数对象,该属性的值为undefined。

function example(a, b, c) {  
  // ...  
}  
console.log(example.length); // 输出 3

 

2、name属性

这个属性返回函数的名称。对于匿名函数,这个属性可能是一个空字符串

function myFunction() {  
  // ...  
}  
console.log(myFunction.name); // 输出 "myFunction"  
  
const anonymous = function() {  
  // ...  
};  
console.log(anonymous.name); // 输出可能是 "anonymous" 或者空字符串,取决于JavaScript引擎

 

 3、prototype属性

这个属性是所有函数对象都有的,它指向一个对象,该对象可以用作构造新对象时的原型。通过修改函数的prototype属性,你可以为该函数创建的所有对象添加新属性或方法。

function MyObject() {  
  console.log('MyObject');
}  
  
MyObject.prototype.myMethod = function() {  
  console.log('myMethod');
};  
  
const obj = new MyObject();  // MyObject
obj.myMethod(); // myMethod 调用原型上的方法

4、其他自定义属性 

也可以给函数添加自定义属性,就像给其他对象添加属性一样。

function greet() {  
  console.log('Hello!');  
}  
  
greet.customProperty = 'Some value';  
console.log(greet.customProperty); // 输出 "Some value"

3-2、函数的方法

1、apply()方法

调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数

function greet(name) {  
  console.log(`Hello, ${name}!`);  
}  
  
const args = ['World'];  
greet.apply(null, args); // 输出 "Hello, World!"

2、call()方法 

调用一个具有给定this值的函数,以及提供的参数列表。

function greet(name) {  
  console.log(`Hello, ${name}!`);  
}  
  
greet.call(null, 'World'); // 输出 "Hello, World!"

 

3、bind()方法

创建一个新的函数,当被调用时,它的this值被设置为提供的值,并且在调用新函数时,将预先传入的一组参数作为原函数的参数序列的前缀。

function greet(name) {  
  console.log(`Hello, ${name}!`);  
}  
  
const boundGreet = greet.bind(null, 'World');  
boundGreet(); // 输出 "Hello, World!"

4、toString()方法

返回一个表示该函数源代码的字符串。

function greet() {  
  console.log('Hello!');  
}  
  
console.log(greet.toString()); // 输出函数的源代码字符串

5、给函数对象添加自定义方法

由于函数本身就是对象,你可以像给任何其他对象添加属性一样给函数添加方法。这允许你扩展函数的功能,并创建出更具表现力和可重用的代码。

function greet() {  
  console.log('Hello!');  
}  
  
// 自定义一个方法到 greet 函数对象上  
greet.customMethod = function() {  
  console.log('This is a custom method on the greet function.');  
};  
  
// 调用 greet 函数  
greet(); // 输出 "Hello!"  
  
// 调用 greet 上的自定义方法  
greet.customMethod(); // 输出 "This is a custom method on the greet function."

 值得注意的是,虽然你可以给函数对象添加任意多的自定义属性和方法,但通常建议谨慎使用这种做法。过度扩展内置对象或常用库可能会导致代码难以理解和维护,也可能与未来的JavaScript版本或第三方库冲突。在创建自定义方法时,最好确保它们有明确的目的,并且与函数的原始功能相关。

如果你发现自己在多个地方重复使用相同的自定义方法,可能更好的做法是将这些方法组织到一个单独的对象或类中,然后通过组合或继承的方式使用它们。这样可以更好地组织你的代码,并使其更易于维护和扩展。

四、arguments关键字

JavaScript还有一个免费赠送的关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array,但它不是一个Array:

function foo(x) {
    console.log('x = ' + x); // 10
    for (var i=0; i<arguments.length; i++) {
        console.log('arg ' + i + ' = ' + arguments[i]); // 10, 20, 30
    }
}
foo(10, 20, 30);

arguments关键字可以拿到调用者传入的所有参数!即使函数不定义任何参数,还是可以拿到参数的值:

function abs() {
    if (arguments.length === 0) {
        return 0;
    }
    var x = arguments[0];
    return x >= 0 ? x : -x;
}

abs(); // 0
abs(10); // 10
abs(-9); // 9

实际上arguments最常用于判断传入参数的个数。

五、rest参数 

为了获取除了已定义参数a、b之外的参数,我们不得不用arguments,并且循环要从索引2开始以便排除前两个参数:

function foo(a, b) {
    var i, rest = [];
    if (arguments.length > 2) {
        for (i = 2; i<arguments.length; i++) {
            rest.push(arguments[i]);
        }
    }
    console.log('a = ' + a);
    console.log('b = ' + b);
    console.log(rest);
}

写法变扭,不方便,使用ES6标准引入的rest参数。因此,rest参数的目的:获取function中调用者传入的额外的参数

function foo(a, b, ...rest) {
    console.log('a = ' + a);
    console.log('b = ' + b);
    console.log(rest);
}

foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]

foo(1);
// 结果:
// a = 1
// b = undefined
// Array []

rest参数只能写在最后,前面用...标识

从运行结果可知,传入的参数先绑定a、b,多余的参数以数组形式交给变量rest,所以,不再需要arguments我们就获取了全部参数。

如果传入的参数连正常定义的参数都没填满,也不要紧,rest参数会接收一个空数组(注意不是undefined)。

四、return语句

JavaScript引擎有一个在行末自动添加分号的机制,所以,存在如下问题:

正确写法:

function foo() {
    return { name: 'foo' };
}

foo(); // { name: 'foo' }

错误写法:

function foo() {
    return
        { name: 'foo' };
}

foo(); // undefined

要小心了,由于JavaScript引擎在行末自动添加分号的机制,上面的代码实际上变成了:

function foo() {
    return; // 自动添加了分号,相当于return undefined;
        { name: 'foo' }; // 这行语句已经没法执行到了
}

所以正确的多行写法是:

function foo() {
    return { // 这里不会自动加分号,因为{表示语句尚未结束
        name: 'foo'
    };
}
  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值