第10章-函数-红宝书笔记

本文详细介绍了JavaScript中的函数,包括函数声明、函数表达式、箭头函数的使用,以及参数处理,如默认参数、参数扩展与收集。还讨论了函数的作用域,特别是函数名作为指针的特性,以及arguments对象和默认参数值的作用。最后,提到了函数声明与函数表达式的区别。
摘要由CSDN通过智能技术生成

函数

  • 函数也是对象
  • 每个函数都是Function类型的实例,而 Function 也有属性和方法
  • 函数名是指向函数对象的指针,而且不一定与函数本身紧密绑定

定义

  • 函数声明的方式
function sum (num1, num2) { 
 return num1 + num2; 
}
  • 函数表达式
let sum = function(num1, num2) { 
 return num1 + num2; 
};
  • 箭头函数
let sum = (num1, num2) => { 
 return num1 + num2; 
};
  • Function 构造函数(不推荐)
    接受任意多个字符串参数
    最后一个参数是函数体
let sum = new Function("num1", "num2", "return num1 + num2"); // 不推荐

箭头函数

箭头函数与正式的函数表达式创建的函数对象行为是相同的

let arrowSum = (a, b) => { 
 return a + b; 
}; 
let functionExpressionSum = function(a, b) { 
 return a + b; 
}; 
console.log(arrowSum(5, 8)); // 13 
console.log(functionExpressionSum(5, 8)); // 13
  • 如果只有一个参数,可以不用括号
    以下两种写法都有效
let double = (x) => { return 2 * x; }; 
let triple = x => { return 3 * x; };
  • 只有没有参数,或者多个参数的情况下,才需要使用括号
// 没有参数需要括号
let getRandom = () => { return Math.random(); }; 
// 多个参数需要括号
let sum = (a, b) => { return a + b; }; 
// 无效的写法:
let multiply = a, b => { return a * b; };
  • 可以不使用大括号,但是只能写一行代码,省略大括号会隐式返回这行代码的值
// 以下两种写法都有效,而且返回相应的值
let double = (x) => { return 2 * x; }; 
let triple = (x) => 3 * x; 
// 可以赋值
let value = {}; 
let setName = (x) => x.name = "Matt"; 
setName(value); 
console.log(value.name); // "Matt" 
// 无效的写法:
let multiply = (a, b) => return a * b;

箭头函数虽然语法简洁,但也有很多场合不适用。箭头函数不能使用 arguments、super 和new.target,也不能用作构造函数。此外,箭头函数也没有 prototype 属性。

函数名

函数名就是指向函数的指针
意味着一个函数可以有多个名称

function sum(num1, num2) { 
 return num1 + num2; 
} 
console.log(sum(10, 10)); // 20 
let anotherSum = sum; 
console.log(anotherSum(10, 10)); // 20 
sum = null; 
console.log(anotherSum(10, 10)); // 20

上面代码sum=null只是切短了sum和函数的联系,不影响anothersum

函数包含一个只读的name属性,包含函数标识符(函数名称),字符串类型

function foo() {} 
let bar = function() {}; 
let baz = () => {}; 
console.log(foo.name); // foo 
console.log(bar.name); // bar 
console.log(baz.name); // baz 
console.log((() => {}).name); //(空字符串)
console.log((new Function()).name); // anonymous

理解参数

ES不会关心传入参数的个数数据类型,无论你定义多少个

arguments对象

  • 在非箭头函数内部可以访问arguments对象
  • arguments 对象是一个类数组对象(但不是 Array 的实例),因此可以使用中括号语法访问其中的元素
  • length属性检查传入的参数个数
  • arguments 对象可以跟命名参数一起使用
    虽然改变arguments的值能改变命名参数所代替的值
    但是两个所对应的内存是不一样的
function doAdd(num1, num2) { 
 arguments[1] = 10; 
 console.log(arguments[0] + num2); 
}

比较传入两个参数和传入一个参数的区别

箭头函数中的参数

箭头函数中不能使用arguments对象

可以在包装函数中把arguments提供给箭头函数

function foo() { 
 let bar = () => { 
 console.log(arguments[0]); // 5 
 }; 
 bar(); 
} 
foo(5);

没有重载

如果在 ECMAScript 中定义了两个同名函数,则后定义的会覆盖先定义的。

function addSomeNumber(num) { 
 return num + 100; 
} 
function addSomeNumber(num) { 
 return num + 200; 
} 
let result = addSomeNumber(100); // 300

默认参数值

  • ES5.1及以前,实现默认参数主要检测是否等于undefined
