JavaScript - 関数型プログラミングで何が重要ですか?

王林
リリース: 2024-08-05 22:57:22
オリジナル
941 人が閲覧しました

JavaScript は、複数のプログラミング パラダイムをサポートする多用途言語です。これらのパラダイムを理解することは、開発者がさまざまな問題を解決するための最適なアプローチを選択するのに役立ちます。主なプログラミング パラダイムには次のものがあります。

  1. 命令型: タスクを実行する方法 (段階的に) に焦点を当てます。
  2. 手続き型: 命令型と似ていますが、再利用可能なプロシージャが含まれます。
  3. オブジェクト指向: コードを再利用可能なオブジェクトに編成します。
  4. 宣言的: プログラムが達成すべきことに焦点を当てます。
  5. 関数型: 計算を数学関数のように扱います (今日の番組の主役です!)。

この記事では、純粋関数、高階関数、不変性を強調する強力なパラダイムである JavaScript での関数型プログラミングについて説明します。

1. 純粋な関数

純粋関数とは、目に見える副作用がなく、出力値が入力値によってのみ決定される関数です。

決定的: 同じ入力に対して、関数は常に同じ出力を生成します。
副作用なし: この関数は外部状態 (グローバル変数、入力パラメーターなど) を変更しません。

:

// Pure function
function add(a, b) {
  return a + b;
}

// Impure function
let count = 0;
function increment() {
  count += 1;
  return count;
}
ログイン後にコピー

上記の例では、add は同じ入力に対して常に同じ結果を返し、外部状態を変更しないため、純粋な関数です。対照的に、increment は外部変数 count を変更するため、不純な関数です。

2. 高階関数

高階関数は、他の関数を引数として受け取ったり、結果として関数を返したりできる関数です。

引数としての関数: 関数を入力パラメーターとして受け入れることができます。
戻り値としての関数: 関数を出力として返すことができます。

:

// Higher-order function
function applyOperation(a, b, operation) {
  return operation(a, b);
}

// Function to be used as an argument
function multiply(x, y) {
  return x * y;
}

// Using the higher-order function
const result = applyOperation(5, 3, multiply); // Output: 15
ログイン後にコピー

この例では、applyOperation は関数 (操作) を引数として取るため、高階関数です。

3. 不変性

不変性とは、データが一度作成されると変更できないという概念を指します。既存のデータ構造を変更する代わりに、新しいデータ構造が作成されます。

変更なし: データ構造は作成後に変更されません。
コピーと変更: 操作により、必要な変更を加えた新しいデータ構造が作成されます。

:

// Mutable object
let user = { name: 'Alice', age: 25 };
user.age = 26; // Mutation

// Immutable object using Object.assign
const newUser = Object.assign({}, user, { age: 26 });
console.log(newUser); // Output: { name: 'Alice', age: 26 }
ログイン後にコピー

この例では、ユーザー オブジェクトを直接変更する代わりに、更新された年齢で新しいオブジェクト newUser が作成されます。

関数型プログラミングの重要な点は何ですか?

JavaScript - What

さて、コードを作成していると想像してください (ここでは完全な比喩になりますのでご了承ください)。命令型プログラミングは、「玉ねぎをみじん切りにし、炒めて、ニンニクを加えて...」という段階的な指示を与えて食事を調理するようなものです。一方、関数型プログラミングは、専門のシェフのチームを組織するようなものです。それぞれが料理の一部を完成させます。あなたが望むものを彼らに伝えるだけで、出来上がりです。料理の魔法が起こります。

コードが for ループと if ステートメントが複雑に絡み合ったものだと感じたことはありませんか?さあ、シートベルトを締めて、JavaScript の関数型プログラミング (FP) の世界への魔法の旅に出発しようとしているからです。スパゲッティ コードをグルメ料理に変えるようなものです。 ?➡️?

いくつかのおいしいコード例を使って、このキッチンの魔法が実際に動作する様子を見てみましょう!

関数型プログラミングの利点を理解するために、より伝統的な命令型スタイルと関数型プログラミングを比較してみましょう。

配列変換: 前菜

命令型スタイル (昔ながらのキッチン):

