此系列体验视频教程
点击观看:哔哩哔哩
函数
函数的参数
函数的参数是用来传递不同的数据到函数内部,从而得到不同的结果,以此来达到函数功能复用的作用
形参和实参
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');
}();
立即调用(立即执行)函数的作用
- 不必为函数命名,避免了污染全局变量
- 立即调用函数内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。
作业
/*
写一个加法器
可以接收任意个数参数的函数
没有参数
直接返回0
如果一个参数
且此参数可以转化成数值则求从1到此参数的和
否则直接返回0
如果是多个参数
则求各参数的和,不能转化为数字的参数跳过。
*/