将来を見据えたウェブ・アプリケーションの構築:The Codestのエキスパート・チームによる洞察
The Codestが、最先端技術を駆使してスケーラブルでインタラクティブなウェブアプリケーションを作成し、あらゆるプラットフォームでシームレスなユーザー体験を提供することにどのように秀でているかをご覧ください。The Codestの専門知識がどのようにデジタルトランスフォーメーションとビジネス...
ここ数年、ウェブ開発は変化している。多くの機能やAPIがブラウザに追加されるにつれ、私たちはそれらを正しい方法で使わなければならなくなった。この栄誉に浴した言語はJavaScriptだった。
当初、開発者たちはこのスクリプトの設計に納得しておらず、このスクリプトを使っている間はほとんど否定的な印象を持っていた。時が経つにつれて、この言語には大きな可能性があることが判明し、その後のECMAScript標準によって、いくつかの仕組みがより人間的で、単純に、より良くなりました。この記事では、そのいくつかを見てみよう。
についてのよく知られた真実 JavaScript というのも、ここではすべてがオブジェクトだからだ。配列、関数、文字列、数値、そしてブーリアンまで。すべてのタイプの値はオブジェクトで表現され、独自のメソッドとフィールドを持っている。しかし、プリミティブと構造体という2つのカテゴリーに分けることができる。つまり、ある変数に新しい値を代入し直すことはできるが、既存の値そのものを変更することはできない。つまり、ある変数に新しい値を代入し直すことはできるが、既存の値そのものを変更することはできない。
深入りする前に、スコープの意味を説明しよう。スコープとは、宣言された変数を使うことができる唯一の領域だと言える。ES6標準以前は、var文で変数を宣言し、グローバル・スコープかローカル・スコープを与えることができた。グローバル・スコープはアプリケーションのどの場所でも変数にアクセスできる領域で、ローカル・スコープは特定の領域(主に関数)に限定されます。
標準のES2015から、 JavaScript には、キーワードによって異なる3つの変数宣言方法がある。varキーワードで宣言された変数は、現在の関数本体にスコープされます。ES6標準では、より人間的な方法で変数を宣言できるようになった。var文とは逆に、const文とlet文によって宣言された変数は、ブロックにのみスコープされる。しかし、JSはconst文を他の プログラミング言語 - の代わりに、その値への参照を保持します。つまり、const文で宣言されたオブジェクトのプロパティを変更することはできるが、この変数の参照を上書きすることはできない。ES6のvarの代替は実はlet文である、と言う人がいる。いいえ、そうではありませんし、var文は今後も廃止されることはないでしょう。というのも、大抵の場合、var文はより多くの問題を引き起こすからです。その代わり、const文を悪用しなければならないが、参照を変更する必要がある場合はletを使うべきだ。
まず、以下から始めよう。 コード:
(() => {
for (var i = 0; i < 5; i++) { { { { { var i = 0; i { を設定します。
console.log(`"i" の値: ${i}`);
}, 1000);
}
})();
これを見ると、forループがiの値を繰り返し、1秒後にイテレータの値を記録しているように見える:1, 2, 3, 4, 5.しかし、そうではない。前述したように、var文は関数本体全体で変数の値を保持するためのものです。つまり、2回目、3回目......と繰り返すうちに、i変数の値は次の値に置き換えられるということです。最後にループが終了し、タイムアウトの目盛りが次のように表示される:5、5、5、5、5。イテレータの現在の値を保持する最善の方法は、代わりにlet文を使うことである:
(() => {
for (let i = 0; i < 5; i++) { { { { for (let i = 0; i { {のようにします。
console.log(`"i" の値: ${i}`);
}, 1000);
}
})();
上の例では、iの値のスコープを現在の反復ブロック内に保持しています。この変数を使用できるのはこの領域だけであり、この領域の外から上書きすることはできません。この場合の結果は予想通り、1 2 3 4 5となる。この状況をvarステートメントで処理する方法を見てみよう:
(() => {
for (var i = 0; i < 5; i++) { { (var i = 0; i {
setTimeout(() => {」とします。
console.log(`"j" の値: ${j}`);
}, 1000);
})(i);
}
})();
var文は関数ブロックの内部に値を保持するためのものなので、引数(イテレータの現在の状態の値)を取る定義された関数を呼び出して、それから何かをしなければならない。宣言された関数の外では、jの値は上書きされません。
私が気づいた最も多い犯罪は、構造体の力を無視し、他のコードでも変更される構造体のプロパティを変更することです。ちょっと見てみよう:
const DEFAULT_VALUE = {(デフォルト値
favoriteBand: 'The Weeknd'
};
const currentValue = DEFAULT_VALUE;
const bandInput = document.querySelector('#favorite-band');
const restoreDefaultButton = document.querySelector('#restore-button');
bandInput.addEventListener('input',() => {)
現在の値.favoriteBand = bandInput.value;
}, false);
restoreDefaultButton.addEventListener('click', () => { { currentValue = DEFAULTBUTTON = DEFAULTBUTTON; }, false
currentValue = DEFAULT_VALUE;
}, false);
はじめに:オブジェクトとして保存されたデフォルトのプロパティを持つモデルがあるとします。入力値をデフォルトのものに戻すボタンが欲しい。入力をいくつかの値で埋めた後、モデルを更新します。しばらくして、デフォルトのピックの方が単純に良かったと思うので、それを元に戻したい。ボタンをクリックしても、何も起こらない。なぜか?参照される値の力を無視しているからだ。
この部分: const currentValue = DEFAULTVALUEはJSに次のことを伝えている。VALUE 値を取得し、currentValue 変数に代入する。実際の値は一度だけメモリに保存され、両方の変数がそれを指している。ある場所のプロパティを変更することは、別の場所のプロパティを変更することを意味する。このような状況を回避する方法はいくつかある。そのひとつがスプレッド演算子だ。コードを修正してみよう:
const DEFAULT_VALUE = {(デフォルト値
favoriteBand: 'The Weeknd'
};
const currentValue = { ...DEFAULT_VALUE };
const bandInput = document.querySelector('#favorite-band');
const restoreDefaultButton = document.querySelector('#restore-button');
bandInput.addEventListener('入力', () => { 現在の値.
currentValue.favoriteBand = bandInput.value;
}, false);
restoreDefaultButton.addEventListener('click', () => {.
currentValue = { ...DEFAULT_VALUE };
}, false);
この場合、スプレッド演算子は次のように動作します:オブジェクトからすべてのプロパティを取り出し、それらを含む新しいオブジェクトを作成します。このおかげで、currentValueとDEFAULT_VALUEの値はメモリ上の同じ場所を指すことがなくなり、どちらか一方に加えられた変更は他方に影響しなくなります。
では、問題は、魔法のスプレッド演算子を使えばいいのでしょうか?この場合はそうだが、我々のモデルにはこの例よりも複雑なものが必要かもしれない。入れ子になったオブジェクトや配列、その他の構造体を使用する場合、最上位で参照される値のスプレッド演算子は最上位にのみ影響し、参照されるプロパティはメモリ内で同じ場所を共有することになります。この問題を解決する方法はたくさんありますが、すべてニーズ次第です。深さレベルごとにオブジェクトをクローンすることもできるし、より複雑な操作の場合は、イマーを使うことでほとんど苦もなくイミュータブルなコードを書くことができる。
スコープとバリュー・タイプに関する知識が混在していても使えるのか?もちろん、使える!この両方を使うものを作ってみよう:
const useValue = (defaultValue) => { {....
const value = [...defaultValue];
定数 setValue = (newValue) => { {....
value.length = 0; // 配列をクリアするトリッキーな方法
newValue.forEach((item, index) => { { 値[インデックス] = item; // 配列をクリアするトリッキーな方法
value[index] = item;
});
// 他のことをする
};
return [value, setValue];
};
const [animals, setAnimals] = useValue(['cat', 'dog']);
console.log(animals); // ['cat', 'dog'].
setAnimals(['horse', 'cow']);
console.log(animals); // ['horse', 'cow']);
このコードがどのように動作するのか、一行ずつ説明していこう。useValue関数はdefaultValueの引数に基づいて配列を作成している。このモディフィケーターは、既存の値に適用されるトリッキーな方法で新しい値を受け取ります。関数の最後には、値とその修飾子を配列の値として返します。次に、作成した関数を使用して、戻り値として animals と setAnimals を宣言します。その修飾子を使って、関数がanimal変数に影響を与えるかどうかをチェックする!
しかし待てよ、このコードのどこがそんなに派手なのだろうか?リファレンスはすべての新しい値を保持し、次のような独自のロジックをこのモディフィケーターに注入することができる。 いくつかのAPI または 生態系の一部 を使うことができる。このトリッキーなパターンは、よりモダンなJSライブラリでよく使われる。プログラミングにおける関数型パラダイムは、コードをより複雑にせず、他のプログラマーが読みやすくすることを可能にする。
言語の仕組みがフードの下でどのように働いているかを理解することで、より意識的で軽量なコードを書くことができる。JSが低レベル言語ではなく、メモリがどのように割り当てられ、保存されるかについてある程度の知識が必要だとしても、オブジェクトを変更する際には予期せぬ動作に注意しなければならない。一方、値のクローンを乱用することは必ずしも正しい方法ではなく、間違った使い方は長所よりも短所の方が多い。データフローを計画する正しい方法は、アプリケーションのロジックを実装する際に何が必要で、どのような障害に遭遇する可能性があるかを考慮することです。
続きを読む