每天3小时学前端之JS-第14天-函数的参数+立即执行函数

330 阅读4分钟

此系列体验视频教程

点击观看:哔哩哔哩

函数

函数的参数

函数的参数是用来传递不同的数据到函数内部,从而得到不同的结果,以此来达到函数功能复用的作用

形参和实参

function square(x) { // 形参
  console.log(x * x);
}

square(2) // 实参 4
square(3) // 9
square() // NaN
  • 多传或者少传参数都不会报错
  • 省略的参数值为undefined

形参的个数

  • 形参的个数就是函数的length属性的值
  • 形参的个数和实际传递的参数的个数是没有关系的
  • 靠前的参数是不能直接留空省略的
  • 想省略必须显式的传递undefined
function fn(a, b) {
  console.log(fn.length);
}
fn() // 2
fn(1) // 2
fn(1, 2) // 2
fn(1, 2, 3) // 2
// fn(, 2) // 报错
fn(undefined, 2) // 2

实参的个数

由于JS允许在调用函数的时候任意传递参数,所以需要一种机制,可以在函数体内部读取所有参数。这就是arguments对象的由来。

  • arguments对象包含了函数运行时的所有参数
  • arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。
  • arguments.length:实参的长度
  • 实参和形参之间有一个联动的关系,修改实参会引起相应位置的形参的变化
  • 如果实参列表中没有给某些形参赋值的话,那么这个形参和实参就没有联动关系
function fn(a, b) {
    console.log(typeof arguments);
    console.log(arguments);
    for (var i = 0; i < arguments.length; i++) {
        console.log(arguments[i]);
    }
    arguments[2] = 33
    console.log(arguments);
    arguments[1] = 22
    console.log(b);
}
fn(1, 2, 3, 4, 5, 6, 'abc')
fn(1)

同名参数

  • 如果有同名的参数,则取最后出现形参的那个值。
  • 即使后面的参数没有传递,依然是获取取后面形参的那个值
  • 如果想在同名参数中获取所有的实参,还是通过arguments
function fn(a, a){
  console.log(a);
  // 同名参数中获取所有实参
  console.log(arguments[0], arguments[1]);
}
// console.log(arguments); // arguments不能在函数外部使用
fn(1, 2)
fn(1)
// 同名参数只取后面的参数的值,即使后面的参数没有传递

参数传递的方式

  • 如果是原始类型的值(数值、字符串、布尔值),传递方式是传值传递(passes by value),传入函数的是原始类型值的拷贝。这意味着,在函数体内修改参数值,不会影响到函数外部原始类型的值
var a = 123
function fn(param) {
  param = 456
}
fn(a)
console.log(a); // 123
  • 如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递(pass by reference)。也就是说,传入函数的是复合类型的地址,因此在函数内部通过点属性修改参数,将会影响到函数外部复合类型的值
var obj = {
  foo: 1
}
function fn(param) {
  param.foo = 2
}
fn(obj)
console.log(obj.foo); // 2

如果不是像上面改变复合类型属性的方式的话,而是对传入的复合类型重新赋值的话,则不会影响到函数外部复合类型的值

var obj = {
  foo: 1
}
function fn(param) {
  param = {
    foo: 2
  }
}
fn(obj)
console.log(obj.foo); // 1

立即执行的函数表达式(IIFE)

有时,我们需要在定义函数之后,立即调用该函数。这时,你不能在声明式函数的定义之后加上圆括号,这会产生语法错误。

function fn() {

}()
// Uncaught SyntaxError: Unexpected token ')'

产生这个错误的原因是,function这个关键字既可以当作语句,也可以当作表达式。而在声明式函数定义中,function被当做语句。

// 语句
function fn1() {}

// 表达式
var fn2 = function () {}

而在function当作表达式时,函数可以在定义后直接加圆括号调用。

var fn2 = function () {
  console.log('fn2');
}() // fn2

另外function只要出现在行首,一律被解释成语句。所以想要能够在函数定义后就可以立即调用的话,就需要不让function出现在行首。让引擎理解成表达式。 注意,立即调用最后的分号最好加上。如果省略分号,遇到连着两个 IIFE,可能就会报错。 解决办法有以下:

(function () {
  console.log('fn1')
})();

(function () {
  console.log('fn2');
}());

var fn3 = function () {
  console.log('fn3');
}()

true && function () {
  console.log('fn4');
}();

0, function () {
  console.log('fn5');
}();
+ function () {
  console.log('fn6');
}();
- function () {
  console.log('fn7');
}();
! function () {
  console.log('fn8');
}();

立即调用(立即执行)函数的作用

  1. 不必为函数命名,避免了污染全局变量
  2. 立即调用函数内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。

作业

/*
写一个加法器
可以接收任意个数参数的函数
没有参数
  直接返回0
如果一个参数
  且此参数可以转化成数值则求从1到此参数的和
  否则直接返回0
如果是多个参数
  则求各参数的和,不能转化为数字的参数跳过。
*/