直接実現JS配列高次関数
43383 ワード
辞書の知識
引数または戻り関数として関数を渡す関数
高次関数により、外部状態の変更や可変データを回避し、不変性を指すことができます.
パラメータによって他の関数内部に渡される関数
高次関数、コールバック関数を使用する理由
1.関数の効率/可読性を向上させるため
関数の基本原則は「1つの関数が1つの役割しか担当しない」ということです.
関数の単位が小さいほど,関数の再利用性が高くなり,関数の名前から関数の挙動を直感的に推定できる.
次のコードを見てください.
case 1. 一般関数の使用
function sum1(a,b){
console.log(a+b)
}
function sum2('결과는 ',a,b){
console.log(a+b)
}
sum1(2,3) // 5 출력
sum2(2,3) // "결과는 5" 출력
case 2. コールバック関数の使用function sum(a,b,callback){
return callback(a+b)
}
function printData(data){
console.log(print)
}
function printResult(data){
console.log('결과는 ',data)
}
sum(2,3,(data)=>console.log(data)) // 5 출력
sum(2,3,printData) // 5 출력
sum(2,3,printResult) // "결과는 5" 출력
case 1
などの場合、sum 1関数は2つの出力と加算計算を担当します.現在のコード量は少なく,あまり差はないが,以降コード長が長ければ長いほど担当する部分が多くなるほど結合度が高くなる.
高い結合度は関数を柔軟にしない.
関数の柔軟性とはどういう意味ですか.
case 2
は代表的な例である.case 2
ではsum関数は演算のみを担当し、残りのprintData、printResult関数は出力のみを担当する.このようにキャラクタを分離すると、コールバック関数を変更するだけでsum結果を任意に処理できます.
すなわち,関数が柔軟になり,再利用性が向上する.
2.非同期処理
コールバック関数は、非同期処理にもよく使用されます.
case 1
function first(){
setTimeout(() => {
console.log("first")
}, 300)
}
function second(){
console.log("second")
}
frist()
second() // "second" 출력 => "first" 출력
case 2function first(callback){
setTimeout(() => {
console.log("first")
callback()
}, 300)
}
function second(){
console.log("second")
}
frist(second) // "first" 출력 => "second" 출력
case 1
frist()関数を明確に実行し、secondを出力する.うん.JavaScriptは上から下へ実行されているのではないでしょうか.JavaScriptの非同期処理方式のためsettimeout関数が最も遅く動作しているという疑問が生じるかもしれません.
したがって、first=>secondのようにコードを順次実行するには、settimeoutのコールバック関数の位置に対応する関数を追加するだけです.
Array.prototype.高次関数の実装
今やっと本題に着いた.前述の知識に基づいて,配列高次関数を実現できる.
Array.prototype.map()
特長
元の配列を変更せずにコールバック関数の戻り値からなる新しい配列を返す関数.
メインインプリメンテーション(thisArgなし)
CurrentValue、index、array、thisArgの処理が必要です.
実装する前に、map関数がどのような形式であるかを確認します.['a','b','c','d'].map((el,i,arr)=>console.log(el,i,arr))
// a 0 ['a','b','c','d']
// b 1 ['a','b','c','d']
// c 2 ['a','b','c','d']
// d 3 ['a','b','c','d']
実施前の考え方
['a','b','c','d'].map((el,i,arr)=>console.log(el,i,arr))
// a 0 ['a','b','c','d']
// b 1 ['a','b','c','d']
// c 2 ['a','b','c','d']
// d 3 ['a','b','c','d']
普段何気なく犯すと、mapはコールバック関数を持つ高次関数だった.
コールバック関数のパラメータ=>currentValue、index、array
mapは巡回配列の関数であるため,クエリが必要である.
mapは、新しい配列を返す必要があるため、関数内部に配列を作成し、新しい配列を返す必要がある場合があります.
インプリメンテーション
const customMap = function(callback){
const arr = [];
for(let i=0;i<this.length;i++){
callback(this[i],i,this);
arr.push(this[i]);
}
return arr;
}
Array.prototype.customMap = customMap;
['a','b','c','d'].customMap((el,i,arr)=>console.log(el,i,arr)) // 기존 map과 같은 결과 나옴
配列内でcallback()関数をループします.これは
console.log(el,i,arr)
部分です.整列中は、customMap内部のarrに
this[i]
(ここではcustomMapを呼び出すオブジェクト["a"、"b"、"c"、"d])を加える.2回目の実施(thisArgを使用)
初めて実現した時、thisargは参加しませんでした.
その原因は
thisArg
への理解不足であり、ここで説明thisArg
完了Array.prototype.map
実施.thisArg
コールバックを実行するときに使用する値.
簡単に言えば、これはthisArgの位置にバインドされたオブジェクト(in callback関数)を意味します.
より速く理解するために、例を挙げます.
const user = {name:'jamong',age: 23}
[1,2,3,4].map(function(){console.log(this)})
/* Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, …}
... 출력 */
thisArgパラメータを指定しない場合、コールバック関数内のthisはグローバルオブジェクトを指します.const user = {name:'jamong',age: 23}
[1,2,3,4].map(function(){console.log(this)})
/* {name: 'jamong', age: 23}
... 출력 */
ただし、userをthisArgに入れると、このオブジェクトがthisにバインドされていることを確認できます.実施前の考え方
このバインドは、
Function.prototype.bind()
を使用する必要があるようです.コールバック関数内部thisはthisArgにバインドする必要があるため、
callback.bind(thisArg)();
とともに使用できます.インプリメンテーション
const customMap = function(callback,thisArg){
const arr = [];
for(let i=0;i<this.length;i++){
callback.bind(thisArg)(this[i],i,this);
arr.push(this[i]);
}
return arr;
}
const user = {name: 'jamong'}
Array.prototype.customMap = customMap;
['a','b','c','d'].customMap(function(el,i,arr){console.log(el,i,arr,this)},user) // 기존 map과 같은 결과 나옴
注意事項コールバック関数が
화살표 함수
で記述されている場合、thisArgは何も実行しません.「矢印関数のthisは常に親スキャンのthisを指す」という特徴のため、矢印関数はcall、apply、bindメソッドを使用して変更できません.
Array.prototype.filter()
特長
コールバック関数でテストされたすべての要素を収集し、元の配列を変更せずに新しい配列に戻る関数です.
インプリメンテーション
実施前の考え方
インプリメンテーション
const customFilter = function(callback,thisArg){
const arr = [];
for(let i=0;i<this.length;i++){
callback.bind(thisArg)(this[i],i,this) && arr.push(this[i]);
}
return arr;
}
Array.prototype.customFilter = customFilter;
const user = { name: "b", age: 23 };
let arr = ['a','b','c','d'].customFilter(function(el,i,arr){return el===this.name},user)
console.log(arr) // ["b"] 출력
el===this.name
elが「b」の場合trueです.従って,コールバック関数がtrueを返すときにarrに対応する値を追加することを実現した.
Array.prototype.forEach()
特長
元のアレイの関数を変更せずに、各アレイ要素に対して指定された関数を実行します.
mapとforeachの最大の違いは、mapメソッドがコールバック関数の戻り値からなる新しい配列を返し、foreachメソッドが常に定義されていない配列を返すことです.
すなわち,forEachは高次関数の代わりに配列にすぎない.
インプリメンテーション
実施前の考え方
インプリメンテーション
const customForEach = function(callback, thisArg) {
const arr = [];
for (let i = 0; i < this.length; i++) {
callback.bind(thisArg)(this[i], i, this);
arr.push(this[i]);
}
return undefined;
}
const user = {name: 'jamong'}
Array.prototype.customForEach = customForEach;
['a','b','c','d'].customForEach(function(el, i, arr) {
console.log(el, i, arr, this)
}, user) // 기존 forEach와 출력 동일
Array.prototype.reduce()
特長
元のアレイを変更せずに、アレイ内の各要素に対してreduce関数を実行し、結果値の関数を返します.
reduce関数
累進関数
パラメータ:(計算機、現在値、現在のインデックス、ソース配列)
インプリメンテーション
実施前の考え方
reduce()のパラメータで
InitialValueがある場合は、
[initialValue,...기존 배열]
の最初のインデックスから累積値を求める.initialValueがない場合は、
コールバック関数の戻り値の累計を続行する必要があります.
第1回実施
const customReduce = function(callback, initialValue) {
if(this
let acc = initialValue ? callback(initialValue, this[0], 0, this) : this[0]
if(this.l
for (let i = 1; i < this.length; i++) {
acc = callback(acc, this[i], i, this);
}
return acc;
}
Array.prototype.customReduce = customReduce;
[0,1,2,3,4].customReduce((acc,cur,i,arr)=>{
console.log(acc,cur,i,arr)
return acc + cur},10)
2回目の実施
最初の実装が完了した後、reduceのMDNドキュメントをもう一度よく読んでみると、異常処理が行われていないところがあることに気づきました.従って、対応する異常処理が追加される.
const customReduce = function(callback, initialValue) {
if(this.length===0){
if(initialValue!==undefined){
return initialValue
}else{
return console.error('Uncaught TypeError: Reduce of empty array with no initial value')
}
}
let acc = initialValue ? callback(initialValue, this[0], 0, this) : this[0]
if(this.length>1){
for (let i = 1; i < this.length; i++) {
acc = callback(acc, this[i], i, this);
}
}
return acc;
}
Array.prototype.customReduce = customReduce;
[0,1,2,3,4].customReduce((acc,cur,i,arr)=>{
console.log(acc,cur,i,arr)
return acc + cur},10)
기존 배열
リファレンス
https://solveaproblem.dev/javascript-callback-function/
https://www.daleseo.com/js-async-callback/
https://ktpark1651.tistory.com/215
https://tesseractjh.tistory.com/175
Reference
この問題について(直接実現JS配列高次関数), 我々は、より多くの情報をここで見つけました
https://velog.io/@wkahd01/JS-배열-고차-함수-직접-구현하기
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
Reference
この問題について(直接実現JS配列高次関数), 我々は、より多くの情報をここで見つけました https://velog.io/@wkahd01/JS-배열-고차-함수-직접-구현하기テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol