跳至正文

JavaScript入门教程笔记(7)-函数

1 概述

函数是一段可以反复调用的代码,它接受不同的输入参数,返回不同的值。

1.1 函数的声明

有两种常用的声明方法。

(1) function命令

function 命令声明的代码区块,就是一个函数。function 命令后面是函数名,函数名后面是一对圆括号,里面是传入函数的参数,函数体放在大括号里面。

function print(s) {
    console.log(s);
}

上面代码命名了一个 print 函数,以后使用 print() 就可以调用相应代码。这叫做函数的声明。

(2)函数表达式

这种写法将一个匿名函数赋值给变量。因为赋值语句的等号右侧只能放表达式,所以这个匿名函数又称为函数表达式。

var print = function(s) {
    console.log(s);
};

需要注意的是,函数表达式需要在语句的结尾加上分号,表示语句结束。

1.2 函数名的提升

JavaScript中函数名相当于变量名,所以采用 function 命令声明函数时,整个函数会像变量一样被提升到代码头部。

f();

function f() {}

上面的代码不会报错。

但是,如果采用赋值语句定义函数,这样就会报错。

f();

var f = function() {}; // Error

上面代码调用 f 时,f 还没有被赋值,因此报错。

2 函数的属性和方法

2.1 name属性

函数的 name 属性返回函数的名字。

function f1() {}
f1.name // "f1"

name 属性的一个用处是获取参数函数的名字。

var myFunc = function() {};
function test(f) {
    console.log(f.name);
}
test(myFunc) // myFunc

2.2 length属性

函数的 length 属性返回函数定义之中的参数个数。

function f(a, b) {}
f.length // 2

上面代码定义了带2个参数的空函数 f,不管调用时传入几个参数,length 属性始终等于2。

2.3 toString()

函数的 toString 方法返回一个字符串,内容是函数的源码。包括函数内部的注释也可以返回。

3 函数的作用域

3.1 定义

作用域(scope)指的是变量存在的范围。在ES5规范中有两种作用域。一种是全局作用域,变量在整个程序一直存在,所有地方都可以访问;另一种是函数作用域,变量仅在函数内部存在。

函数外部声明的变量就是全局变量,它也可以在函数内部访问。

var a = 1;
function f() {
    console.log(a);
}
f() // 1

上面代码表明,函数 f 内部可以读取全局变量 a。

在函数内部定义的变量,外部无法读取,称为“局部变量”。

function f() {
    var a = 1;
}
a // Error

上面代码表明,变量 a 在函数内部定义,函数外部无法访问局部变量 a。

3.2 函数内部的变量提升

函数内部也存在“变量提升”,即变量声明无论在函数什么位置,都会被提升到函数体的头部。

function f(a) {
    if (a > 10) {
        var tmp = a - 10;
    }
}
// 等同于
function f(a) {
    var tmp; // 变量提升
    if (a > 10) {
        tmp = a - 10;
    }
}

3.3 函数本身的作用域

函数本身有自己的作用域,就是其声明时所在的作用域,而不是其运行时所在的作用域。

var a = 1;
var x = function() {
    console.log(a);
}
function f() {
    var a = 2;
    x();
}
f() // 1

上面代码中,函数 x 是在函数 f 的外部声明的,它的作用域在外层,不会到 f 函数体内取值,所以输出1,而不是2。

如果去掉第一行的 var a = 1,将会报错,因为找不到变量 a。

4 函数的参数

4.1 概述

函数运行的时候,有时需要传入不同的外部数据来得到不同的结果,这种外部数据就叫做参数。

function add(a, b) {
    return a + b;
}
add(1, 2); // 3

上面代码中的a和b就是add函数的参数。

4.2 参数的省略

参数不是必需的,即使函数声明时定义了参数,但运行时无论提供多少个参数(或者不提供),都不会报错。省略的参数的值等于 undefined。

但是,没有办法省略靠前的参数,而只保留靠后的参数。如果一定要省略,只能显式地传入 undefined。

function f(a, b) {
    return a;
}
f( , 1); // Error
f(undefined, 1); // undefined

4.3 参数传递方式

函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值。即在函数体内修改参数值,不会影响到函数外部。

如果是复合类型的值(数组、对象、其它函数),传递方式是传址。即在函数体内修改参数值,将会影响到函数外部。

但是,如果函数内部替换掉整个参数,这时不会影响到原始值。

var obj = [1, 2, 3];
function f(o) {
    o = [4, 5, 6];
}
f(obj); 
obj // [1, 2, 3]

上面代码中,obj在函数内部被整个替换成另一个值,这时形参o指向的是另一个内存地址,所以原始地址的obj值不会改变。

4.4 同名参数

如果有同名的参数,则取最后出现的那个值。

function f(a, a) {
    console.log(a);
}
f(1, 2) // 2

上面代码中,函数f有两个同名参数a,以后面的a为准。

4.5 arguments 对象

4.5.1 定义

函数允许有不定数目的参数,而 arguments 对象包含了函数运行时的所有参数。arguments[0]是第一个参数,arguments[1]是第二个参数,以此类推。

var f = function(obj) {
    console.log(arguments[0]); // 1
    console.log(arguments[1]); // 2
    console.log(arguments[2]); // 3
}
f(1, 2, 3) 

注意,arguments 对象只有在函数体内部才可以使用。

通过 arguments 对象的 length 属性,可以判断函数调用时到底带几个参数。

function f() {
    return arguments.length;
}
f(1, 2, 3) // 3
f(1) // 1
f() // 0
4.5.2 与数组的关系

需要注意的是,虽然 arguments 很像数组,但它实际是一个对象。所以数组专有的方法(比如slice和forEach),不能在 arguments 对象上直接使用。

注:本文适用于ES5规范,原始内容来自 JavaScript 教程,有修改。

标签:

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注