前言
函数是一段可以反复调用的代码块。函数还能接受输入的参数,不同的参数会返回不同的值。
JavaScript 语言将函数看作一种值,与其它值(数值、字符串、布尔值等等)地位相同。凡是可以使用值的地方,就能使用函数。比如,可以把函数赋值给变量和对象的属性,也可以当作参数传入其他函数,或者作为函数的结果返回
函数参数
函数运行的时候,有时需要提供外部数据,不同的外部数据会得到不同的结果,这种外部数据就叫参数。分为以下两种:
- 形参:函数定义的参数
- 实参:函数调用时实际传递的参数。
function square(x) {
return x * x;
}
square(2) // 4
square(3) // 9
上式的x就是square函数的形参。每次运行的时候,需要提供这个值,否则得不到结果。
参数匹配是从左向右进行匹配,如果实参个数少于形参,后面的参数对应赋值undefined。
实参的个数如果多于形参的个数,可以通过arguments访问。
function f(a, b) {
return a;
}
f(1, 2, 3) // 1
f(1) // 1
f() // undefined
f.length // 2
函数内部的变量提升
与全局作用域一样,函数作用域内部也会产生“变量提升”现象。var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部
function foo(x) {
if (x > 100) {
var tmp = x - 100;
}
}
// 等同于
function foo(x) {
var tmp;
if (x > 100) {
tmp = x - 100;
};
}
按值传递还是按引用传递?
-
函数的参数如果是简单类型,会将一个值类型的数值副本传到函数内部,函数内部不影响函数外部传递的参数变量
-
如果是一个参数是引用类型,会将引用类型的地址值复制给传入函数的参数,函数内部修改会影响传递参数的引用对象。
var a = 9, // 简单类型,值类型
b = { name: 'laoma', age: 18 } // 引用类型
function demo(c1, c2) {
c1 = 29 // 对c1做了更改。
c2.name = '6666' // 更改了c2引用类型的顺序name
}
demo(a, b) // 调用函数执行
console.log(a) // a => 9;
console.log(b) // b.name => '6666'
break、continue和return区别
-
break语句用于跳出代码块或循环
-
continue语句用于立即终止本轮循环,返回循环结构的头部,开始下一轮循环。
-
使用return可以结束整个函数
function fun () {
for (var i = 0; i < 5; i++) {
if (i == 2) {
//break; 0 1 “执行完了”
//continue; 0 1 3 4 “执行完了”
return;// 0 1
}
console.log(i);
}
console.log("函数执行完了");
}
fun();
return返回值类型
返回值可以是任意的数据类型,也可以是一个对象,也可以是一个函数。
function fun2 () {
return { name: "沙和尚" };//返回一个对象
}
var a = fun2();
function fun3 () {
function fun4 () {//在函数内部再声明一个函数
alert("我是fun4");
}
return fun4;//将fun4函数对象作为返回值返回
}
a = fun3();
a(); //"我是fun4"
fun3()(); //"我是fun4"
立即调用的函数表达式
有时,我们需要在定义函数之后,立即调用该函数。这时,你不能在函数的定义之后加上圆括号,这会产生语法错误。而是写成如下形式:
(function(){ /* code */ }());
// 或者
(function(){ /* code */ })();
上面两种写法都是以圆括号开头,引擎就会认为后面跟的是一个表示式,而不是函数定义语句,所以就避免了错误。这就叫做“立即调用的函数表达式”(Immediately-Invoked Function Expression),简称 IIFE。
它的目的有两个:一是不必为函数命名,避免了污染全局变量;二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。
// 写法一
var tmp = newData;
processData(tmp);
storeData(tmp);
// 写法二
(function () {
var tmp = newData;
processData(tmp);
storeData(tmp);
}());
上面代码中,写法二比写法一更好,因为完全避免了污染全局变量。