function makeKing(name) { 
 name = (typeof name !== 'undefined') ? name : 'Henry'; 
 return `King ${name} VIII`; 
} 
console.log(makeKing()); // 'King Henry VIII' 
console.log(makeKing('Louis')); // 'King Louis VIII'
  • ES6之后,直接在定义出加一个=就可以定义默认参数。
function makeKing(name = 'Henry') { 
 return `King ${name} VIII`; 
} 
console.log(makeKing('Louis')); // 'King Louis VIII' 
console.log(makeKing()); // 'King Henry VIII'
  • 而给参数传undefined相当于没传值,函数会调用默认值
function makeKing(name = 'Henry', numerals = 'VIII') { 
 return `King ${name} ${numerals}`; 
} 
console.log(makeKing()); // 'King Henry VIII' 
console.log(makeKing('Louis')); // 'King Louis VIII' 
console.log(makeKing(undefined, 'VI')); // 'King Henry VI'
  • arguments 对象的值不反映参数的默认值,只反应传给函数的参数
function makeKing(name = 'Henry') { 
 name = 'Louis'; 
 return `King ${arguments[0]}`; 
} 
console.log(makeKing()); // 'King undefined' 
console.log(makeKing('Louis')); // 'King Louis'
  • 默认参数值并不限于原始值或对象类型,也可以使用调用函数返回的值
let romanNumerals = ['I', 'II', 'III', 'IV', 'V', 'VI']; 
let ordinality = 0; 
function getNumerals() { 
 // 每次调用后递增
 return romanNumerals[ordinality++]; 
} 
function makeKing(name = 'Henry', numerals = getNumerals()) { 
 return `King ${name} ${numerals}`; 
} 
console.log(makeKing()); // 'King Henry I'
console.log(makeKing('Louis', 'XVI')); // 'King Louis XVI' 
console.log(makeKing()); // 'King Henry II' 
console.log(makeKing()); // 'King Henry III'

注意:

  • 默认参数只有在函数被调用时才会求值
  • 计算默认值的函数只有在未传相应参数时才会被调用
  • 箭头函数也可以使用默认参数,在只有一个参数时,括号不能省略
let makeKing = (name = 'Henry') => `King ${name}`; 
console.log(makeKing()); // King Henry
默认参数作用域与暂时性死区
function makeKing(name = 'Henry', numerals = 'VIII') { 
 return `King ${name} ${numerals}`; 
} 
console.log(makeKing()); // King Henry VIII

可以想象成下面的代码

function makeKing() { 
 let name = 'Henry'; 
 let numerals = 'VIII'; 
 return `King ${name} ${numerals}`; 
}

参数初始化顺序遵循“暂时性死区”规则,即前面定义的参数不能引用后面定义的。像这样就会抛出错误:

// 调用时不传第一个参数会报错
function makeKing(name = numerals, numerals = 'VIII') { 
 return `King ${name} ${numerals}`; 
}

参数也存在于自己的作用域中,它们不能引用函数体的作用域:

// 调用时不传第二个参数会报错
function makeKing(name = 'Henry', numerals = defaultNumeral) { 
 let defaultNumeral = 'VIII'; 
 return `King ${name} ${numerals}`; 
}

参数扩展与收集

扩展参数

有时候可能不需要传一个数组,而是要分别传入数组的元素

console.log(getSum(...values)); // 10

对函数中的 arguments 对象而言,它并不知道扩展操作符的存在,而是按照调用函数时传入的参数接收每一个值:

let values = [1,2,3,4] 
function countArguments() { 
 console.log(arguments.length); 
} 
countArguments(-1, ...values); // 5 
countArguments(...values, 5); // 5 
countArguments(-1, ...values, 5); // 6 
countArguments(...values, ...[5,6,7]); // 7

收集参数

收集参数的结果会得到一个 Array 实例,区别于arguments 对象

function getSum(...values) { 
 // 顺序累加 values 中的所有值
 // 初始值的总和为 0 
 return values.reduce((x, y) => x + y, 0); 
} 
console.log(getSum(1,2,3)); // 6

多余的参数要放在它前边

// 不可以
function getProduct(...values, lastValue) {} 
// 可以
function ignoreFirst(firstValue, ...values) { 
 console.log(values); 
} 
ignoreFirst(); // [] 
ignoreFirst(1); // [] 
ignoreFirst(1,2); // [2] 
ignoreFirst(1,2,3); // [2, 3]

箭头函数支持收集参数,虽然不支持aarguments,但能利用收集函数实现同样的功能。

函数声明与函数表达式

函数声明会得到函数声明提升

// 没问题 
console.log(sum(10, 10)); 
function sum(num1, num2) { 
 return num1 + num2; 
}

函数表达式会出错

// 会出错
console.log(sum(10, 10)); 
let sum = function(num1, num2) { 
 return num1 + num2; 
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值