const veggies = ['carrot', 'broccoli', 'cauliflower'];
const cookedVeggies = [];
for (let i = 0; i < veggies.length; i++) {
    cookedVeggies.push(`cooked ${veggies[i]}`);
}
ログイン後にコピー

機能的なスタイル (モダンなキッチン):

const veggies = ['carrot', 'broccoli', 'cauliflower'];
const cookedVeggies = veggies.map(veggie => `cooked ${veggie}`);
ログイン後にコピー

そのぎこちない for ループを洗練されたワンライナーにどのように変えたかわかりますか?それが FP の利点です。副料理長 (マップ) に繰り返しの作業をすべてやってもらっているようなものです!

パンケーキスタックの逆転: 朝食タワーをひっくり返す

あなたがパンケーキアーティストで、それぞれに文字が書かれたパンケーキのそびえ立つ山を作成したところだと想像してください。ここで、スタック全体を反転してメッセージを下から上に読みたいとします。コードでこれを行う方法を見てみましょう!

命令型スタイル (昔ながらのパンケーキひっくり返し):

function flipPancakeStack(stack) {
    let flippedStack = '';
    for (let i = stack.length - 1; i >= 0; i--) {
        flippedStack += stack[i];
    }
    return flippedStack;
}

const originalStack = "PANCAKE";
const flippedStack = flipPancakeStack(originalStack);
console.log(flippedStack); // "EKACNAP"
ログイン後にコピー

このアプローチでは、各パンケーキをスタックの一番上から一番下まで手動で 1 つずつ裏返します。それは機能しますが、少し手間がかかりますね。高いスタックをこのようにひっくり返すことを想像してみてください!

機能的なスタイル (滑らかなパンケーキをひっくり返すマシン):

const flipPancakeStack = str => 
    str.split('').reduce((reversed, char) => char + reversed, '');

const originalStack = "PANCAKE";
const flippedStack = flipPancakeStack(originalStack);
console.log(flippedStack); // "EKACNAP"
ログイン後にコピー

Wow! Look at that smooth operator! ? We've turned our string into an array of characters, then used the reduce function to flip our pancake in one sweeping motion. Here's what's happening:

  1. split('') turns our string into an array of characters.
  2. reduce goes through each character, adding it to the front of our accumulating result.
  3. We start with an empty string '' and build it up, character by character.

It's like having a fancy pancake-flipping robot that assembles the pancake in reverse as it goes along. No manual flipping required!

The Beauty of Functional Flipping

Notice how our functional approach doesn't use any loops or temporary variables. It's a single expression that flows from left to right. This makes it:

  1. More readable: Once you're used to reduce, this reads almost like English.
  2. Immutable: We're not changing any existing data, just creating new strings.
  3. Shorter: We've reduced our function to a single, powerful line.

Remember, in the kitchen of code, it's not just about getting the job done – it's about style, efficiency, and leaving a clean workspace. Our functional pancake flipper does all three!

Main Course: Curry Transformation Feast

Now, let's spice things up with some Indian cuisine! Imagine we're running a bustling Indian restaurant, and we need to transform our thali menu. We want to adjust spice levels, filter out dishes based on dietary preferences, and format the names for our trendy menu board.

Imperative Style (The frazzled curry chef):

const thaliMenu = [
    { name: 'Butter Chicken', spiceLevel: 2, vegetarian: false, available: true },
    { name: 'Palak Paneer', spiceLevel: 1, vegetarian: true, available: true },
    { name: 'Lamb Vindaloo', spiceLevel: 4, vegetarian: false, available: false },
    { name: 'Dal Makhani', spiceLevel: 1, vegetarian: true, available: true },
    { name: 'Chicken Tikka Masala', spiceLevel: 3, vegetarian: false, available: true }
];

const veggieSpicyMenu = [];
for (let i = 0; i < thaliMenu.length; i++) {
    if (thaliMenu[i].vegetarian && thaliMenu[i].available) {
        let dish = {
            name: thaliMenu[i].name.toUpperCase().replace(/ /g, '_'),
            spiceLevel: thaliMenu[i].spiceLevel + 1
        };
        if (dish.spiceLevel > 5) dish.spiceLevel = 5;
        veggieSpicyMenu.push(dish);
    }
}
ログイン後にコピー

