Javascript実践ヒント大全、あなたの知らないECMAScript

マップ紹介

文法

array.map(callback[, thisArg])

パラメータ

折り返し電話

元の配列内の要素は、このメソッドを通過した後に新しい要素を返します。

現在の価値

コールバックの最初のパラメータは、配列内で現在渡されている要素です。

索引

callback の 2 番目のパラメータは、配列内で現在渡されている要素のインデックスです。

配列

callback の 3 番目のパラメータ、map メソッドを呼び出す配列。

この引数

コールバック関数の実行時に this が指すオブジェクト。

戻り値

コールバック関数の戻り値で構成される新しい配列。

https://www.codewars.com/kata/double-char

文字列を指定すると、各文字 (大文字と小文字が区別される) が 1 回繰り返される文字列を返す必要があります。

doubleChar("String") ==> "SSttrriinngg"

doubleChar("Hello World") ==> "HHeelllloo  WWoorrlldd"

doubleChar("1234!_ ") ==> "11223344!!__  "

幸運を!

答え:

const doubleChar = (str) =>
  str
    .split('')
    .map((i) => i.repeat(2))
    .join('');

リデュースの概要

文法

arr.reduce(callback, [initialValue]);

パラメータ

折り返し電話

配列内の各値に対して実行する関数。次の 4 つのパラメーターを使用します。

アキュムレータ

コールバックへの最後の呼び出しによって返された値、または提供された初期値 (initialValue)

現在の価値

処理される配列内の要素

現在のインデックス

データ内で処理されている要素のインデックス。initialValues が指定されていない場合は、デフォルトで 0 から始まります。

配列

reduce を呼び出す配列

初期値

コールバックの最初の呼び出しの最初の引数として。

戻り値

この関数は処理結果を蓄積します。

https://www.codewars.com/kata/beginner-reduce-but-grow

整数の配列 (x) を指定すると、値を順番に乗算した結果を返します。例:

[1, 2, 3] --> 6

初心者の場合は、reduce メソッドを使用してみてください。これは非常に便利なので、知っておくと良いでしょう。

配列は空にはなりません。

答え:

const grow = (x) => x.reduce((r, i) => r * i, 1);

定期交換

参考:

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp

道具:

  • RegExp テスター (Chrome プラグイン)

10 個の整数 (0 ~ 9) の配列を受け取り、それらの数値の文字列を電話番号の形式で返す関数を作成します。

例:

createPhoneNumber([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) // => returns "(123) 456-7890"

このチャレンジを完了するには、返される形式が正しい必要があります。
閉じ括弧の後のスペースを忘れないでください。

トピックのアドレス: https://www.codewars.com/kata/create-phone-number

答え:

const createPhoneNumber = (n) => n.join('').replace(/(\d{3})(\d{3})(\d{3})/, '($1) $2-$3');

例外キャプチャ

ES5 の従来のアプローチ

コード ブロックの実行でエラー失敗がスローされたと仮定すると、エラーを捕捉する方法は次のとおりです。

try {
    
    
  // 代码块执行,并抛出 fail 错误
  throw new Error('fail');
} catch (e) {
    
    
  console.log(e);
}

タイマー

まず上記のコードを書き直してタイマーを追加しましょう。

try {
    
    
  setTimeout(() => {
    
    
    throw new Error('fail');
    // Uncaught Error: fail
  }, 1000);
} catch (e) {
    
    
  console.log(e);
}

このように、タイマーの外で try/catch をスローしても内部エラーをキャッチできません。

正しいアプローチは次のとおりです。

setTimeout(() => {
    
    
  try {
    
    
    throw new Error('fail');
  } catch (e) {
    
    
    console.log(e);
  }
}, 1000);

約束

function doSomething() {
    
    
  return new Promise((resolve, reject) => {
    
    
    // 同步代码中的 throw 可以被捕捉到
    throw new Error('fail');
  });
}

doSomething()
  .then((x) => {
    
    
    console.log('success:', x);
  })
  .catch((err) => {
    
    
    console.log('fail:', err);
  });

このように書いても問題はありませんが、エラーは検出される可能性があります。ただし、少し変更する限り、問題が発生する可能性があります。例えば:

function doSomething() {
    
    
  return new Promise((resolve, reject) => {
    
    
    // 异步代码中的 throw 不能被 Promise 的 catch 捕捉到
    setTimeout(() => {
    
    
      throw new Error('fail');
    }, 1000);
  });
}

doSomething()
  .then((x) => {
    
    
    console.log('success:', x);
  })
  .catch((err) => {
    
    
    console.log('fail:', err);
  });

ここでスローされますが、エラーは捕捉されません。したがって、Promise では通常、reject を通じてエラーをスローします。

function doSomething(x) {
    
    
  return new Promise((resolve, reject) => reject(x));
}

doSomething('fail')
  .then((x) => {
    
    
    console.log('success:', x);
  })
  .catch((err) => {
    
    
    console.log('fail:', err);
  });
// fail: fail

さらに、もう 1 つの興味深い詳細があり、catch の後に .then を追加すると実行が継続されます。

function doSomething(x) {
    
    
  return new Promise((resolve, reject) => reject(x));
}

doSomething('fail')
  .then((x) => {
    
    
    console.log('success:', x);
  })
  .catch((err) => {
    
    
    console.log('fail:', err);
    // 这里可以写 return 给下面的方法继续执行
  })
  .then((x) => {
    
    
    console.log('continue:', x);
  });
// fail: fail
// continue: undefined

非同期/待機

基本的に、Async/Await は Promise を通じて実装されるため、上記の Promise の説明と基本的に同じです。

次のように、await メソッドの外側で try/catch をネストできます。

function doSomething(x) {
    
    
  return new Promise((resolve, reject) => reject(x));
}

(async () => {
    
    
  try {
    
    
    const result = await doSomething('fail');
    console.log('success:', result);
    // return 返回
  } catch (err) {
    
    
    console.log('fail:', err);
    // return 返回
  }
})();
// fail: fail

しかし、ここで問題が発生し、例えば関数がリターンする必要がある場合、return 文を 2 回記述する必要があり、これは正常ですが、正常な場合は結果を返し、異常な場合はどちらかを返しますthrow new Error()ちょっとしたコツがあって、次のように書くことができます。

function doSomething(x) {
    
    
  return new Promise((resolve, reject) => reject(x));
}

(async () => {
    
    
  const result = await doSomething('fail').catch((err) => {
    
    
    console.log('fail:', err);
    return 0; // 默认值
  });
  console.log('success:', result);
})();
// fail: fail
// success: 0

エラーが検出されたら、デフォルト値を再割り当てし、コードの実行を続行します。

イベントの代表団

たとえば、イベント バインディングは、AJAX リクエストによって返された結果のボタンに対して実行されますclick

var handleClick = function (e) {
    
    
  if (e.target && e.target.nodeName.toLowerCase() === 'button') {
    
    
    // Codes Here
  }
};

parentNode.addEventListener('click', handleClick);

ディープクローン

問題現象:

var obj1 = {
    
    
  key1: 'value1',
  key2: 'value2',
  children: {
    
    
    key3: 'value3',
    key4: 'value4'
  }
};
var obj2 = Object.assign({
    
    }, obj1);
obj2.children.key3 = 'test';
console.log(obj1.children);
// { key3: 'test', key4: 'value4' }

簡単な解決策:

const obj2 = JSON.parse(JSON.stringify(obj1));

スクロールデバウンス

フロントエンドのスクロールリスニングイベントのトリガー頻度が高すぎる問題を解決するために使用されます。

コアコード:

function debounce(func, wait = 20, immediate = true) {
    
    
  var timeout;
  return function () {
    
    
    var context = this,
      args = arguments;
    var later = function () {
    
    
      timeout = null;
      if (!immediate) func.apply(context, args);
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
  };
}

サンプルコード:

function testFunc(e) {
    
    
  console.count(e);
}

window.addEventListener('scroll', () => console.count('bounce'));
window.addEventListener('scroll', debounce(testFunc));

ブラウザでテストします。

Map または For を使用したトラバース

同じ横断ですが、実際には大きく異なります。

比較した

地図

自分を変えてください。

[1, 2, 3, 4, 5].map((x) => x + 1);
// [ 2, 3, 4, 5, 6 ]

ために

ただループするだけです。

ベンチマークテスト

ベンチマークスクリプト:

suite('iterator', function () {
    
    
  bench('for', function () {
    
    
    const a = [1, 2, 3, 4, 5];
    for (let i = 0; i < a.length; i++) {
    
    
      // nothing
    }
  });
  bench('foreach', function () {
    
    
    const a = [1, 2, 3, 4, 5];
    a.forEach(function (d) {
    
    
      // nothing
    });
  });
  bench('for of', function () {
    
    
    const a = [1, 2, 3, 4, 5];
    for (let i of a) {
    
    
      // nothing
    }
  });
  bench('map', function () {
    
    
    const a = [1, 2, 3, 4, 5];
    a.map((x) => x);
  });
});

試験結果:

                      iterator
      50,038,931 op/s » for
       8,980,276 op/s » foreach
       8,990,758 op/s » for of
       1,713,807 op/s » map


  Suites:  1
  Benches: 4
  Elapsed: 5,710.33 ms

結論は

ループのみがfor最も信頼性が高くなります。

foreachとほぼ同じですfor ... of

map最低のパフォーマンス。

変更イベントに反応して値を割り当てるトリガー

var setValue = function (element, value) {
    
    
  element.value = value;
  if ('createEvent' in document) {
    
    
    var event = new Event('input', {
    
     bubbles: true });
    element.dispatchEvent(event);
  } else {
    
    
    element.fireEvent('onchange');
  }
};

パイプラインオペレーター(案)

現在ドラフト段階: https://github.com/tc39/proposal-pipeline-operator

function doubleSay(str) {
    
    
  return `${
      
      str}, ${
      
      str}`;
}
function capitalize(str) {
    
    
  return str[0].toUpperCase() + str.substring(1);
}
function exclaim(str) {
    
    
  return `${
      
      str}!`;
}

let result = 'hello' |> doubleSay |> capitalize |> exclaim;

result |> console.log;
//=> "Hello, hello!"

プロジェクトテンプレート: https://github.com/willin/esnext-pipeline-biolerplate

非同期 (ES 7)

async function fn(args) {
    
    
  // ...
}

// 等同于

function fn(args) {
    
    
  return spawn(function* () {
    
    
    // ...
  });
}

複数のコマンドawaitに続く非同期操作の場合、後続関係がない場合は、それらを同時にトリガーさせるのが最善です。

let foo = await getFoo();
let bar = await getBar();

上記のコードでは、getFooと はgetBar2 つの独立した非同期操作 (つまり、互いに独立) であり、二次関係として記述されています。getFooこれは完了後にのみ実行され、getBar同時にトリガーされる可能性があるため、時間がかかります。

// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

上記 2 つの書き込み方法、 、getFoogetBar同時に実行することで、プログラムの実行時間を短縮できます。

プロキシ (ES6)

Node v6.1.0 以降のバージョンはテストされ、統合されています。

サンプルコード:

const proxy = new Proxy(
  {
    
    },
  {
    
    
    get: (target, property) => [target, property]
  }
);

console.log(proxy.func); // [ {}, 'func' ]
console.log(proxy.func('123')); // TypeError: proxy.func is not a function
const proxy = new Proxy(
  {
    
    },
  {
    
    
    get: (target, property) => (test) => [target, property, test]
  }
);

console.log(proxy.func); // [Function]
console.log(proxy.func('123')); // [ {}, 'func', '123' ]

ES6 の範囲

For ループを例に挙げます。

var funcs = [];

for (var i = 0; i < 10; i += 1) {
    
    
  funcs.push(function () {
    
    
    console.log(i);
  });
}

funcs.forEach((func) => func());
// 输出 10 十次

閉鎖:

var funcs = [];

for (var i = 0; i < 10; i += 1) {
    
    
  funcs.push((function(value){
    
     console.log(value); }(i));
}

funcs.forEach(func => func());
// 0 到 9 依次输出

ES6 では次のように簡略化できます。

const funcs = [];

for (let i = 0; i < 10; i += 1) {
    
    
  funcs.push(() => console.log(i));
}

funcs.forEach((func) => func());
// 0 到 9 依次输出

関数が関数を作成する

var add = new Function('first', 'second = first', 'return first + second');
console.log(add(1, 1)); // 2
console.log(add(1)); // 2
var pickFirst = new Function('..args', 'return args[0]');
console.log(pickFirst(1, 2)); // 1

ES6で値を交換する

let a = 1;
let b = 2;

[a, b] = [b, a];

console.log(a, b); // 2 1

API AJAX を取得する

ブラウザの互換性

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-3HRKmB2K-1690025164220)(/basic/js/fetch.png)]

サポートチェック

if (typeof fetch === 'function' && typeof window.fetch === 'function') {
    
    
  // 支持
}

if (typeof fetch !== 'function' || typeof window.fetch !== 'function') {
    
    
  // 不支持
}

サンプルコード

var req = new Request('/data.json', {
    
     method: 'POST', cache: 'reload' });
fetch(req)
  .then(function (res) {
    
    
    return res.json();
  })
  .then(function (data) {
    
    
    console.log(data);
  });

クロスドメインCookieの設定

credentials資格情報パラメータ

fetch('a.com/api', {
    
     credentials: 'include' }).then(function (res) {
    
    
  // ...
});

また

var req = new Request('/data.json', {
    
     method: 'POST', cache: 'reload', credentials: 'include' });
fetch(req)
  .then(function (res) {
    
    
    return res.json();
  })
  .then(function (data) {
    
    
    console.log(data);
  });

参考文献

おすすめ

転載: blog.csdn.net/jslygwx/article/details/131871715