ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScriptの5つの一般的な関数を詳しく解説

JavaScriptの5つの一般的な関数を詳しく解説

小云云
小云云オリジナル
2018-03-26 09:07:521215ブラウズ

JavaScript ではよく議論される問題がいくつかあります。これらの問題については、人によってさまざまな考えがあります。これ以上苦労することなく、自分で実装するのが最善の方法です。

配列の平坦化

配列を平坦化する方法はたくさんありますが、最終的に最善の方法は、基本的なルーチンを理解できるように、指定された深さで平坦化メソッドを再帰して実装することです。


function flattenDepth(array, depth = 1) {
 let result = []
 array.forEach(item => {
 let d = depth
 if (Array.isArray(item) && d > 0) {
  result.push(...(flattenDepth(item, --d)))
 } else {
  result.push(item)
 }
 })
 return result
}
console.log(flattenDepth([1, [2, [3, [4]], 5]])) // [ 1, 2, [ 3, [ 4 ] ], 5 ]
console.log(flattenDepth([1, [2, [3, [4]], 5]], 2)) // [ 1, 2, 3, [ 4 ], 5 ]
console.log(flattenDepth([1, [2, [3, [4]], 5]], 3)) // [ 1, 2, 3, 4, 5 ]

再帰的な実装は非常にシンプルで理解しやすいです。つまり、各項目を走査し、項目が配列の場合、その項目を引き続き呼び出すようにします。このパラメータは配列にとって非常に重要なので、各項目には役割があるため、ループ内に配置されます。

カリー化

関数のカリー化については、人それぞれの理解と実装方法があります。一言で説明すると、十分なパラメーターがなければ関数は実行されます。十分になるまで前のパラメータが保存されます。


function curry(func) {
 var l = func.length
 return function curried() {
 var args = [].slice.call(arguments)
 if(args.length < l) {
  return function() {
  var argsInner = [].slice.call(arguments)
  return curried.apply(this, args.concat(argsInner))
  }
 } else {
  return func.apply(this, args)
 }
 }
}
var f = function(a, b, c) {
 return console.log([a, b, c])
};
var curried = curry(f)
curried(1)(2)(3) // => [1, 2, 3]
curried(1, 2)(3) // => [1, 2, 3]
curried(1, 2, 3) // => [1, 2, 3]

上記のコードを見ると難しくありませんが、パラメータの数を判断するたびに、カリー化された関数のパラメータの数と比較され、その数より小さい場合は返し続けます。それ以外の場合は関数が実行されます。

手ぶれ補正

私の理解によれば、手ぶれ補正とは、何度トリガーしても、最後のトリガーから指定した時間が経過するまではトリガーされないことを意味します。この説明に続いて、基本バージョンを作成します。


function debounce(func, wait) {
 var timer
 return function() {
 var context = this
 var args = arguments
 clearTimeout(timer)
 timer = setTimeout(function() {
  func.apply(context, args)
 }, wait)
 }
}

ここで、最初と最後にトリガーされるという要件があり、スペースバーを押すたびに関数のテストを容易にするためにテストページを作成します。手ぶれ補正機能とスロットル機能をテストする場合、数値は 1 ずつ増加します。


<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
 <style>
  #container{text-align: center; color: #333; font-size: 30px;}
 </style>
</head>
<body>
 <p id="container"></p>
 <script>
  var count = 1
  var container = document.getElementById(&#39;container&#39;)
  function getUserAction(e) {
  // 空格
  if (e.keyCode === 32) {
   container.innerHTML = count++
  }
  }
  // document.onkeydown = debounce(getUserAction, 1000, false, true)
  document.onkeydown = throttle(getUserAction, 1000, true, true)
  function debounce(func, wait, leading, trailing) {}
  function throttle(func, wait, leading, trailing) {}
 </script>
</body>
</html>

先頭と末尾の 2 つのパラメータは、先頭と末尾を実行するかどうかを決定するために使用されます。先頭が true の場合、スペースを押すたびに 1 回実行されます。末尾が true の場合、最後のトリガーが実行されます。終了するたびに実行されます。手ぶれ補正機能の距離、両方が true の場合、最初にスペースを押すと 1 が追加され、すぐにスペースを押すと、この時点では内部の getUserAction は実行されませんが、末尾を false に放した後に実行されます。 、手放した後は実行されません。


function debounce(func, wait, leading, trailing) {
 var timer, lastCall = 0, flag = true
 return function() {
 var context = this
 var args = arguments
 var now = + new Date()
 if (now - lastCall < wait) {
  flag = false
  lastCall = now
 } else {
  flag = true
 }
 if (leading && flag) {
  lastCall = now
  return func.apply(context, args)
 }
 if (trailing) {
  clearTimeout(timer)
  timer = setTimeout(function() {
  flag = true
  func.apply(context, args)
  }, wait)
 }
 }
}

説明します、最後の呼び出しの時間が記録されるたびに、それが間隔より小さい場合、最初の実行以降は実行されません。間隔を指定するか、間隔の後に呼び出された場合は、フラグをリセットして、上記の基本バージョンと比較します。

スロットリング

スロットルとは、どのようにトリガーされたとしても、指定された間隔に従って実行されることを意味します。 基本バージョンもあります。


function throttle(func, wait) {
 var timer
 return function() {
 var context = this
 var args = arguments
 if (!timer) {
  timer = setTimeout(function () {
  timer = null
  func.apply(context, args)
  }, wait)
 }
 }
}

は、手ぶれ補正機能のような 2 つのパラメーターも追加します。実際、この 2 つのコードは非常に似ています。


function throttle(func, wait, leading, trailing) {
 var timer, lastCall = 0, flag = true
 return function() {
 var context = this
 var args = arguments
 var now = + new Date()
 flag = now - lastCall > wait
 if (leading && flag) {
  lastCall = now
  return func.apply(context, args)
 }
 if (!timer && trailing && !(flag && leading)) {
  timer = setTimeout(function () {
  timer = null
  lastCall = + new Date()
  func.apply(context, args)
  }, wait)
 } else {
  lastCall = now
 }
 }
}

オブジェクトコピー

オブジェクトコピーが深いコピーと浅いコピーに分けられることは誰もが知っています

JSON.parse(JSON.stringify(obj))

もう一つの方法は再帰


function clone(value, isDeep) {
 if (value === null) return null
 if (typeof value !== &#39;object&#39;) return value
 if (Array.isArray(value)) {
 if (isDeep) {
  return value.map(item => clone(item, true))
 }
 return [].concat(value)
 } else {
 if (isDeep) {
  var obj = {}
  Object.keys(value).forEach(item => {
  obj[item] = clone(value[item], true)
  })
  return obj
 }
 return { ...value }
 }
}
var objects = { c: { &#39;a&#39;: 1, e: [1, {f: 2}] }, d: { &#39;b&#39;: 2 } }
var shallow = clone(objects, true)
console.log(shallow.c.e[1]) // { f: 2 }
console.log(shallow.c === objects.c) // false
console.log(shallow.d === objects.d) // false
console.log(shallow === objects) // false

を使用することです。基本型を直接返します。参照型の場合は、clone メソッドを再帰的に走査して呼び出します。

まとめ

実際、上記のメソッドの一般的な考え方は、クロージャの使用を含む再帰関数と高階関数の使用です。フロントエンドはこれらの質問を自分で実装するのが最善です。を理解するのに役立ちます。

関連する推奨事項:

JavaScriptでのさまざまな一般的な関数定義方法_javascriptスキル

JS関数関連の知識ポイントのまとめと共有

JS関数パラメータの値渡しの説明

以上がJavaScriptの5つの一般的な関数を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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