JavaScript 编码原则之过程抽象 | 青训营笔记

87 阅读4分钟

这是我参与「第五届青训营 」笔记创作活动的第6天

一、本堂课重点内容:

  1. 过程抽象概念
  2. 高阶函数使用模式
  3. JavaScript 编程范式

二、详细知识点介绍:

过程抽象概念

过程抽象是一种设计模式,它允许将一组相关的操作封装在一起,而不关注这些操作的具体实现细节。这样,我们就可以在使用这些操作的地方,只关注它们的行为而不关心它们的实现。

在 JavaScript 中,过程抽象可以通过函数来实现。函数就是一组封装在一起的操作,可以在需要时调用。通过将实现细节隐藏在函数内部,我们可以避免在调用函数时过多关注细节。

简单来说,过程抽象是一种将实现细节隐藏起来,使得代码更加简洁易懂的技巧。

高阶函数使用模式

高阶函数是指能够接收函数作为参数返回一个函数作为结果的函数。它是一种进阶的过程抽象概念,常用于作为函数装饰器,可以使得代码更加灵活和可重用。

常用高阶函数:

  1. Once: 一个函数只能被调用一次。
    function once(fn) {
        let called = false;
        return function () {
            if (!called) {
                called = true;
                fn.apply(this, arguments);
            }
        }
    }
    let sayHello = once(function () {
        console.log("Hello!");
    });
    sayHello(); // "Hello!"
    sayHello(); // nothing happens
    
  2. Throttle: 函数被调用时,在一个固定的时间间隔内只会被执行一次。
    function throttle(fn, wait) {
        let lastCall = 0;
        return function () {
            let now = Date.now();
            if (now - lastCall < wait) {
                return;
            }
            lastCall = now;
            fn.apply(this, arguments);
        }
    }
    let sayHello = function () {
        console.log("Hello!");
    };
    let throttledSayHello = throttle(sayHello, 1000);
    throttledSayHello(); // "Hello!"
    throttledSayHello(); // nothing happens
    setTimeout(throttledSayHello, 2000); // "Hello!"
    
  3. Debounce: 函数被调用时,在一个固定的时间间隔后才会被执行。
    function debounce(fn, wait) {
        let timeoutId;
        return function () {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(() => {
                fn.apply(this, arguments);
            }, wait);
        }
    }
    let sayHello = function () {
        console.log("Hello!");
    };
    let debouncedSayHello = debounce(sayHello, 1000);
    debouncedSayHello();
    debouncedSayHello();
    setTimeout(debouncedSayHello, 2000); // "Hello!"
    
  4. Consumer /2: 将两个函数组合成一个新的函数,并将结果传递给第二个函数。
    function consumer(fn1, fn2) {
        return function() {
            fn2(fn1.apply(this, arguments));
        }
    }
    let add = (a, b) => a + b;
    let double = x => x * 2;
    let addThenDouble = consumer(add, double);
    console.log(addThenDouble(3,4)); // 14
    
  5. Iterative: 将函数应用于数组中的每个元素。
    function iterate(arr, fn) {
        for (let i = 0; i < arr.length; i++) {
            fn(arr[i]);
        }
    }
    let arr= [1, 2, 3, 4]; 
    let square = x => x * x; 
    iterate(arr, square); // arr is now [1, 4, 9, 16]
    

这些高阶函数都是常用的设计模式,可以用来实现复杂的功能。它们可以帮助开发人员更好地管理函数的执行次数和时间间隔,从而提高程序的性能。

JavaScript 编程范式

JavaScript 编程范式是指对于编写 JavaScript 代码的方式和风格的统称。

Toggle 是一种常见的功能,用来在两种状态之间切换。

在命令式编程范式中,我们通过操作状态变量来实现 toggle 功能。下面的代码是一个命令式的 toggle 实现:

switcher.onclick = function(evt){
  if(evt.target.className === 'on'){
    evt.target.className = 'off';
  }else{
    evt.target.className = 'on';
  }
}

在声明式编程范式中,我们通过描述结果而不是如何计算结果来实现 toggle 功能。下面的代码是一个声明式的 toggle 实现:

function toggle(...actions){
  return function(...args){
    let action = actions.shift();
    actions.push(action);
    return action.apply(this, args);
  }
}

switcher.onclick = toggle(
  evt => evt.target.className = 'off',
  evt => evt.target.className = 'on'
);

Toggle 三态是指一种可以在三种状态之间切换的 toggle 功能,例如三态开关。可以用命令式或声明式编程范式来实现:

function toggle(...actions){
  return function(...args){
    let action = actions.shift();
    actions.push(action);
    return action.apply(this, args);
  }
}

switcher.onclick = toggle(
  evt => evt.target.className = 'warn',
  evt => evt.target.className = 'off',
  evt => evt.target.className = 'on'
);

总之,命令式编程更侧重于具体操作,而声明式编程更侧重于结果。在不同的场景下应用合适的范式可以使代码更简洁,更易于维护。

三、实践练习例子:

过程抽象

假设我们要编写一个函数,它可以对任意数组进行排序。我们可以使用过程抽象来实现这个函数,而不需要关心数组中具体的元素类型。

function sortArray(arr) {
    // 过程抽象:实现了排序算法,但是没有具体实现
    // 可以支持任意类型的数组
    arr.sort();
    return arr;
}

let numbers = [4, 2, 5, 1, 3];
let sortedNumbers = sortArray(numbers);
console.log(sortedNumbers); // [1, 2, 3, 4, 5]

let words = ["dog", "cat", "bird", "ant"];
let sortedWords = sortArray(words);
console.log(sortedWords); // ["ant", "bird", "cat", "dog"]

在这个例子中,我们使用了 JavaScript 的 sort() 方法来实现数组的排序,但是我们并没有详细说明它是如何排序的。这就是过程抽象的一个简单示例,因为我们只关心它能完成排序这个功能,而不关心具体实现细节。

四、课后个人总结:

在学习 JavaScript 编程范式时,我们可以了解到函数式编程适用于纯函数和无副作用的逻辑,声明式编程适用于描述结果。

在学习函数式编程范式时,我们学会了高阶函数的常用使用模式,如Once,Throttle,Debounce,Consumer 和 Iterative 。这些高阶函数都是常用的设计模式,可以用来实现复杂的功能。

最后,在学习状态管理时,我了解了命令式编程范式、声明式编程范式和三态的关系,命令式编程范式可以实现复杂的逻辑,但可能会导致代码难以维护,而声明式编程范式可以使代码更简洁,更易于维护,但可能难以实现复杂的逻辑。三态可以让程序更加灵活,使用命令式或声明式编程范式都可以实现三态。

五、引用参考:

JavaScript 编码原则之过程抽象