ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript のファクトリー関数の詳細なサンプルコード

JavaScript のファクトリー関数の詳細なサンプルコード

黄舟
黄舟オリジナル
2017-03-22 14:40:002000ブラウズ

いわゆるファクトリー関数は、これらの組み込み関数がすべてクラス オブジェクトであることを意味し、それらを呼び出すと、実際にはクラス インスタンスが作成されます。この記事では主にJavaScriptファクトリー関数を紹介しますので、必要な方は参考にしてみてください

jQueryを学習する際に「ファクトリー関数」という概念をよく目にしますが、「ファクトリー関数」とは一体何なのか? 「毛織物? 「いわゆるファクトリー関数とは、これらの組み込み関数がすべてクラス オブジェクトであることを意味します。これらを呼び出すと、実際にはクラス インスタンスが作成されます。」という概念を見てみましょう。これは、この関数を呼び出すと、実際にクラスを使用してオブジェクトを作成し、そのオブジェクトを返すことを意味します。 Javascript 自体は厳密なオブジェクト指向言語ではない (クラスを含まない) ため、実際には Javascript には厳密な「ファクトリー関数」はありませんが、JavaScript では関数を使用してクラスをシミュレートできます。 最初に new キーワードを使用してオブジェクトを作成します。obj は Object のインスタンスに相当します。クラスを通じてオブジェクトをインスタンス化し、そのオブジェクトに対応する属性を与え、最後にオブジェクトを返します。この関数を呼び出すことでオブジェクトを作成できます。この場合、ファクトリー関数は非常に理解しやすいものです。

1、これは関数です。

2、オブジェクトの作成に使用されます。

3. 「生成される」関数はすべて「標準部品」です (同じプロパティを持っています)

関数とオブジェクトを学習し、それらを組み合わせて使用​​することなしに JavaScript プログラマーになることはできません。ブロックを構築するには、コンポジションと呼ばれる強力なオブジェクト パラダイムから始める必要があります。今日は、ファクトリ関数を使用して関数、オブジェクト、Promise を構成するための慣用的なパターンをいくつか見ていきます。

複合モード

は、サブオブジェクトのバッチをツリー構造に編成し、トップレベルのコマンドでツリー内のすべてのオブジェクトを操作します。関数がオブジェクトを返すとき、それをファクトリ関数と呼びます。 簡単な例を見てみましょう。

function createJelly() {
 return {
 type: 'jelly',
 colour: 'red'
 scoops: 3
 };
 }

いくつかの例を通してご紹介しましょう。

このファクトリー関数を呼び出すたびに、新しいゼリーオブジェクトインスタンスが返されます。注意すべき重要な点は、ファクトリー関数名の前に create を付ける必要はありませんが、そうすることで関数の意図が他の人にとってより明確になるということです。同じことが type 属性にも当てはまりますが、一般に、これはプログラムのオブジェクトを区別するのに役立ちます。


1. パラメータ付きのファクトリ関数

すべての関数と同様に、パラメータを通じてファクトリ関数 (icecream アイスクリーム) を定義でき、返されたオブジェクトの

model

を変更するために使用できます。

function createIceCream(flavour='Vanilla') {
 return {
 type: 'icecream',
 scoops: 3,
 flavour
 }
 }
理論的には、何百もの引数を持つファクトリ関数を使用して、深くネストされたオブジェクトのエンボイを返すことができますが、これからわか​​るように、それは合成の本質ではまったくありません。

2. ファクトリ関数の結合

ファクトリ関数内に別のファクトリ関数を定義すると、複雑なファクトリ関数をより小さな再利用可能なフラグメントに分割するのに役立ちます。

たとえば、前のゼリー (jelly) およびアイスクリーム (アイスクリーム) ファクトリ関数によって定義されたデザート (デザート) ファクトリ関数を作成できます。

 function createDessert() {
 return {
 type: 'dessert',
 bowl: [
 createJelly(),
 createIceCream()
 ]
 };
 }

ファクトリ関数を組み合わせて任意の複雑なオブジェクトを構築できます。その場合、new や this を組み合わせて使用​​する必要はありません。オブジェクトは、is-a (is) の代わりに has-a (has) 関係で表すことができます。つまり、

継承

の代わりに合成を使用して実装できます。
たとえば、継承を使用します。

 // A trifle *is a* dessert 蛋糕*是*甜点
 function Trifle() {
 Dessert.apply(this, arguments);
 }
 Trifle.prototype = Dessert.prototype;
 // 或者
 class Trifle extends Dessert {
 constructor() {
 super();
 }
 }

同じ意味を組み合わせパターンで表現できます。

 // A trifle *has* layers of jelly, custard and cream. It also *has a* topping.
 // 蛋糕 *有* 果冻层,奶酪层和奶油层,顶部还 *有* 装饰配料。
 function createTrifle() {
 return {
 type: 'trifle',
 layers: [
 createJelly(),
 createCustard(),
 createCream()
 ],
 topping: createAlmonds()
 };
 }