Functional Style (The Michelin-star tandoor master):

const thaliMenu = [
    { name: 'Butter Chicken', spiceLevel: 2, vegetarian: false, available: true },
    { name: 'Palak Paneer', spiceLevel: 1, vegetarian: true, available: true },
    { name: 'Lamb Vindaloo', spiceLevel: 4, vegetarian: false, available: false },
    { name: 'Dal Makhani', spiceLevel: 1, vegetarian: true, available: true },
    { name: 'Chicken Tikka Masala', spiceLevel: 3, vegetarian: false, available: true }
];

const veggieSpicyMenu = thaliMenu
    .filter(dish => dish.vegetarian && dish.available)
    .map(dish => ({
        name: dish.name.toUpperCase().replace(/ /g, '_'),
        spiceLevel: Math.min(dish.spiceLevel + 1, 5)
    }));
ログイン後にコピー

?✨ We've just transformed our thali menu with the grace of a yoga master. The functional approach reads like a recipe from a classic Indian cookbook: "Filter the vegetarian and available dishes, then map them to new objects with formatted names and increased spice levels." It's a recipe for code that's as aromatic and delightful as the dishes it describes!

Dessert: Async Chai Brewing Symphony

For our final course, let's steep ourselves in the art of asynchronous chai brewing. Imagine we're creating a smart chai maker that needs to check tea leaves, heat water, and blend spices, all in perfect harmony.

Imperative Style (The flustered chai wallah):

function brewChai(teaType, callback) {
    checkTeaLeaves(teaType)
        .then(leaves => {
            if (leaves.quality === 'good') {
                heatWater(leaves.requiredTemperature)
                    .then(water => {
                        blendSpices(teaType)
                            .then(spices => {
                                const chai = mixChaiIngredients(leaves, water, spices);
                                callback(null, chai);
                            })
                            .catch(error => callback(error));
                    })
                    .catch(error => callback(error));
            } else {
                callback(new Error('Tea leaves are not of good quality'));
            }
        })
        .catch(error => callback(error));
}
ログイン後にコピー

Functional Style (The serene chai master):

const brewChai = teaType =>
    checkTeaLeaves(teaType)
        .then(leaves => 
            leaves.quality === 'good'
                ? Promise.all([
                    Promise.resolve(leaves),
                    heatWater(leaves.requiredTemperature),
                    blendSpices(teaType)
                  ])
                : Promise.reject(new Error('Tea leaves are not of good quality'))
        )
        .then(([leaves, water, spices]) => mixChaiIngredients(leaves, water, spices));
ログイン後にコピー

Wah, what a beautiful symphony! ?? We've just orchestrated a complex chai brewing process into a smooth, promise-based operation. It's like watching a graceful kathak dance – each step flows seamlessly into the next, creating a perfect blend of flavors and aromas.

The Secret Masala: Why FP is the Chef's Kiss ?‍??

  • Readability: FP code often reads like a story. "Filter this, map that, reduce those." It's like writing a recipe for your future self (or your poor colleague who has to maintain your code).
  • Predictability: Pure functions always return the same output for a given input. No surprises, no "it worked on my machine" mysteries.
  • Testability: Since FP emphasizes pure functions, testing becomes a breeze. It's like being able to taste each ingredient separately before combining them.
  • Conciseness: As we've seen, FP can often express complex operations in just a few lines. Less code means fewer bugs and easier maintenance.
  • Composition: You can combine simple functions to create complex behaviors, like stacking Lego bricks to build a castle. ?

Wrapping Up Our Functional Feast

There you have it, folks! We've transformed our code from a fast-food joint to a Michelin-star restaurant. Functional programming in JavaScript isn't just about writing less code; it's about writing code that's easier to understand, test, and maintain.

Remember, you don't have to go full Gordon Ramsay and remake your entire codebase overnight. Start small – try using map instead of a for-loop, or break a complex function into smaller, pure functions. Before you know it, you'll be whipping up functional programming delicacies that would make any code chef proud!

Now, go forth and func-tionalize! May your code be pure, your functions be high-order, and your bugs be few.

Happy coding, and may the func be with you! ??
JavaScript - What

以上がJavaScript - 関数型プログラミングで何が重要ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート