JavaScriptfunction

LearningJavaScriptfunction 定义, 调用, parameter传递, return value and advanced features

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:

  1. creation一个calculatefunction, 接受三个parameter: 两个number and 一个operation符 ('+', '-', '*', '/') , 返回计算结果
  2. creation一个isPrimefunction, 判断一个number is 否 for 质数
  3. creation一个filterEvenNumbersfunction, using剩余parameter and 箭头function, filter出arrayin 偶数
  4. creation一个createGreetingfunction, 返回一个function, 该function用于生成问候语
  5. 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

1. creation一个factorialfunction, 计算一个number 阶乘:
  • 阶乘 定义: n! = n × (n-1) × (n-2) × ... × 1
  • 0! = 1
  • using递归 or 循环implementation
2. creation一个reverseStringfunction, 反转一个string:
  • 例such as: "Hello" → "olleH"
  • 可以usingarraymethod or 循环implementation
3. creation一个findMaxfunction, using剩余parameter, 找出一组numberin 最 big 值:
  • 例such as: findMax(1, 5, 3, 9, 2) → 9
4. creation一个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 ascalculateTotal)
  • for 于返回boolean值 function, usingis or has before 缀 (such asisValid)
  • for 于operationfunction, using动词开头 (such asgetUser)

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范式