3. 非同期ファクトリー関数

すべてのファクトリーがすぐにデータを返すわけではありません。たとえば、最初にデータを取得する必要がある人もいます。このような場合、Promise を返してファクトリ関数を定義できます。

function getMeal(menuUrl) {
 return new Promise((resolve, reject) => {
 fetch(menuUrl)
 .then(result => {
 resolve({
 type: 'meal',
 courses: result.json()
 });
 })
 .catch(reject);
 });
 }

この深くネストされたインデントにより、非同期ファクトリーの読み取りとテストが困難になる可能性があります。多くの場合、次のように記述できるように、それらを複数の異なるファクトリーに分割すると便利です。

function getMeal(menuUrl) {
 return fetch(menuUrl)
 .then(result => result.json())
 .then(json => createMeal(json));
 }
 function createMeal(courses=[]) {
 return {
 type: 'meal',
 courses
 };
 }

もちろん、

コールバック関数

を使用することもできますが、ファクトリ関数を定義するために Promise を返す Promise.all のようなツールがすでにあります。

 function getWeeksMeals() {
 const menuUrl = 'jsfood.com/';
 return Promise.all([
 getMeal(`${menuUrl}/monday`),
 getMeal(`${menuUrl}/tuesday`),
 getMeal(`${menuUrl}/wednesday`),
 getMeal(`${menuUrl}/thursday`),
 getMeal(`${menuUrl}/friday`)
 ]);
 }
これらのファクトリーが非同期作業を行って Promise を返すことを示すために、命名規則として create の代わりに get を使用します。

    4.函数和方法

    到目前为止,我们还没有看到任何工厂用方法返回对象,这是故意的。这是因为一般来说,我们不需要这么做。工厂允许我们从计算中分离我们的数据。这意味着我们总是能够将对象序列化为JSON,这对于在会话之间持久化,通过HTTP或WebSockets发送它们,并将它们放入数据存储很重要。

    例如,不是在 jelly(果冻) 对象上定义 eat 方法,我们可以定义一个新的函数,它接受一个对象作为参数并返回一个修改的版本。 

function eatJelly(jelly) {
 if(jelly.scoops > 0) {
 jelly.scoops -= 1;
 }
 return jelly;
 }

    一点点句法帮助使这是一个可行的模式,那些喜欢编程而不改变数据结构的人。对于那些喜欢编程而不改变数据结构的人来说,使用 ES6 的 ... 语法 是一个可行的模式。   

 function eat(jelly) {
 if(jelly.scoops > 0) {
 return { ...jelly, scoops: jelly.scoops - 1 };
 } else {
 return jelly;
 }
 }

    现在,不是这样写:

 import { createJelly } from './jelly';
 createJelly().eat();

    而是这样写   

 import { createJelly, eatJelly } from './jelly';
 eatJelly(createJelly());

    最终结果是一个函数,它接受一个对象并返回一个对象。我们称之为返回对象的函数是什么? 一个工厂!  

    5.高级工厂

    将工厂传递给 高阶函数 ,这将给我们带来巨大的控制力。例如,我们可以使用这个概念来创建一个增强的对象。   

 function giveTimestamp(factory) {
 return (...args) => {
 const instance = factory(...args);
 const time = Date.now();
 return { time, instance };
 };
 }
 const createOrder = giveTimestamp(function(ingredients) {
 return {
 type: 'order',
 ingredients
 };
 });

    这个增强的对象采用一个现有工厂,并将其包装以创建返回带有时间戳实例的工厂。或者,如果我们想要确保一个工厂返回不可变的对象,我们可以用 freezer 来增强它。    

 function freezer(factory) {
 return (...args) => Object.freeze(factory(...args)));
 }
 const createImmutableIceCream = freezer(createIceCream);
 createImmutableIceCream('strawberry').flavour = 'mint'; // Error!

    6.结论

    作为一个 聪明的程序员 曾经说过:从没有抽象比错误的抽象更容易回收。JavaScript项目有一个趋势,变得难以测试和重构,因为我们经常鼓励使用复杂的抽象层。原型和类实现一个简单的想法使用复杂和不人性的工具,如 new 和 this ,即使现在,这仍然引起 各种各样的困惑 -几年后他们被添加到语言。对象和函数对于来自大多数语言背景的程序员来说是有意义的,并且都是JavaScript中的原始类型,所以可以说工厂不是抽象的!对象和函数对来自大多数背景的程序员都有意义,并且都是JavaScript中的原始类型,所以可以说工厂不是抽象的!使用这些简单的构建块使得我们的代码对于没有经验的程序员更加友好,这绝对是我们应该关心的事情。工厂鼓励我们用原始数据来模拟复杂和异步数据,原始数据具有组合的自然能力,而不强迫我们去做一些高级抽象。 当我们坚持简单时,JavaScript更甜蜜!

以上がJavaScript のファクトリー関数の詳細なサンプルコードの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。