1. functionoverview
function is JavaScriptin core concepts, is 一段可重复using code块, 用于执行specific task. function可以接受输入parameter, 执行operation, 并返回结果. in JavaScriptin, function is 一etc.公民, 这意味着function可以像other值一样被传递, 赋值给variable, serving asparameter传递给otherfunction, 以及serving asfunction return value.
1.1 function 作用
- code复用: 避免重复writing相同 code
- module化: 将 complex issues分解 for 更 small , 可management 部分
- abstraction: 隐藏implementation细节, 只暴露必要 interface
- 可maintenance性: 使code更加structure化, 易于understanding and maintenance
2. function定义
in JavaScriptin, has many 种定义function 方式: function声明, function表达式, 箭头function and functionconstructfunction.
2.1 function声明
function声明 is 最common function定义方式, usingfunction关键字 after 跟function名:
// function声明
function add(a, b) {
return a + b;
}
// 调用function
let result = add(3, 5);
console.log(result); // 8
function声明具 has function提升 features, 这意味着可以 in function声明之 before 调用function:
// in function声明之 before 调用function
let result = add(3, 5);
console.log(result); // 8
// function声明
function add(a, b) {
return a + b;
}
2.2 function表达式
function表达式 is 将function赋值给variable 方式, function可以 has 名称也可以没 has 名称 (匿名function) :
// 匿名function表达式
let add = function(a, b) {
return a + b;
};
// 命名function表达式
let multiply = function multiply(a, b) {
return a * b;
};
// 调用function
console.log(add(3, 5)); // 8
console.log(multiply(3, 5)); // 15
function表达式不具 has function提升 features, 必须先定义 after 调用:
// error: add is not defined
// let result = add(3, 5);
// console.log(result);
// function表达式
let add = function(a, b) {
return a + b;
};
// 正确: 先定义 after 调用
let result = add(3, 5);
console.log(result); // 8
2.3 箭头function (ES6+)
箭头function is ES6引入 一种更简洁 function定义方式, using=>符号:
// basic箭头function
let add = (a, b) => {
return a + b;
};
// 简写形式 (当只 has 一个表达式时)
let multiply = (a, b) => a * b;
// 当只 has 一个parameter时, 可以省略括号
let square = x => x * x;
// 当没 has parameter时, 需要using空括号
let greet = () => console.log('Hello!');
// 调用function
console.log(add(3, 5)); // 8
console.log(multiply(3, 5)); // 15
console.log(square(4)); // 16
greet(); // Hello!
箭头function has 以 under 特点:
- 没 has 自己
this绑定 - 不能用作constructfunction
- 没 has
argumentsobject - 语法更简洁
2.4 functionconstructfunction
可以usingFunctionconstructfunctioncreationfunction, 但这种方式不常用, 因 for 它会导致code难以阅读 and maintenance:
// usingFunctionconstructfunctioncreationfunction
let add = new Function('a', 'b', 'return a + b');
// 调用function
console.log(add(3, 5)); // 8
3. function调用
function定义 after , 需要through调用来执行它. function调用 basic语法 is function名 after 跟括号, 括号in可以package含parameter.
3.1 basic调用
function greet(name) {
console.log(`Hello, ${name}!`);
}
// 调用function
greet('张三'); // Hello, 张三!
3.2 serving asobjectmethod调用
当functionserving asobject property时, 称 for method. method调用时, this指向调用该method object:
const person = {
name: '张三',
age: 30,
greet: function() {
console.log(`Hello, my name is ${this.name}!`);
}
};
// 调用objectmethod
person.greet(); // Hello, my name is 张三!
3.3 serving asconstructfunction调用
usingnew关键字调用function时, function成 for constructfunction, 用于creation new object:
function Person(name, age) {
this.name = name;
this.age = age;
this.greet = function() {
console.log(`Hello, my name is ${this.name}!`);
};
}
// usingconstructfunctioncreation new object
const person1 = new Person('张三', 30);
const person2 = new Person('李四', 25);
// 调用objectmethod
person1.greet(); // Hello, my name is 张三!
person2.greet(); // Hello, my name is 李四!
3.4 usingcall() and apply()调用
call() and apply()method允许我们显式指定this 值来调用function:
function greet() {
console.log(`Hello, my name is ${this.name}!`);
}
const person1 = { name: '张三' };
const person2 = { name: '李四' };
// usingcall()调用function, 第一个parameter is this 值
console.log('usingcall():');
greet.call(person1); // Hello, my name is 张三!
// usingapply()调用function, 第一个parameter is this 值
console.log('usingapply():');
greet.apply(person2); // Hello, my name is 李四!
call() and apply() 区别 in 于parameter传递方式:
function add(a, b) {
return a + b;
}
// usingcall()传递parameter, parameter逐个列出
let result1 = add.call(null, 3, 5);
console.log(result1); // 8
// usingapply()传递parameter, parameterserving asarray
let result2 = add.apply(null, [3, 5]);
console.log(result2); // 8
3.5 usingbind()creation绑定function
bind()methodcreation一个 new function, 该function this值被绑定 to 指定 值:
function greet() {
console.log(`Hello, my name is ${this.name}!`);
}
const person = { name: '张三' };
// creation绑定function
const boundGreet = greet.bind(person);
// 调用绑定function
boundGreet(); // Hello, my name is 张三!
4. parameter传递
function可以接受parameter, parameter is function执行所需 输入值. in JavaScriptin, parameter传递 is 按值传递 , 但 for 于object and arrayetc.引用class型, 传递 is 引用 值.
4.1 basicparameter
function add(a, b) {
return a + b;
}
// 传递parameter
let result = add(3, 5);
console.log(result); // 8
4.2 默认parameter (ES6+)
ES6引入了默认parameter, 允许 for functionparameter设置默认值:
// using默认parameter
function greet(name = '匿名') {
console.log(`Hello, ${name}!`);
}
// 调用function时不传递parameter, using默认值
greet(); // Hello, 匿名!
// 调用function时传递parameter, 覆盖默认值
greet('张三'); // Hello, 张三!
4.3 剩余parameter (ES6+)
剩余parameter允许function接受任意数量 parameter, using...语法:
// using剩余parameter
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
// 传递任意数量 parameter
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15
console.log(sum()); // 0
4.4 argumentsobject
in function in 部, 可以usingargumentsobject访问传递给function 所 has parameter, 无论function定义了how many个parameter:
// usingargumentsobject
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
// 传递任意数量 parameter
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15
注意: 箭头function没 has 自己 argumentsobject.
4.5 parameter解构 (ES6+)
ES6引入了parameter解构, 允许 from object or arrayin提取值serving asfunctionparameter:
// object解构parameter
function greet({ name, age }) {
console.log(`Hello, ${name}! You are ${age} years old.`);
}
// 调用function
const person = { name: '张三', age: 30 };
greet(person); // Hello, 张三! You are 30 years old.
// array解构parameter
function calculate([a, b, c]) {
return a + b * c;
}
// 调用function
const numbers = [1, 2, 3];
console.log(calculate(numbers)); // 7
5. return value
function可以usingreturn语句return value, return value is function执行 结果. such as果function没 has 明确 return语句, or 者return语句 after 面没 has 值, function会返回undefined.
5.1 basicreturn value
function add(a, b) {
return a + b;
}
// 获取functionreturn value
let result = add(3, 5);
console.log(result); // 8
5.2 提 before 返回
return语句会立即终止function执行, 返回 to 调用者:
function isEven(num) {
if (num % 2 === 0) {
return true; // 提 before 返回
}
return false;
}
console.log(isEven(4)); // true
console.log(isEven(5)); // false
5.3 返回 complex 值
function可以返回任何class型 值, includingobject, array, functionetc.:
// 返回object
function createPerson(name, age) {
return {
name: name,
age: age,
greet: function() {
console.log(`Hello, my name is ${this.name}!`);
}
};
}
// 返回array
function getNumbers() {
return [1, 2, 3, 4, 5];
}
// 返回function
function createMultiplier(factor) {
return function(number) {
return number * factor;
};
}
// 调用function
const person = createPerson('张三', 30);
person.greet(); // Hello, my name is 张三!
const numbers = getNumbers();
console.log(numbers); // [1, 2, 3, 4, 5]
const double = createMultiplier(2);
console.log(double(5)); // 10
6. function作用域 and 闭package
6.1 function作用域
function作用域 is 指variable in function in 部声明时, 只能 in function in 部访问, function out 部无法访问:
function example() {
// function in 部variable
let insideVar = ' in 部variable';
console.log(insideVar); // in 部variable
}
// 调用function
example();
// 尝试 in function out 部访问 in 部variable
// console.log(insideVar); // error: insideVar is not defined
6.2 闭package
闭package is 指functionable to访问其词法作用域之 out variable, 即使该function in 其词法作用域之 out 被调用:
function createCounter() {
let count = 0; // 闭packagevariable
return {
increment: function() {
count++;
return count;
},
decrement: function() {
count--;
return count;
},
getCount: function() {
return count;
}
};
}
// creation计数器
const counter = createCounter();
// 调用method
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
console.log(counter.getCount()); // 1
// 闭packagevariablecount in function out 部无法直接访问
// console.log(count); // error: count is not defined
闭package application场景:
- data私 has 化: 保护variable不被 out 部访问 and modify
- function工厂: creation具 has specificbehavior function
- module化: implementationmodule模式, encapsulationcode
7. 箭头function 特殊features
7.1 this绑定
箭头function没 has 自己 this绑定, 它会inheritance out 层作用域 this值:
// 普通function this绑定
const person = {
name: '张三',
greet: function() {
console.log(`Hello, my name is ${this.name}!`);
// 普通function, this指向全局object or undefined (严格模式)
setTimeout(function() {
console.log(`Hello again, my name is ${this.name}!`); // undefined
}, 1000);
}
};
// 箭头function this绑定
const person2 = {
name: '李四',
greet: function() {
console.log(`Hello, my name is ${this.name}!`);
// 箭头function, thisinheritance自 out 层作用域
setTimeout(() => {
console.log(`Hello again, my name is ${this.name}!`); // 李四
}, 1000);
}
};
// 调用method
person.greet(); // Hello, my name is 张三! 然 after is Hello again, my name is undefined!
person2.greet(); // Hello, my name is 李四! 然 after is Hello again, my name is 李四!
7.2 没 has argumentsobject
箭头function没 has 自己 argumentsobject, 但可以using剩余parameter:
// 普通function has argumentsobject
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
// 箭头function没 has argumentsobject, using剩余parameter
const sumArrow = (...numbers) => {
return numbers.reduce((total, num) => total + num, 0);
};
console.log(sum(1, 2, 3)); // 6
console.log(sumArrow(1, 2, 3, 4)); // 10
7.3 不能用作constructfunction
箭头function不能usingnew关键字调用, 否则会抛出error:
// 箭头function
const Person = (name, age) => {
this.name = name;
this.age = age;
};
// error: Cannot call a function which has a non-object prototype 'undefined' as a constructor
// const person = new Person('张三', 30);
// console.log(person);
实践case: functionapplication
creation一个JavaScript程序, usingfunctionimplementation以 under functions:
- creation一个
calculatefunction, 接受三个parameter: 两个number and 一个operation符 ('+', '-', '*', '/') , 返回计算结果 - creation一个
isPrimefunction, 判断一个number is 否 for 质数 - creation一个
filterEvenNumbersfunction, using剩余parameter and 箭头function, filter出arrayin 偶数 - creation一个
createGreetingfunction, 返回一个function, 该function用于生成问候语 - test所 has function functions
// 实践case: functionapplication
// 1. calculatefunction
function calculate(a, b, operator) {
switch (operator) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
if (b === 0) {
return 'error: 除数不能 for 零';
}
return a / b;
default:
return 'error: 无效 operation符';
}
}
// 2. isPrimefunction
function isPrime(num) {
if (num <= 1) return false;
if (num === 2) return true;
if (num % 2 === 0) return false;
for (let i = 3; i <= Math.sqrt(num); i += 2) {
if (num % i === 0) {
return false;
}
}
return true;
}
// 3. filterEvenNumbersfunction
const filterEvenNumbers = (...numbers) => {
return numbers.filter(num => num % 2 === 0);
};
// 4. createGreetingfunction
function createGreeting(language) {
switch (language) {
case 'zh':
return name => `你 good , ${name}!`;
case 'en':
return name => `Hello, ${name}!`;
case 'es':
return name => `¡Hola, ${name}!`;
default:
return name => `Hello, ${name}!`;
}
}
// 5. testfunction
console.log('=== testcalculatefunction ===');
console.log(calculate(5, 3, '+')); // 8
console.log(calculate(5, 3, '-')); // 2
console.log(calculate(5, 3, '*')); // 15
console.log(calculate(5, 3, '/')); // 1.666...
console.log(calculate(5, 0, '/')); // error: 除数不能 for 零
console.log('\n=== testisPrimefunction ===');
console.log(isPrime(2)); // true
console.log(isPrime(3)); // true
console.log(isPrime(4)); // false
console.log(isPrime(17)); // true
console.log(isPrime(18)); // false
console.log('\n=== testfilterEvenNumbersfunction ===');
console.log(filterEvenNumbers(1, 2, 3, 4, 5, 6)); // [2, 4, 6]
console.log(filterEvenNumbers(10, 15, 20, 25, 30)); // [10, 20, 30]
console.log('\n=== testcreateGreetingfunction ===');
const greetChinese = createGreeting('zh');
const greetEnglish = createGreeting('en');
const greetSpanish = createGreeting('es');
console.log(greetChinese('张三')); // 你 good , 张三!
console.log(greetEnglish('John')); // Hello, John!
console.log(greetSpanish('Juan')); // ¡Hola, Juan!
互动练习: functionchallenges
factorialfunction, 计算一个number 阶乘: - 阶乘 定义: n! = n × (n-1) × (n-2) × ... × 1
- 0! = 1
- using递归 or 循环implementation
reverseStringfunction, 反转一个string: - 例such as: "Hello" → "olleH"
- 可以usingarraymethod or 循环implementation
findMaxfunction, using剩余parameter, 找出一组numberin 最 big 值: - 例such as: findMax(1, 5, 3, 9, 2) → 9
debouncefunction, implementationfunction防抖: - function防抖: in 一定时间 in , many 次调用function只会执行最 after 一次
- 接受一个function and latency时间serving asparameter, 返回一个 new function
8. functionbest practices
8.1 命名规范
- usingdescribes性 function名, 清晰表达function 用途
- using驼峰命名法 (such as
calculateTotal) - for 于返回boolean值 function, using
isorhasbefore 缀 (such asisValid) - for 于operationfunction, using动词开头 (such as
getUser)
8.2 functiondesign
- function应该只做一件事, 并且做 good
- function应该保持简 short , 通常不超过50行
- functionparameter应该适量, 通常不超过3-4个
- using默认parameter and 解构parameterimprovingcode readable 性
- for 于 complex function, 添加comment说明functions and parameter
8.3 performance考虑
- 避免 in 循环increationfunction
- for 于频繁调用 function, 考虑usingcache
- 合理using闭package, 避免memory泄漏
- for 于 big 型application, 考虑usingfunction式programming范式