1. 函数与对象的区别
function foo(){}
class Cls {}
foo(); // 函数是可调用的
Cls();
// Uncaught TypeError: Class constructor Cls cannot be invoked without 'new'
2. 回调函数
- 定义:将某个函数作为参数传入另一个函数,传入函数会在应用程序执行的未来某个时间点才执行,这个传入的函数被称为回调函数
function foo(fn){ // 接收一个函数fn作为参数 return fn(); // 返回时调用传入的函数 }
3. 函数作为对象的意义
3.1 存储函数
// 需求:存储唯一函数集合(即添加的函数唯一且不重复)
var store = {
nextId: 1,
cache: {},
add: function (fn) {
if (!fn.id) { // 检查该函数是否已经存在id属性
fn.id = this.nextId++;
this.cache[fn.id] = fn;
return true;
}
return false;
}
};
function fn_01(){}
function fn_01(){}
function fn_02(){}
console.log(store.add(fn_01)); // true
console.log(store.add(fn_01)); // false
console.log(store.add(fn_02)); // true
console.log(fn_01.id); // 1
console.log(fn_02.id); // 2
3.2 自记忆函数
- 定义:当函数计算得到结果时就将该结果按照参数存储起来,如果另一个调用也使用相同的参数,则可以直接赶回上次存储的结果而不是再计算一边。这样可以避免重复且复杂的计算。通常用于动画中的计算、搜索不经常变化的数据或任何耗时的数学计算。
// 判断一个值是否是素数(除了1和它本身不再有其他因数)
function isPrime(value) {
// 建立缓存
if (!isPrime.answers) {
isPrime.answers = {};
}
// 检查是否已经计算过这个值
if (isPrime.answers[value] !== undefined) {
return isPrime.answers[value];
}
var prime = value !== 0 && value !== 1;
for (var i = 2; i < value; i++) {
if (value % i === 0) {
prime = false;
break;
}
}
// 存储计算的值
return isPrime.answers[value] = prime;
}
console.log(isPrime(0)); // false
console.log(isPrime(1)); // false
console.log(isPrime(5)); // true
console.log(isPrime(5)); // true
console.log(isPrime.answers); // {0: false, 1: false, 5: true}
4. 函数定义
4.1 函数声明和函数表达式
- 函数声明
function fn(params) { /** 函数体 */ }
- 函数表达式
var fn = function(params) { /** 函数体 */ }
- 立即调用函数表达式(IIFE)
// 这一特性可以模拟模块化
(function(val) {console.log(val)})(3); // 3
(function(val) {console.log(val)}(3)); // 3 不推荐使用
// 如果去掉包裹函数表达式的括号会报错,
// 因为这个语句以function开头,解析器会认为这是一个函数声明。
// 每个函数声明必须有名字,而这里没有
// 所以函数报错
// 立即调用函数表达式的常用形式(使用一元操作符将函数声明改为表达式)
// 不影响最终结果
+function(val) {console.log(val)}(3);
-function(val) {console.log(val)}(3);
!function(val) {console.log(val)}(3);
~function(val) {console.log(val)}(3);
4.2 箭头函数(ES6)
var vals = [1, 5, 6, 2, 9, 6, 0];
// 箭头函数最简式:param => expression
vals.sort((a, b) => a - b);
console.log(vals);
// [0, 1, 2, 5, 6, 6, 9]
var getName = (() => "Wango")();
console.log(getName); // Wango
// 箭头函数中只有一条语句且没有{}代码块和return时,返回值为这一条语句的结果
var getName = (() => {"Wango"})();
console.log(getName); // undefined
// 箭头函数的函数体时一个代码块时,值是return语句的值,
// 这里没有return语句,所以值是undefined
函数构造函数(主要用在动态创建和执行代码)和生成器函数暂未涉及
5 函数的参数
- 实参:调用函数时所传递给函数的值
- 形参:定义函数时所列举的变量
- 实参的数量大于形参时,额外的实参不会赋值给任何形参
- 剩余参数(ES6)
// 用...接收多个参数,并将参数放入remaining数组中
// 只有最后一个参数才能时剩余参数,
// 否则会:SyntaxError: Rest parameter must be last formal parameter
function add(first, ...remaining) {
var sum = first;
for (var i = 0; i < remaining.length; i++) {
sum += remaining[i];
}
return sum;
}
console.log(add(1, 2, 3));
- 默认参数(ES6)
// ES6之前处理默认参数的方法
function setInfo(name, age, gender) {
gender = typeof gender === "undefined" ? "Unknown" : gender;
// 或者使用更简洁的判定方式
// gender = gender || "Unknown";
return {
name: name,
age: age,
gender: gender
};
}
console.log(setInfo("Wango", 24, "male"));
// {name: "Wango", age: 24, gender: "male"}
console.log(setInfo("Lily", 25));
// name: "Lily", age: 25, gender: "Unknown"}
// ES6处理默认参数的方法
// 为形参赋值
// 若指定了实参的值,默认值会被覆盖,否则使用默认值
function setInfo(name, age, gender = "Unknown") {
return {
name: name,
age: age,
gender: gender
};
}
console.log(setInfo("Wango", 24, "male"));
// {name: "Wango", age: 24, gender: "male"}
console.log(setInfo("Lily", 25));
// name: "Lily", age: 25, gender: "Unknown"}
对后面的默认参数赋值时可以引用前面的默认参数