├── CONTRIBUTING.md ├── CONTRIBUTING_es_ES.md ├── CONTRIBUTING_zh_CN.md ├── CONTRIBUTING_zh_TW.md ├── LICENSE.md ├── POST_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md ├── README.md └── _posts ├── en ├── angular │ ├── 2016-01-01-angularjs-digest-vs-apply.md │ └── 2017-03-07-preventing-unwanted-scopes-creation-in-angularjs.md ├── javascript │ ├── 2015-12-29-insert-item-inside-an-array.md │ ├── 2016-01-03-improve-nested-conditionals.md │ ├── 2016-01-04-sorting-strings-with-accented-characters.md │ ├── 2016-01-05-differences-between-undefined-and-null.md │ ├── 2016-01-06-writing-a-single-method-for-arrays-and-a-single-element.md │ ├── 2016-01-07-use-strict-and-get-lazy.md │ ├── 2016-01-08-converting-a-node-list-to-an-array.md │ ├── 2016-01-09-template-strings.md │ ├── 2016-01-10-check-if-a-property-is-in-a-object.md │ ├── 2016-01-11-hoisting.md │ ├── 2016-01-12-pseudomandatory-parameters-in-es6-functions.md │ ├── 2016-01-13-tip-to-measure-performance-of-a-javascript-block.md │ ├── 2016-01-14-fat-arrow-functions.md │ ├── 2016-01-15-even-simpler-way-of-using-indexof-as-a-contains-clause.md │ ├── 2016-01-16-passing-arguments-to-callback-functions.md │ ├── 2016-01-17-nodejs-run-a-module-if-it-is-not-required.md │ ├── 2016-01-18-rounding-the-fast-way.md │ ├── 2016-01-19-safe-string-concatenation.md │ ├── 2016-01-20-return-objects-to-enable-chaining-of-functions.md │ ├── 2016-01-21-shuffle-an-array.md │ ├── 2016-01-22-two-ways-to-empty-an-array.md │ ├── 2016-01-23-converting-to-number-fast-way.md │ ├── 2016-01-24-use_===_instead_of_==.md │ ├── 2016-01-25-Using-immediately-invoked-function-expression.md │ ├── 2016-01-26-filtering-and-sorting-a-list-of-strings.md │ ├── 2016-01-27-short-circuit-evaluation-in-js.md │ ├── 2016-01-28-curry-vs-partial-application.md │ ├── 2016-01-29-speed-up-recursive-functions-with-memoization.md │ ├── 2016-01-30-converting-truthy-falsy-values-to-boolean.md │ ├── 2016-01-31-avoid-modifying-or-passing-arguments-into-other-functions—it-kills-optimization.md │ ├── 2016-02-01-map-to-the-rescue-adding-order-to-object-properties.md │ ├── 2016-02-02-create-range-0-n-easily-using-one-line.md │ ├── 2016-02-03-implementing-asynchronous-loops.md │ ├── 2016-02-04-assignment-shorthands.md │ ├── 2016-02-05-observe-dom-changes.md │ ├── 2016-02-06-deduplicate-an-array.md │ ├── 2016-02-07-flattening-multidimensional-arrays-in-javascript.md │ ├── 2016-02-08-advanced-properties.md │ ├── 2016-02-09-using-json-stringify.md │ ├── 2016-02-10-array-average-and-median.md │ ├── 2016-02-11-preventing-unapply-attacks.md │ ├── 2016-02-12-use-destructuring-in-function-parameters.md │ ├── 2016-02-13-know-the-passing-mechanism.md │ ├── 2016-02-14-calculate-the-max-min-value-from-an-array.md │ ├── 2016-02-15-detect-document-ready-in-pure-js.md │ ├── 2016-02-16-basics-declarations.md │ ├── 2016-02-17-reminders-about-reduce-function-usage.md │ ├── 2016-02-26-extract-unix-timestamp-easily.md │ ├── 2016-03-03-helpful-console-log-hacks.md │ ├── 2016-03-16-DOM-event-listening-made-easy.md │ ├── 2016-04-05-return-values-with-the-new-operator.md │ ├── 2016-04-21-get-file-extension.md │ ├── 2016-05-06-use-optional-arguments.md │ ├── 2016-05-12-make-easy-loop-on-array.md │ ├── 2016-08-02-copy-to-clipboard.md │ ├── 2016-08-10-comma-operaton-in-js.md │ ├── 2016-08-17-break-continue-loop-functional.md │ ├── 2016-08-25-keyword-var-vs-let.md │ ├── 2016-10-28-three-useful-hacks.md │ ├── 2017-01-19-binding-objects-to-functions.md │ ├── 2017-03-09-working-with-websocket-timeout.md │ ├── 2017-03-12-3-array-hacks.md │ ├── 2017-03-16-tapping-for-quick-debugging.md │ ├── 2017-03-29-recursion-iteration-and-tail-calls-in-js.md │ ├── 2017-04-03-why-you-should-use-Object.is()-in-equality-comparison.md │ ├── 2017-04-05-picking-and-rejecting-object-properties.md │ ├── 2017-04-11-protocols-for-the-brave.md │ ├── 2017-04-24-improving-your-async-functions-with-webworkers.md │ ├── 2017-06-14-closures-inside-loops.md │ ├── 2017-06-14-immutable-structures-and-cloning.md │ ├── 2017-06-15-looping-over-arrays.md │ ├── 2017-09-01-hash-maps-without-side-effects.md │ ├── 2018-11-25-creating-immutable-objects-in-native-javascript.md │ ├── 2020-10-13-what-is-a-functional-inheritance.md │ ├── 2020-10-15-what-is-a-currying-function.md │ ├── 2020-10-20-what-is-the-temporal-dead-zone.md │ ├── 2020-10-22-difference-between-target-and-currentTarget.md │ ├── 2020-10-27-what-is-a-spread-operator.md │ ├── 2020-11-04-what-is-a-void-operator.md │ ├── 2020-11-17-what-is-the-promise-executor.md │ └── 2021-02-02-what-is-the-javascript-ternary-operator.md ├── more │ └── 2017-04-06-vuejs-how-vuejs-makes-a-copy-update-replace-inside-the-data-binding.md └── react │ ├── 2016-01-02-keys-in-children-components-are-important.md │ ├── 2017-03-27-state-to-props-maps-with-memory.md │ ├── 2017-04-04-enhancing-react-components-composition.md │ ├── 2017-04-10-adventurers-guide-to-react.md │ ├── 2017-05-29-upping-performance-by-appending-keying.md │ └── 2021-07-18-trace-the-reason-make-your-page-rerender.md ├── es_ES ├── angular │ └── 2016-01-01-angularjs-digest-vs-apply.md ├── javascript │ ├── 2015-12-29-insert-item-inside-an-array.md │ ├── 2016-01-03-improve-nested-conditionals.md │ ├── 2016-01-04-sorting-strings-with-accented-characters.md │ ├── 2016-01-05-differences-between-undefined-and-null.md │ ├── 2016-01-06-writing-a-single-method-for-arrays-and-a-single-element.md │ ├── 2016-01-07-use-strict-and-get-lazy.md │ ├── 2016-01-08-converting-a-node-list-to-an-array.md │ ├── 2016-01-09-template-strings.md │ ├── 2016-01-10-check-if-a-property-is-in-a-object.md │ ├── 2016-01-11-hoisting.md │ ├── 2016-01-12-pseudomandatory-parameters-in-es6-functions.md │ ├── 2016-01-13-tip-to-measure-performance-of-a-javascript-block.md │ ├── 2016-01-14-fat-arrow-functions.md │ ├── 2016-01-15-even-simpler-way-of-using-indexof-as-a-contains-clause.md │ ├── 2016-01-16-passing-arguments-to-callback-functions.md │ ├── 2016-01-17-nodejs-run-a-module-if-it-is-not-required.md │ ├── 2016-01-18-rounding-the-fast-way.md │ ├── 2016-01-19-safe-string-concatenation.md │ ├── 2016-01-20-return-objects-to-enable-chaining-of-functions.md │ ├── 2016-01-21-shuffle-an-array.md │ ├── 2016-01-22-two-ways-to-empty-an-array.md │ ├── 2016-01-23-converting-to-number-fast-way.md │ ├── 2016-01-24-use_===_instead_of_==.md │ ├── 2016-01-25-Using-immediately-invoked-function-expression.md │ ├── 2016-01-26-filtering-and-sorting-a-list-of-strings.md │ ├── 2016-01-27-short-circiut-evaluation-in-js.md │ ├── 2016-01-28-curry-vs-partial-application.md │ ├── 2016-01-29-speed-up-recursive-functions-with-memoization.md │ ├── 2016-01-30-converting-truthy-falsy-values-to-boolean.md │ ├── 2016-01-31-avoid-modifying-or-passing-arguments-into-other-functions—it-kills-optimization.md │ ├── 2016-02-01-map-to-the-rescue-adding-order-to-object-properties.md │ ├── 2016-02-02-create-range-0-n-easily-using-one-line.md │ ├── 2016-02-03-implementing-asynchronous-loops.md │ ├── 2016-02-04-assignment-shorthands.md │ ├── 2016-02-05-observe-dom-changes.md │ ├── 2016-02-06-deduplicate-an-array.md │ ├── 2016-02-07-flattening-multidimensional-arrays-in-javascript.md │ ├── 2016-02-08-advanced-properties.md │ ├── 2016-02-09-using-json-stringify.md │ ├── 2016-02-10-array-average-and-median.md │ ├── 2016-02-11-preventing-unapply-attacks.md │ ├── 2016-02-12-use-destructuring-in-function-parameters.md │ ├── 2016-02-13-know-the-passing-mechanism.md │ ├── 2016-02-14-calculate-the-max-min-value-from-an-array.md │ ├── 2016-02-15-detect-document-ready-in-pure-js.md │ ├── 2016-02-16-basics-declarations.md │ ├── 2016-02-17-reminders-about-reduce-function-usage.md │ ├── 2016-02-26-extract-unix-timestamp-easily.md │ ├── 2016-03-03-helpful-console-log-hacks.md │ ├── 2016-03-16-DOM-event-listening-made-easy.md │ ├── 2016-04-05-return-values-with-the-new-operator.md │ ├── 2016-04-21-get-file-extension.md │ ├── 2016-05-06-use-optional-arguments.md │ └── 2016-05-12-make-easy-loop-on-array.md └── react │ └── 2016-01-02-keys-in-children-components-are-important.md ├── zh_CN ├── angular │ └── 2016-01-01-angularjs-digest-vs-apply.md ├── javascript │ ├── 2015-12-29-insert-item-inside-an-array.md │ ├── 2016-01-03-improve-nested-conditionals.md │ ├── 2016-01-04-sorting-strings-with-accented-characters.md │ ├── 2016-01-05-differences-between-undefined-and-null.md │ ├── 2016-01-06-writing-a-single-method-for-arrays-and-a-single-element.md │ ├── 2016-01-07-use-strict-and-get-lazy.md │ ├── 2016-01-08-converting-a-node-list-to-an-array.md │ ├── 2016-01-09-template-strings.md │ ├── 2016-01-10-check-if-a-property-is-in-a-object.md │ ├── 2016-01-11-hoisting.md │ ├── 2016-01-12-pseudomandatory-parameters-in-es6-functions.md │ ├── 2016-01-13-tip-to-measure-performance-of-a-javascript-block.md │ ├── 2016-01-14-fat-arrow-functions.md │ ├── 2016-01-15-even-simpler-way-of-using-indexof-as-a-contains-clause.md │ ├── 2016-01-16-passing-arguments-to-callback-functions.md │ ├── 2016-01-17-nodejs-run-a-module-if-it-is-not-required.md │ ├── 2016-01-18-rounding-the-fast-way.md │ ├── 2016-01-19-safe-string-concatenation.md │ ├── 2016-01-20-return-objects-to-enable-chaining-of-functions.md │ ├── 2016-01-21-shuffle-an-array.md │ ├── 2016-01-22-two-ways-to-empty-an-array.md │ ├── 2016-01-23-converting-to-number-fast-way.md │ ├── 2016-01-24-use_===_instead_of_==.md │ ├── 2016-01-25-Using-immediately-invoked-function-expression.md │ ├── 2016-01-26-filtering-and-sorting-a-list-of-strings.md │ ├── 2016-01-27-short-circuit-evaluation-in-js.md │ ├── 2016-01-28-curry-vs-partial-application.md │ ├── 2016-01-29-speed-up-recursive-functions-with-memoization.md │ ├── 2016-01-30-converting-truthy-falsy-values-to-boolean.md │ ├── 2016-01-31-avoid-modifying-or-passing-arguments-into-other-functions—it-kills-optimization.md │ ├── 2016-02-01-map-to-the-rescue-adding-order-to-object-properties.md │ ├── 2016-02-02-create-range-0-n-easily-using-one-line.md │ ├── 2016-02-03-implementing-asynchronous-loops.md │ ├── 2016-02-04-assignment-shorthands.md │ ├── 2016-02-05-observe-dom-changes.md │ ├── 2016-02-06-deduplicate-an-array.md │ ├── 2016-02-07-flattening-multidimensional-arrays-in-javascript.md │ ├── 2016-02-08-advanced-properties.md │ ├── 2016-02-09-using-json-stringify.md │ ├── 2016-02-10-array-average-and-median.md │ ├── 2016-02-11-preventing-unapply-attacks.md │ ├── 2016-02-12-use-destructuring-in-function-parameters.md │ ├── 2016-02-13-know-the-passing-mechanism.md │ ├── 2016-02-14-calculate-the-max-min-value-from-an-array.md │ ├── 2016-02-15-detect-document-ready-in-pure-js.md │ ├── 2016-02-16-basics-declarations.md │ ├── 2016-02-17-reminders-about-reduce-function-usage.md │ ├── 2016-02-26-extract-unix-timestamp-easily.md │ ├── 2016-03-03-helpful-console-log-hacks.md │ ├── 2016-03-16-DOM-event-listening-made-easy.md │ ├── 2016-04-05-return-values-with-the-new-operator.md │ ├── 2016-04-21-get-file-extension.md │ ├── 2016-05-06-use-optional-arguments.md │ ├── 2016-05-12-make-easy-loop-on-array.md │ ├── 2016-08-02-copy-to-clipboard.md │ ├── 2016-08-10-comma-operaton-in-js.md │ ├── 2016-08-17-break-continue-loop-functional.md │ ├── 2016-08-25-keyword-var-vs-let.md │ ├── 2016-10-28-three-useful-hacks.md │ ├── 2017-01-19-binding-objects-to-functions.md │ ├── 2017-03-09-working-with-websocket-timeout.md │ ├── 2017-03-12-3-array-hacks.md │ ├── 2017-03-16-tapping-for-quick-debugging.md │ ├── 2017-04-03-why-you-should-use-Object.is()-in-equality-comparison.md │ └── 2017-04-05-picking-and-rejecting-object-properties.md ├── more │ └── 2017-04-06-vuejs-how-vuejs-makes-a-copy-update-replace-inside-the-data-binding.md └── react │ └── 2016-01-02-keys-in-children-components-are-important.md └── zh_TW ├── angular ├── 2016-01-01-angularjs-digest-vs-apply.md └── 2017-03-07-preventing-unwanted-scopes-creation-in-angularjs.md ├── javascript ├── 2015-12-29-insert-item-inside-an-array.md ├── 2016-01-03-improve-nested-conditionals.md ├── 2016-01-04-sorting-strings-with-accented-characters.md ├── 2016-01-05-differences-between-undefined-and-null.md ├── 2016-01-06-writing-a-single-method-for-arrays-and-a-single-element.md ├── 2016-01-07-use-strict-and-get-lazy.md ├── 2016-01-08-converting-a-node-list-to-an-array.md ├── 2016-01-09-template-strings.md ├── 2016-01-10-check-if-a-property-is-in-a-object.md ├── 2016-01-11-hoisting.md ├── 2016-01-12-pseudomandatory-parameters-in-es6-functions.md ├── 2016-01-13-tip-to-measure-performance-of-a-javascript-block.md ├── 2016-01-14-fat-arrow-functions.md ├── 2016-01-15-even-simpler-way-of-using-indexof-as-a-contains-clause.md ├── 2016-01-16-passing-arguments-to-callback-functions.md ├── 2016-01-17-nodejs-run-a-module-if-it-is-not-required.md ├── 2016-01-18-rounding-the-fast-way.md ├── 2016-01-19-safe-string-concatenation.md ├── 2016-01-20-return-objects-to-enable-chaining-of-functions.md ├── 2016-01-21-shuffle-an-array.md ├── 2016-01-22-two-ways-to-empty-an-array.md ├── 2016-01-23-converting-to-number-fast-way.md ├── 2016-01-24-use_===_instead_of_==.md ├── 2016-01-25-Using-immediately-invoked-function-expression.md ├── 2016-01-26-filtering-and-sorting-a-list-of-strings.md ├── 2016-01-27-short-circiut-evaluation-in-js.md ├── 2016-01-28-curry-vs-partial-application.md ├── 2016-01-29-speed-up-recursive-functions-with-memoization.md ├── 2016-01-30-converting-truthy-falsy-values-to-boolean.md ├── 2016-01-31-avoid-modifying-or-passing-arguments-into-other-functions—it-kills-optimization.md ├── 2016-02-01-map-to-the-rescue-adding-order-to-object-properties.md ├── 2016-02-02-create-range-0-n-easily-using-one-line.md ├── 2016-02-03-implementing-asynchronous-loops.md ├── 2016-02-04-assignment-shorthands.md ├── 2016-02-05-observe-dom-changes.md ├── 2016-02-06-deduplicate-an-array.md ├── 2016-02-07-flattening-multidimensional-arrays-in-javascript.md ├── 2016-02-08-advanced-properties.md ├── 2016-02-09-using-json-stringify.md ├── 2016-02-10-array-average-and-median.md ├── 2016-02-11-preventing-unapply-attacks.md ├── 2016-02-12-use-destructuring-in-function-parameters.md ├── 2016-02-13-know-the-passing-mechanism.md ├── 2016-02-14-calculate-the-max-min-value-from-an-array.md ├── 2016-02-15-detect-document-ready-in-pure-js.md ├── 2016-02-16-basics-declarations.md ├── 2016-02-17-reminders-about-reduce-function-usage.md ├── 2016-02-26-extract-unix-timestamp-easily.md ├── 2016-03-03-helpful-console-log-hacks.md ├── 2016-03-16-DOM-event-listening-made-easy.md ├── 2016-04-05-return-values-with-the-new-operator.md ├── 2016-04-21-get-file-extension.md ├── 2016-05-06-use-optional-arguments.md ├── 2016-05-12-make-easy-loop-on-array.md ├── 2016-08-02-copy-to-clipboard.md ├── 2016-08-10-comma-operaton-in-js.md ├── 2016-08-17-break-continue-loop-functional.md ├── 2016-08-25-keyword-var-vs-let.md ├── 2016-10-28-three-useful-hacks.md ├── 2017-01-19-binding-objects-to-functions.md ├── 2017-03-09-working-with-websocket-timeout.md ├── 2017-03-12-3-array-hacks.md ├── 2017-03-16-tapping-for-quick-debugging.md ├── 2017-03-29-recursion-iteration-and-tail-calls-in-js.md ├── 2017-04-03-why-you-should-use-Object.is()-in-equality-comparison.md ├── 2017-04-05-picking-and-rejecting-object-properties.md └── 2017-06-15-looping-over-arrays.md ├── more └── 2017-04-06-vuejs-how-vuejs-makes-a-copy-update-replace-inside-the-data-binding.md └── react ├── 2016-01-02-keys-in-children-components-are-important.md ├── 2017-03-27-state-to-props-maps-with-memory.md ├── 2017-04-04-enhancing-react-components-composition.md └── 2017-04-10-adventurers-guide-to-react.md /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to submit your tip 2 | 3 | To submit a tip to the list, fork the repository and add your tip in a new file in the correct folder (according language). The name of the file should be `2016-xx-xx-name-of-your-tip`. 4 | 5 | Use [this format](POST_TEMPLATE.md) when writing your tip. 6 | 7 | ### Requirements 8 | 9 | - The tip should be readable in less than two minutes 10 | - Adding links to other sites or videos that give more insight is welcome 11 | - Mark JS code with ```js 12 | - Don't mention "JavaScript" in the title (as our tips are about it anyway) 13 | - Use backticks (`) to mark code in the **title** and/or **tip-tldr** fields. _Warning_: Both values must not start with backticks! 14 | - How you can be rewarded: If you have a PayPal, Coinbase or another account, type the url on tip-writer-support. That's all! Now your readers will be able to grab you a beer for your knowledge. 15 | 16 | Once your tip is ready, [issue a pull request](https://help.github.com/articles/using-pull-requests/) with this [PR template](PULL_REQUEST_TEMPLATE.md) and your tip will be reviewed (see below). 17 | 18 | ## Notes 19 | 20 | Leave the date and the tip number as **xx**. When the PR is `ready to merge`, we will tell you the correct numbers. Please also [squash](https://davidwalsh.name/squash-commits-git) your commits. 21 | 22 | ## Tip flow 23 | 24 | **Tip proposal** ⇒ **Tip under review** ⇒ **Tip ready to merge** 25 | 26 | - When you send a tip, it has to pass the review process and while that happens, its status is `under review`. 27 | - Once the tip is reviewed by 5 people and has been given the reviewer's ship it emote (:shipit:), the tip is `ready to merge`. 28 | 29 | 30 | We are looking forward to your contribution! 31 | -------------------------------------------------------------------------------- /CONTRIBUTING_es_ES.md: -------------------------------------------------------------------------------- 1 | # Como enviar tu tip 2 | 3 | Para agregar tu tip a la lista, debes forkear el repositorio y agregar tu tip en un nuevo archivos en el direcctorio correcto (de acuero el lenguage). El nombre del archivo deberia ser '2016-xx-xx-nombre-de-tu-tip'. 4 | 5 | Utilice [este formato](https://github.com/loverajoel/jstips/blob/gh-pages/POST_TEMPLATE.md) para escribir su tip. 6 | 7 | ### Requisitos 8 | 9 | - Su tip debe ser legible en menos de dos minutos. 10 | - Puede añadir enlaces a otros sitios o videos que dan una visión más clara es bienvenido. 11 | - Se marcará el código JS con ```js 12 | - No Mencione "JavaScript" en el título (como nuestros consejos son respecto de todos modos) 13 | - Use comillas invertidas (`) para marcar código en el campos **title** y/o **tip-tldr**. _Precaucion_: Ambos valores no deben comenzar con acentos abiertos! 14 | 15 | 16 | Una vez que su tip está listo, [issue a pull request](https://help.github.com/articles/using-pull-requests/) con esta [PR template](https://github.com/loverajoel/jstips/blob/gh-pages/PULL_REQUEST_TEMPLATE.md) y su tip será revisado (véase más adelante). 17 | 18 | # Notas 19 | 20 | Deje la fecha y el número de tip con **xx**. Cuando el PR es `ready to merge`, le diremos los números correctos. Por favor, también [squash] (https://davidwalsh.name/squash-commits-git) sus confirmaciones. 21 | 22 | # Flujo del Tip 23 | 24 | **Tip proposal** ⇒ **Tip under review** ⇒ **Tip ready to merge** 25 | 26 | - Cuando se envía un tip, tiene que pasar el proceso de revisión y mientras eso sucede, su estado es `under review`. 27 | - Después de que el tip sea revisado por 5 personas y han dado (:shipit:), el tip esta `ready to merge`. -------------------------------------------------------------------------------- /CONTRIBUTING_zh_CN.md: -------------------------------------------------------------------------------- 1 | # 如何提交小知识 2 | 3 | 将小知识提交到本列表,`fork`此仓库(repository)然后将的小知识放到对应文件夹(根据语言)的新文件中。新文件的名字应该像`2016-xx-xx-name-of-your-tip`这样。 4 | 5 | 书写小知识时请按照[这个格式](https://github.com/loverajoel/jstips/blob/gh-pages/POST_TEMPLATE.md)。 6 | 7 | ### 要求 8 | - 小知识可以在两分钟内阅读完。 9 | - 增加其他网站或视频的链接提供更深讲解更佳 10 | - 使用 ```js 标记JS代码 11 | - 无序在标题处提及"JavaScript"(因为我们的小知识全是关于它的) 12 | - 使用反引号(`) 标记**标题**或**tip-tldr**中的代码 ‐ _警告_:它们都不能以反引号开头 13 | 14 | 当你的小知识准备就绪了, 根据这个[PR 模板](https://github.com/loverajoel/jstips/blob/gh-pages/GIT_TEMPLATE.md),[发布一个pull request](https://help.github.com/articles/using-pull-requests/)你的小知识将被审查(见下文)。 15 | 16 | # 提示 17 | 18 | 将时间和小知识number保留为**xx**。当PR为`ready to merge`状态时,我们将告诉你正确的数字。请同时[squash](https://davidwalsh.name/squash-commits-git)你的commits. 19 | 20 | # 工作流程 21 | 22 | **Tip 提交** ⇒ **Tip 审查** ⇒ **Tip 通过并发布** 23 | 24 | - 当你提交 tip 时,如果 tip 正在通过审查,此时 tip 状态为 `under review`。 25 | - 如果 tip 经过5个人的审查,而且他們都给了 :shipit:,tip 将会被合并(`merge`)到 tip 列表中。 26 | 27 | 期待您的贡献! -------------------------------------------------------------------------------- /CONTRIBUTING_zh_TW.md: -------------------------------------------------------------------------------- 1 | # 如何提交你的 tip 2 | 3 | 如果要提交 tip 到目錄,fork 這個儲存庫(repository)並加入你的 tip 到檔案內,放入到正確的資料夾(根據語系)。檔案名稱應該為 `2016-xx-xx-name-of-your-tip`。 4 | 5 | 當你撰寫你的 tip 時,請使用[這個格式](POST_TEMPLATE.md)。 6 | 7 | ### 要求 8 | 9 | - tip 應該至少可以在兩分鐘內讀懂。 10 | - 你可以連結到其他的網站或者是影片讓我們了解更多。 11 | - 程式碼區塊使用 ```js。 12 | - 避免在 title 提到「JavaScript」(因為我們的 tips 都是與 JavaScript 相關的)。 13 | - 使用反引號(`)來標記程式碼 - _警告_:tip **標題**和 **tip-tldr** 不要使用反引號。 14 | 15 | 16 | 當你的 tip 準備好了,依據這個 [PR 樣板](PULL_REQUEST_TEMPLATE.md),[發送一個 PR](https://help.github.com/articles/using-pull-requests/) 你的 tip 將會被校閱。每天都會有 tip 從可用的 PR 中被合併(merged)。 17 | 18 | ## 注意 19 | 20 | 使用 **xx** 為日期和 tip 的編號。當我們決定合併你的 PR 你可以把它們增加並 [squash](https://davidwalsh.name/squash-commits-git) 到你的 commits。 21 | 22 | ## Tip 工作流程 23 | 24 | **Tip 發送** ⇒ **Tip 審查** ⇒ **Tip 接受並發布** 25 | 26 | - 當你提交 tip 時,如果 tip 正在校閱流程,則 tip 狀態為 `under-review`。 27 | - 如果 tip 經過 5 位專業的人士校閱,而且他們都給了 :shipit:,tip 將會被合併(`merge`)到 tip 清單。 28 | -------------------------------------------------------------------------------- /POST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: *post 3 | 4 | title: Demo post 5 | tip-number: xx 6 | tip-username: tip_js 7 | tip-username-profile: https://twitter.com/tips_js 8 | tip-tldr: Just a demo 9 | 10 | 11 | 12 | categories: 13 | - en 14 | --- 15 | 16 | content here 17 | ### Subtitles format 18 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## [Title here] 2 | ## TL;DR; 3 | [content here] 4 | ## Username 5 | [twitter account link or github account link ej: [@tips-js](https://twitter.com/tips_js)] 6 | ## Extra 7 | [content here] -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-05-differences-between-undefined-and-null.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Differences between `undefined` and `null` 5 | tip-number: 05 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: Understanding the differences between `undefined` and `null`. 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /en/differences-between-undefined-and-null/ 13 | 14 | categories: 15 | - en 16 | - javascript 17 | --- 18 | 19 | - `undefined` means a variable has not been declared, or has been declared but has not yet been assigned a value 20 | - `null` is an assignment value that means "no value" 21 | - Javascript sets unassigned variables with a default value of `undefined` 22 | - Javascript never sets a value to `null`. It is used by programmers to indicate that a `var` has no value. 23 | - `undefined` is not valid in JSON while `null` is 24 | - `undefined` typeof is `undefined` 25 | - `null` typeof is an `object`. [Why?](http://www.2ality.com/2013/10/typeof-null.html) 26 | - Both are primitives 27 | - Both are [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) 28 | (`Boolean(undefined) // false`, `Boolean(null) // false`) 29 | - You can know if a variable is [undefined](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined) 30 | 31 | ```javascript 32 | typeof variable === "undefined" 33 | ``` 34 | - You can check if a variable is [null](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null) 35 | 36 | ```javascript 37 | variable === null 38 | ``` 39 | - The **equality** operator considers them equal, but the **identity** doesn't 40 | 41 | ```javascript 42 | null == undefined // true 43 | 44 | null === undefined // false 45 | ``` -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-06-writing-a-single-method-for-arrays-and-a-single-element.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Writing a single method for arrays and a single element 5 | tip-number: 06 6 | tip-username: mattfxyz 7 | tip-username-profile: https://twitter.com/mattfxyz 8 | tip-tldr: Rather than writing separate methods to handle an array and a single element parameter, write your functions so they can handle both. This is similar to how some of jQuery's functions work (`css` will modify everything matched by the selector). 9 | 10 | redirect_from: 11 | - /en/writing-a-single-method-for-arrays-and-a-single-element/ 12 | 13 | categories: 14 | - en 15 | - javascript 16 | --- 17 | 18 | Rather than writing separate methods to handle an array and a single element parameter, write your functions so they can handle both. This is similar to how some of jQuery's functions work (`css` will modify everything matched by the selector). 19 | 20 | You just have to concat everything into an array first. `Array.concat` will accept an array or a single element. 21 | 22 | ```javascript 23 | function printUpperCase(words) { 24 | var elements = [].concat(words || []); 25 | for (var i = 0; i < elements.length; i++) { 26 | console.log(elements[i].toUpperCase()); 27 | } 28 | } 29 | ``` 30 | 31 | `printUpperCase` is now ready to accept a single node or an array of nodes as its parameter. It also avoids the potential `TypeError` that would be thrown if no parameter was passed. 32 | 33 | ```javascript 34 | printUpperCase("cactus"); 35 | // => CACTUS 36 | printUpperCase(["cactus", "bear", "potato"]); 37 | // => CACTUS 38 | // BEAR 39 | // POTATO 40 | ``` 41 | -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-09-template-strings.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Template Strings 5 | tip-number: 09 6 | tip-username: JakeRawr 7 | tip-username-profile: https://github.com/JakeRawr 8 | tip-tldr: As of ES6, JS now has template strings as an alternative to the classic end quotes strings. 9 | 10 | redirect_from: 11 | - /en/template-strings/ 12 | 13 | categories: 14 | - en 15 | - javascript 16 | --- 17 | 18 | As of ES6, JS now has template strings as an alternative to the classic end quotes strings. 19 | 20 | Ex: 21 | Normal string 22 | 23 | ```javascript 24 | var firstName = 'Jake'; 25 | var lastName = 'Rawr'; 26 | console.log('My name is ' + firstName + ' ' + lastName); 27 | // My name is Jake Rawr 28 | ``` 29 | Template String 30 | 31 | ```javascript 32 | var firstName = 'Jake'; 33 | var lastName = 'Rawr'; 34 | console.log(`My name is ${firstName} ${lastName}`); 35 | // My name is Jake Rawr 36 | ``` 37 | 38 | You can do multi-line strings without `\n`, perform simple logic (ie 2+3) or even use the [ternary operator](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) inside `${}` in template strings. 39 | 40 | ```javascript 41 | var val1 = 1, val2 = 2; 42 | console.log(`${val1} is ${val1 < val2 ? 'less than': 'greater than'} ${val2}`) 43 | // 1 is less than 2 44 | ``` 45 | 46 | You are also able to modify the output of template strings using a function; they are called [tagged template strings](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings#Tagged_template_strings) for example usages of tagged template strings. 47 | 48 | You may also want to [read](https://hacks.mozilla.org/2015/05/es6-in-depth-template-strings-2) to understand template strings more. 49 | -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-11-hoisting.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Hoisting 5 | tip-number: 11 6 | tip-username: squizzleflip 7 | tip-username-profile: https://twitter.com/squizzleflip 8 | tip-tldr: Understanding hoisting will help you organize your function scope. 9 | 10 | redirect_from: 11 | - /en/hoisting/ 12 | 13 | categories: 14 | - en 15 | - javascript 16 | --- 17 | 18 | Understanding [hoisting](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting) will help you organize your function scope. Just remember, variable declarations and function definitions are hoisted to the top. Variable definitions are not, even if you declare and define a variable on the same line. Also, a variable **declaration** lets the system know that the variable exists while **definition** assigns it a value. 19 | 20 | ```javascript 21 | function doTheThing() { 22 | // ReferenceError: notDeclared is not defined 23 | console.log(notDeclared); 24 | 25 | // Outputs: undefined 26 | console.log(definedLater); 27 | var definedLater; 28 | 29 | definedLater = 'I am defined!' 30 | // Outputs: 'I am defined!' 31 | console.log(definedLater) 32 | 33 | // Outputs: undefined 34 | console.log(definedSimulateneously); 35 | var definedSimulateneously = 'I am defined!' 36 | // Outputs: 'I am defined!' 37 | console.log(definedSimulateneously) 38 | 39 | // Outputs: 'I did it!' 40 | doSomethingElse(); 41 | 42 | function doSomethingElse(){ 43 | console.log('I did it!'); 44 | } 45 | 46 | // TypeError: undefined is not a function 47 | functionVar(); 48 | 49 | var functionVar = function(){ 50 | console.log('I did it!'); 51 | } 52 | } 53 | ``` 54 | 55 | To make things easier to read, declare all of your variables at the top of your function scope so it is clear which scope the variables are coming from. Define your variables before you need to use them. Define your functions at the bottom of your scope to keep them out of your way. 56 | -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-12-pseudomandatory-parameters-in-es6-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Pseudomandatory parameters in ES6 functions 5 | tip-number: 12 6 | tip-username: Avraam Mavridis 7 | tip-username-profile: https://github.com/AvraamMavridis 8 | tip-tldr: In many programming languages the parameters of a function are by default mandatory and the developer has to explicitly define that a parameter is optional. 9 | 10 | redirect_from: 11 | - /en/pseudomandatory-parameters-in-es6-functions/ 12 | 13 | categories: 14 | - en 15 | - javascript 16 | --- 17 | 18 | In many programming languages the parameters of a function are by default mandatory and the developer has to explicitly define that a parameter is optional. In Javascript, every parameter is optional, but we can enforce this behavior without messing with the actual body of a function, taking advantage of [**es6's default values for parameters**] (http://exploringjs.com/es6/ch_parameter-handling.html#sec_parameter-default-values) feature. 19 | 20 | ```javascript 21 | const _err = function( message ){ 22 | throw new Error( message ); 23 | } 24 | 25 | const getSum = (a = _err('a is not defined'), b = _err('b is not defined')) => a + b 26 | 27 | getSum( 10 ) // throws Error, b is not defined 28 | getSum( undefined, 10 ) // throws Error, a is not defined 29 | ``` 30 | 31 | `_err` is a function that immediately throws an Error. If no value is passed for one of the parameters, the default value is going to be used, `_err` will be called and an Error will be thrown. You can see more examples for the **default parameters feature** on [Mozilla's Developer Network ](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/default_parameters) -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-13-tip-to-measure-performance-of-a-javascript-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Tip to measure performance of a javascript block 5 | tip-number: 13 6 | tip-username: manmadareddy 7 | tip-username-profile: https://twitter.com/manmadareddy 8 | tip-tldr: For quickly measuring performance of a javascript block, we can use the console functions like `console.time(label)` and `console.timeEnd(label)` 9 | 10 | redirect_from: 11 | - /en/tip-to-measure-performance-of-a-javascript-block/ 12 | 13 | categories: 14 | - en 15 | - javascript 16 | --- 17 | 18 | For quickly measuring performance of a javascript block, we can use the console functions like 19 | [`console.time(label)`](https://developer.chrome.com/devtools/docs/console-api#consoletimelabel) and [`console.timeEnd(label)`](https://developer.chrome.com/devtools/docs/console-api#consoletimeendlabel) 20 | 21 | ```javascript 22 | console.time("Array initialize"); 23 | var arr = new Array(100), 24 | len = arr.length, 25 | i; 26 | 27 | for (i = 0; i < len; i++) { 28 | arr[i] = new Object(); 29 | }; 30 | console.timeEnd("Array initialize"); // Outputs: Array initialize: 0.711ms 31 | ``` 32 | 33 | More info: 34 | [Console object](https://github.com/DeveloperToolsWG/console-object), 35 | [Javascript benchmarking](https://mathiasbynens.be/notes/javascript-benchmarking) 36 | 37 | Demo: [jsfiddle](https://jsfiddle.net/meottb62/) - [codepen](http://codepen.io/anon/pen/JGJPoa) (outputs in browser console) 38 | 39 | > Note: As [Mozilla](https://developer.mozilla.org/en-US/docs/Web/API/Console/time) suggested don't use this for production sites, use it for development purposes only. -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-16-passing-arguments-to-callback-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Passing arguments to callback functions 5 | tip-number: 16 6 | tip-username: minhazav 7 | tip-username-profile: https://twitter.com/minhazav 8 | tip-tldr: By default you cannot pass arguments to a callback function, but you can take advantage of the closure scope in Javascript to pass arguments to callback functions. 9 | 10 | redirect_from: 11 | - /en/passing-arguments-to-callback-functions/ 12 | 13 | categories: 14 | - en 15 | - javascript 16 | --- 17 | 18 | By default you cannot pass arguments to a callback function. For example: 19 | 20 | ```js 21 | function callback() { 22 | console.log('Hi human'); 23 | } 24 | 25 | document.getElementById('someelem').addEventListener('click', callback); 26 | 27 | ``` 28 | 29 | You can take advantage of the closure scope in Javascript to pass arguments to callback functions. Check this example: 30 | 31 | ```js 32 | function callback(a, b) { 33 | return function() { 34 | console.log('sum = ', (a+b)); 35 | } 36 | } 37 | 38 | var x = 1, y = 2; 39 | document.getElementById('someelem').addEventListener('click', callback(x, y)); 40 | 41 | ``` 42 | 43 | ### What are closures? 44 | 45 | Closures are functions that refer to independent (free) variables. In other words, the function defined in the closure 'remembers' the environment in which it was created. [Check MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) to learn more. 46 | 47 | So this way the arguments `x` and `y` are in scope of the callback function when it is called. 48 | 49 | Another method to do this is using the `bind` method. For example: 50 | 51 | ```js 52 | var alertText = function(text) { 53 | alert(text); 54 | }; 55 | 56 | document.getElementById('someelem').addEventListener('click', alertText.bind(this, 'hello')); 57 | ``` 58 | There is a very slight difference in performance of both methods, checkout [jsperf](http://jsperf.com/bind-vs-closure-23). 59 | -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-17-nodejs-run-a-module-if-it-is-not-required.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Node.js - Run a module if it is not `required` 5 | tip-number: 17 6 | tip-username: odsdq 7 | tip-username-profile: https://twitter.com/odsdq 8 | tip-tldr: In node, you can tell your program to do two different things depending on whether the code is run from `require('./something.js')` or `node something.js`. This is useful if you want to interact with one of your modules independently. 9 | 10 | redirect_from: 11 | - /en/nodejs-run-a-module-if-it-is-not-required/ 12 | 13 | categories: 14 | - en 15 | - javascript 16 | --- 17 | 18 | In node, you can tell your program to do two different things depending on whether the code is run from `require('./something.js')` or `node something.js`. This is useful if you want to interact with one of your modules independently. 19 | 20 | ```js 21 | if (!module.parent) { 22 | // ran with `node something.js` 23 | app.listen(8088, function() { 24 | console.log('app listening on port 8088'); 25 | }) 26 | } else { 27 | // used with `require('/.something.js')` 28 | module.exports = app; 29 | } 30 | ``` 31 | 32 | See [the documentation for modules](https://nodejs.org/api/modules.html#modules_module_parent) for more info. -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-19-safe-string-concatenation.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Safe string concatenation 5 | tip-number: 19 6 | tip-username: gogainda 7 | tip-username-profile: https://twitter.com/gogainda 8 | tip-tldr: Suppose you have a couple of variables with unknown types and you want to concatenate them in a string. To be sure that the arithmetical operation is not be applied during concatenation, use concat 9 | 10 | redirect_from: 11 | - /en/safe-string-concatenation/ 12 | 13 | categories: 14 | - en 15 | - javascript 16 | --- 17 | 18 | Suppose you have a couple of variables with unknown types and you want to concatenate them in a string. To be sure that the arithmetical operation is not be applied during concatenation, use `concat`: 19 | 20 | ```javascript 21 | var one = 1; 22 | var two = 2; 23 | var three = '3'; 24 | 25 | var result = ''.concat(one, two, three); //"123" 26 | ``` 27 | 28 | This way of concatenting does exactly what you'd expect. In contrast, concatenation with pluses might lead to unexpected results: 29 | 30 | ```javascript 31 | var one = 1; 32 | var two = 2; 33 | var three = '3'; 34 | 35 | var result = one + two + three; //"33" instead of "123" 36 | ``` 37 | 38 | Speaking about performance, compared to the `join` [type](http://www.sitepoint.com/javascript-fast-string-concatenation/) of concatenation, the speed of `concat` is pretty much the same. 39 | 40 | You can read more about the `concat` function on MDN [page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/concat). -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-20-return-objects-to-enable-chaining-of-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Return objects to enable chaining of functions 5 | tip-number: 20 6 | tip-username: WakeskaterX 7 | tip-username-profile: https://twitter.com/WakeStudio 8 | tip-tldr: When creating functions on an object in Object Oriented Javascript, returning the object in the function will enable you to chain functions together. 9 | 10 | redirect_from: 11 | - /en/return-objects-to-enable-chaining-of-functions/ 12 | 13 | categories: 14 | - en 15 | - javascript 16 | --- 17 | 18 | When creating functions on an object in Object Oriented Javascript, returning the object in the function will enable you to chain functions together. 19 | 20 | ```js 21 | function Person(name) { 22 | this.name = name; 23 | 24 | this.sayName = function() { 25 | console.log("Hello my name is: ", this.name); 26 | return this; 27 | }; 28 | 29 | this.changeName = function(name) { 30 | this.name = name; 31 | return this; 32 | }; 33 | } 34 | 35 | var person = new Person("John"); 36 | person.sayName().changeName("Timmy").sayName(); 37 | ``` -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-21-shuffle-an-array.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Shuffle an Array 5 | tip-number: 21 6 | tip-username: 0xmtn 7 | tip-username-profile: https://github.com/0xmtn/ 8 | tip-tldr: Fisher-Yates Shuffling it's an algorithm to shuffle an array. 9 | 10 | redirect_from: 11 | - /en/shuffle-an-array/ 12 | 13 | categories: 14 | - en 15 | - javascript 16 | --- 17 | 18 | This snippet here uses [Fisher-Yates Shuffling](https://www.wikiwand.com/en/Fisher%E2%80%93Yates_shuffle) Algorithm to shuffle a given array. 19 | 20 | ```javascript 21 | function shuffle(arr) { 22 | var i, 23 | j, 24 | temp; 25 | for (i = arr.length - 1; i > 0; i--) { 26 | j = Math.floor(Math.random() * (i + 1)); 27 | temp = arr[i]; 28 | arr[i] = arr[j]; 29 | arr[j] = temp; 30 | } 31 | return arr; 32 | }; 33 | ``` 34 | An example: 35 | 36 | ```javascript 37 | var a = [1, 2, 3, 4, 5, 6, 7, 8]; 38 | var b = shuffle(a); 39 | console.log(b); 40 | // [2, 7, 8, 6, 5, 3, 1, 4] 41 | ``` -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-23-converting-to-number-fast-way.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Converting to number fast way 5 | tip-number: 23 6 | tip-username: sonnyt 7 | tip-username-profile: http://twitter.com/sonnyt 8 | tip-tldr: Converting strings to numbers is extremely common. The easiest and fastest way to achieve that would be using the + operator. 9 | 10 | redirect_from: 11 | - /en/converting-to-number-fast-way/ 12 | 13 | categories: 14 | - en 15 | - javascript 16 | --- 17 | 18 | Converting strings to numbers is extremely common. The easiest and fastest ([jsPerf](https://jsperf.com/number-vs-parseint-vs-plus/29)) way to achieve that would be using the `+` (plus) operator. 19 | 20 | ```javascript 21 | var one = '1'; 22 | 23 | var numberOne = +one; // Number 1 24 | ``` 25 | 26 | You can also use the `-` (minus) operator which type-converts the value into number but also negates it. 27 | 28 | ```javascript 29 | var one = '1'; 30 | 31 | var negativeNumberOne = -one; // Number -1 32 | ``` 33 | -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-24-use_===_instead_of_==.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Use === instead of == 5 | tip-number: 24 6 | tip-username: bhaskarmelkani 7 | tip-username-profile: https://www.twitter.com/bhaskarmelkani 8 | tip-tldr: The `==` (or `!=`) operator performs an automatic type conversion if needed. The `===` (or `!==`) operator will not perform any conversion. It compares the value and the type, which could be considered faster ([jsPref](http://jsperf.com/strictcompare)) than `==`. 9 | 10 | redirect_from: 11 | - /en/use_===_instead_of_==/ 12 | 13 | categories: 14 | - en 15 | - javascript 16 | --- 17 | 18 | The `==` (or `!=`) operator performs an automatic type conversion if needed. The `===` (or `!==`) operator will not perform any conversion. It compares the value and the type, which could be considered faster ([jsPref](http://jsperf.com/strictcompare)) than `==`. 19 | 20 | ```js 21 | [10] == 10 // is true 22 | [10] === 10 // is false 23 | 24 | '10' == 10 // is true 25 | '10' === 10 // is false 26 | 27 | [] == 0 // is true 28 | [] === 0 // is false 29 | 30 | '' == false // is true but true == "a" is false 31 | '' === false // is false 32 | 33 | ``` 34 | -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-25-Using-immediately-invoked-function-expression.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Using immediately invoked function expression 5 | tip-number: 25 6 | tip-username: rishantagarwal 7 | tip-username-profile: https://github.com/rishantagarwal 8 | tip-tldr: Called as "Iffy" ( IIFE - immediately invoked function expression) is an anonymous function expression that is immediately invoked and has some important uses in Javascript. 9 | 10 | 11 | redirect_from: 12 | - /en/Using-immediately-invoked-function-expression/ 13 | 14 | categories: 15 | - en 16 | - javascript 17 | --- 18 | 19 | Called as "Iffy" ( IIFE - immediately invoked function expression) is an anonymous function expression that is immediately invoked and has some important uses in Javascript. 20 | 21 | ```javascript 22 | 23 | (function() { 24 | // Do something​ 25 | } 26 | )() 27 | 28 | ``` 29 | 30 | It is an anonymous function expression that is immediately invoked, and it has some particularly important uses in JavaScript. 31 | 32 | The pair of parenthesis surrounding the anonymous function turns the anonymous function into a function expression or variable expression. So instead of a simple anonymous function in the global scope, or wherever it was defined, we now have an unnamed function expression. 33 | 34 | Similarly, we can even create a named, immediately invoked function expression: 35 | 36 | ```javascript 37 | (someNamedFunction = function(msg) { 38 | console.log(msg || "Nothing for today !!") 39 | }) (); // Output --> Nothing for today !!​ 40 | ​ 41 | someNamedFunction("Javascript rocks !!"); // Output --> Javascript rocks !! 42 | someNamedFunction(); // Output --> Nothing for today !!​ 43 | ``` 44 | 45 | For more details, check the following URL's - 46 | 1. [Link 1](https://blog.mariusschulz.com/2016/01/13/disassembling-javascripts-iife-syntax) 47 | 2. [Link 2](http://javascriptissexy.com/12-simple-yet-powerful-javascript-tips/) 48 | 49 | Performance: 50 | [jsPerf](http://jsperf.com/iife-with-call) -------------------------------------------------------------------------------- /_posts/en/javascript/2016-01-30-converting-truthy-falsy-values-to-boolean.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Converting truthy/falsy values to boolean 5 | tip-number: 30 6 | tip-username: hakhag 7 | tip-username-profile: https://github.com/hakhag 8 | tip-tldr: Logical operators are a core part of JavaScript, here you can see a a way you always get a true or false no matter what was given to it. 9 | 10 | 11 | redirect_from: 12 | - /en/converting-truthy-falsy-values-to-boolean/ 13 | 14 | categories: 15 | - en 16 | - javascript 17 | --- 18 | 19 | You can convert a [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) or [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) value to true boolean with the `!!` operator. 20 | 21 | ```js 22 | !!"" // false 23 | !!0 // false 24 | !!null // false 25 | !!undefined // false 26 | !!NaN // false 27 | 28 | !!"hello" // true 29 | !!1 // true 30 | !!{} // true 31 | !![] // true 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /_posts/en/javascript/2016-02-09-using-json-stringify.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Using JSON.Stringify 5 | tip-number: 40 6 | tip-username: vamshisuram 7 | tip-username-profile: https://github.com/vamshisuram 8 | tip-tldr: Create string from selected properties of JSON object. 9 | 10 | 11 | redirect_from: 12 | - /en/using-json-stringify/ 13 | 14 | categories: 15 | - en 16 | - javascript 17 | --- 18 | 19 | Let's say there is an object with properties "prop1", "prop2", "prop3". 20 | We can pass __additional params__ to __JSON.stringify__ to selectively write properties of the object to string like: 21 | 22 | ```javascript 23 | var obj = { 24 | 'prop1': 'value1', 25 | 'prop2': 'value2', 26 | 'prop3': 'value3' 27 | }; 28 | 29 | var selectedProperties = ['prop1', 'prop2']; 30 | 31 | var str = JSON.stringify(obj, selectedProperties); 32 | 33 | // str 34 | // {"prop1":"value1","prop2":"value2"} 35 | 36 | ``` 37 | 38 | The __"str"__ will contain only info on selected properties only. 39 | 40 | Instead of array we can pass a function also. 41 | 42 | ```javascript 43 | 44 | function selectedProperties(key, val) { 45 | // the first val will be the entire object, key is empty string 46 | if (!key) { 47 | return val; 48 | } 49 | 50 | if (key === 'prop1' || key === 'prop2') { 51 | return val; 52 | } 53 | 54 | return; 55 | } 56 | ``` 57 | 58 | The last optional param it takes is to modify the way it writes the object to string. 59 | 60 | ```javascript 61 | var str = JSON.stringify(obj, selectedProperties, '\t\t'); 62 | 63 | /* str output with double tabs in every line. 64 | { 65 | "prop1": "value1", 66 | "prop2": "value2" 67 | } 68 | */ 69 | 70 | ``` 71 | 72 | -------------------------------------------------------------------------------- /_posts/en/javascript/2016-02-10-array-average-and-median.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Array average and median 5 | tip-number: 41 6 | tip-username: soyuka 7 | tip-username-profile: https://github.com/soyuka 8 | tip-tldr: Calculate the average and median from array values 9 | 10 | 11 | redirect_from: 12 | - /en/array-average-and-median/ 13 | 14 | categories: 15 | - en 16 | - javascript 17 | --- 18 | 19 | The following examples will be based on the following array: 20 | 21 | ```javascript 22 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 23 | ``` 24 | 25 | To get the average, we have to sum up numbers and then divide by the number of values. Steps are: 26 | - get the array length 27 | - sum up values 28 | - get the average (`sum/length`) 29 | 30 | ```javascript 31 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 32 | let sum = values.reduce((previous, current) => current += previous); 33 | let avg = sum / values.length; 34 | // avg = 28 35 | ``` 36 | 37 | Or: 38 | 39 | ```javascript 40 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 41 | let count = values.length; 42 | values = values.reduce((previous, current) => current += previous); 43 | values /= count; 44 | // avg = 28 45 | ``` 46 | 47 | Now, to get the median steps are: 48 | - sort the array 49 | - get the arethmic mean of the middle values 50 | 51 | ```javascript 52 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 53 | values.sort((a, b) => a - b); 54 | let lowMiddle = Math.floor((values.length - 1) / 2); 55 | let highMiddle = Math.ceil((values.length - 1) / 2); 56 | let median = (values[lowMiddle] + values[highMiddle]) / 2; 57 | // median = 13,5 58 | ``` 59 | 60 | With a bitwise operator: 61 | 62 | ```javascript 63 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 64 | values.sort((a, b) => a - b); 65 | let median = (values[(values.length - 1) >> 1] + values[values.length >> 1]) / 2 66 | // median = 13,5 67 | ``` 68 | -------------------------------------------------------------------------------- /_posts/en/javascript/2016-02-14-calculate-the-max-min-value-from-an-array.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Calculate the Max/Min value from an array 5 | tip-number: 45 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: Ways to use the built-in functions Math.max() and Math.min() with arrays of numbers 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /en/calculate-the-max-min-value-from-an-array/ 13 | 14 | categories: 15 | - en 16 | - javascript 17 | --- 18 | 19 | The built-in functions [Math.max()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max) and [Math.min()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min) find the maximum and minimum value of the arguments, respectively. 20 | 21 | ```js 22 | Math.max(1, 2, 3, 4); // 4 23 | Math.min(1, 2, 3, 4); // 1 24 | ``` 25 | 26 | These functions will not work as-is with arrays of numbers. However, there are some ways around this. 27 | 28 | [`Function.prototype.apply()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) allows you to call a function with a given `this` value and an _array_ of arguments. 29 | 30 | ```js 31 | var numbers = [1, 2, 3, 4]; 32 | Math.max.apply(null, numbers) // 4 33 | Math.min.apply(null, numbers) // 1 34 | ``` 35 | 36 | Passing the `numbers` array as the second argument of `apply()` results in the function being called with all values in the array as parameters. 37 | 38 | A simpler, ES2015 way of accomplishing this is with the new [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator). 39 | 40 | ```js 41 | var numbers = [1, 2, 3, 4]; 42 | Math.max(...numbers) // 4 43 | Math.min(...numbers) // 1 44 | ``` 45 | 46 | This operator causes the values in the array to be expanded, or "spread", into the function's arguments. 47 | -------------------------------------------------------------------------------- /_posts/en/javascript/2016-02-15-detect-document-ready-in-pure-js.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Detect document ready in pure JS 5 | tip-number: 46 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: The cross-browser way to check if the document has loaded in pure JavaScript 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /en/detect-document-ready-in-pure-js/ 13 | 14 | categories: 15 | - en 16 | - javascript 17 | --- 18 | 19 | The cross-browser way to check if the document has loaded in pure JavaScript is using [`readyState`](https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState). 20 | 21 | ```js 22 | if (document.readyState === 'complete') { 23 | // The page is fully loaded 24 | } 25 | ``` 26 | 27 | You can detect when the document is ready... 28 | 29 | 30 | ```js 31 | let stateCheck = setInterval(() => { 32 | if (document.readyState === 'complete') { 33 | clearInterval(stateCheck); 34 | // document ready 35 | } 36 | }, 100); 37 | ``` 38 | 39 | or with [onreadystatechange](https://developer.mozilla.org/en-US/docs/Web/Events/readystatechange)... 40 | 41 | 42 | ```js 43 | document.onreadystatechange = () => { 44 | if (document.readyState === 'complete') { 45 | // document ready 46 | } 47 | }; 48 | ``` 49 | 50 | Use `document.readyState === 'interactive'` to detect when the DOM is ready. 51 | -------------------------------------------------------------------------------- /_posts/en/javascript/2016-02-26-extract-unix-timestamp-easily.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Easiest way to extract unix timestamp in JS 5 | tip-number: 49 6 | tip-username: nmrony 7 | tip-username-profile: https://github.com/nmrony 8 | tip-tldr: In Javascript you can easily get the unix timestamp 9 | 10 | redirect_from: 11 | - /en/extract-unix-timestamp-easily/ 12 | 13 | categories: 14 | - en 15 | - javascript 16 | --- 17 | 18 | We frequently need to calculate with unix timestamp. There are several ways to grab the timestamp. For current unix timestamp easiest and fastest way is 19 | 20 | ```js 21 | const dateTime = Date.now(); 22 | const timestamp = Math.floor(dateTime / 1000); 23 | ``` 24 | or 25 | 26 | ```js 27 | const dateTime = new Date().getTime(); 28 | const timestamp = Math.floor(dateTime / 1000); 29 | ``` 30 | 31 | To get unix timestamp of a specific date pass `YYYY-MM-DD` or `YYYY-MM-DDT00:00:00Z` as parameter of `Date` constructor. For example 32 | 33 | ```js 34 | const dateTime = new Date('2012-06-08').getTime(); 35 | const timestamp = Math.floor(dateTime / 1000); 36 | ``` 37 | You can just add a `+` sign also when declaring a `Date` object like below 38 | 39 | ```js 40 | const dateTime = +new Date(); 41 | const timestamp = Math.floor(dateTime / 1000); 42 | ``` 43 | or for specific date 44 | 45 | ```js 46 | const dateTime = +new Date('2012-06-08'); 47 | const timestamp = Math.floor(dateTime / 1000); 48 | ``` 49 | Under the hood the runtime calls `valueOf` method of the `Date` object. Then the unary `+` operator calls `toNumber()` with that returned value. For detailed explanation please check the following links 50 | 51 | * [Date.prototype.valueOf](http://es5.github.io/#x15.9.5.8) 52 | * [Unary + operator](http://es5.github.io/#x11.4.6) 53 | * [toNumber()](http://es5.github.io/#x9.3) 54 | * [Date Javascript MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) 55 | * [Date.parse()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse) 56 | -------------------------------------------------------------------------------- /_posts/en/javascript/2016-08-02-copy-to-clipboard.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Copy to Clipboard 5 | tip-number: 56 6 | tip-username: loverajoel 7 | tip-username-profile: https://twitter.com/loverajoel 8 | tip-tldr: This week I had to create a common "Copy to Clipboard" button, I've never created one before and I want to share how I made it. 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /en/copy-to-clipboard/ 13 | 14 | categories: 15 | - en 16 | - javascript 17 | --- 18 | 19 | This is a simple tip, this week I had to create a common "Copy to Clipboard" button, I've never created one before and I want to share how I made it. 20 | It's easy, the bad thing is that we must add an `` with the text to be copied to the DOM. Then, we selected the content and execute the copy command with [execCommand](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand). 21 | `execCommand('copy')` will copy the actual selected content. 22 | 23 | Also, this command that now is [supported](http://caniuse.com/#search=execCommand) by all the latest version of browsers, allows us to execute another system commands like `copy`, `cut`, `paste`, and make changes like fonts color, size, and much more. 24 | 25 | ```js 26 | document.querySelector('#input').select(); 27 | document.execCommand('copy'); 28 | ``` 29 | 30 | ##### Playground 31 |
32 | JS Bin on jsbin.com 33 |
34 | -------------------------------------------------------------------------------- /_posts/en/javascript/2016-08-10-comma-operaton-in-js.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Comma operator in JS 5 | tip-number: 57 6 | tip-username: bhaskarmelkani 7 | tip-username-profile: https://www.twitter.com/bhaskarmelkani 8 | tip-tldr: When placed in an expression, it evaluates every expression from left to right and returns the last one. 9 | 10 | redirect_from: 11 | - /en/comma-operaton-in-js/ 12 | 13 | categories: 14 | - en 15 | - javascript 16 | --- 17 | Apart from being just a delimiter, the comma operator allows you to put multiple statements in a place where one statement is expected. 18 | Eg:- 19 | 20 | ```js 21 | for(var i=0, j=0; i<5; i++, j++, j++){ 22 | console.log("i:"+i+", j:"+j); 23 | } 24 | ``` 25 | 26 | Output:- 27 | 28 | ```js 29 | i:0, j:0 30 | i:1, j:2 31 | i:2, j:4 32 | i:3, j:6 33 | i:4, j:8 34 | ``` 35 | 36 | When placed in an expression, it evaluates every expression from left to right and returns the right most expression. 37 | 38 | Eg:- 39 | 40 | ```js 41 | function a(){console.log('a'); return 'a';} 42 | function b(){console.log('b'); return 'b';} 43 | function c(){console.log('c'); return 'c';} 44 | 45 | var x = (a(), b(), c()); 46 | 47 | console.log(x); // Outputs "c" 48 | ``` 49 | Output:- 50 | 51 | ```js 52 | "a" 53 | "b" 54 | "c" 55 | 56 | "c" 57 | ``` 58 | 59 | * Note: The comma(`,`) operator has the lowest priority of all javascript operators, so without the parenthesis the expression would become: `(x = a()), b(), c();`. 60 | 61 | ##### Playground 62 |
63 | JS Bin on jsbin.com 64 |
65 | -------------------------------------------------------------------------------- /_posts/en/javascript/2016-10-28-three-useful-hacks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Three useful hacks 5 | tip-number: 60 6 | tip-username: leandrosimoes 7 | tip-username-profile: https://github.com/leandrosimoes 8 | tip-tldr: Three very useful and syntax sugar hacks to speed up your development. 9 | 10 | 11 | redirect_from: 12 | - /en/three-useful-hacks/ 13 | 14 | categories: 15 | - en 16 | - javascript 17 | --- 18 | 19 | #### Getting array items from behind to front 20 | 21 | If you want to get the array items from behind to front, just do this: 22 | 23 | ```javascript 24 | var newArray = [1, 2, 3, 4]; 25 | 26 | console.log(newArray.slice(-1)); // [4] 27 | console.log(newArray.slice(-2)); // [3, 4] 28 | console.log(newArray.slice(-3)); // [2, 3, 4] 29 | console.log(newArray.slice(-4)); // [1, 2, 3, 4] 30 | ``` 31 | 32 | #### Short-circuits conditionals 33 | 34 | If you have to execute a function just if a condition is `true`, like this: 35 | 36 | ```javascript 37 | if(condition){ 38 | dosomething(); 39 | } 40 | ``` 41 | 42 | You can use a short-circuit just like this: 43 | 44 | ```javascript 45 | condition && dosomething(); 46 | ``` 47 | 48 | 49 | #### Set variable default values using "||" 50 | 51 | 52 | If you have to set a default value to variables, you can simple do this: 53 | 54 | ```javascript 55 | var a; 56 | 57 | console.log(a); //undefined 58 | 59 | a = a || 'default value'; 60 | 61 | console.log(a); //default value 62 | 63 | a = a || 'new value'; 64 | 65 | console.log(a); //default value 66 | ``` -------------------------------------------------------------------------------- /_posts/en/javascript/2017-01-19-binding-objects-to-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Binding objects to functions 5 | tip-number: 61 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: Understanding how to use `Bind` method with objects and functions in JavaScript 9 | 10 | 11 | redirect_from: 12 | - /en/binding-objects-to-functions/ 13 | 14 | categories: 15 | - en 16 | - javascript 17 | --- 18 | 19 | More than often, we need to bind an object to a function’s this object. JS uses the bind method when this is specified explicitly and we need to invoke desired method. 20 | 21 | ### Bind syntax 22 | 23 | ```js 24 | fun.bind(thisArg[, arg1[, arg2[, ...]]]) 25 | ``` 26 | 27 | ## Parameters 28 | **thisArg** 29 | 30 | `this` parameter value to be passed to target function while calling the `bound` function. 31 | 32 | **arg1, arg2, ...** 33 | 34 | Prepended arguments to be passed to the `bound` function while invoking the target function. 35 | 36 | **Return value** 37 | 38 | A copy of the given function along with the specified `this` value and initial arguments. 39 | 40 | ### Bind method in action in JS 41 | 42 | ```js 43 | const myCar = { 44 | brand: 'Ford', 45 | type: 'Sedan', 46 | color: 'Red' 47 | }; 48 | 49 | const getBrand = function () { 50 | console.log(this.brand); 51 | }; 52 | 53 | const getType = function () { 54 | console.log(this.type); 55 | }; 56 | 57 | const getColor = function () { 58 | console.log(this.color); 59 | }; 60 | 61 | getBrand(); // object not bind,undefined 62 | 63 | getBrand(myCar); // object not bind,undefined 64 | 65 | getType.bind(myCar)(); // Sedan 66 | 67 | let boundGetColor = getColor.bind(myCar); 68 | boundGetColor(); // Red 69 | 70 | ``` -------------------------------------------------------------------------------- /_posts/en/javascript/2017-03-09-working-with-websocket-timeout.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Working With Websocket Timeout 5 | tip-number: 63 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: A trick to control the timeout 9 | 10 | categories: 11 | - en 12 | - javascript 13 | --- 14 | 15 | In case of established websocket connection, server or firewall could timeout and terminate the connection after a period of inactivity. To deal with this situation, we send periodic message to the server. To control the timeout we will add two functions in our code : one to make sure connection keep alive and another one to cancel the keep alive. Also we need a common ```timerID``` variable. 16 | Let’s have a look on implementation- 17 | 18 | ```js 19 | var timerID = 0; 20 | function keepAlive() { 21 | var timeout = 20000; 22 | if (webSocket.readyState == webSocket.OPEN) { 23 | webSocket.send(''); 24 | } 25 | timerId = setTimeout(keepAlive, timeout); 26 | } 27 | function cancelKeepAlive() { 28 | if (timerId) { 29 | clearTimeout(timerId); 30 | } 31 | } 32 | ``` 33 | 34 | Now as we have both of our desired function for the task, we will place ```keepAlive()``` function at the end of ```onOpen()``` method of websocket connection and ```cancelKeepAlive()``` function at the end of ```onClose()``` method of websocket connection. 35 | 36 | Yes! We have perfectly implemented hack for websocket timeout problem. 37 | -------------------------------------------------------------------------------- /_posts/en/javascript/2017-04-03-why-you-should-use-Object.is()-in-equality-comparison.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Why you should use Object.is() in equality comparison 5 | tip-number: 68 6 | tip-username: TarekAlQaddy 7 | tip-username-profile: https://github.com/TarekAlQaddy 8 | tip-tldr: A good solution for the looseness of equality comparisons in javascript 9 | 10 | categories: 11 | - en 12 | - javascript 13 | --- 14 | 15 | We all know that JavaScript is loosely typed and in some cases it fall behind specially when it comes to quality comparison with '==', comparing with '==' gives unexpected results due to whats called coercion or casting "converting one of the 2 operands to the other's type then compare". 16 | 17 | ``` javascript 18 | 0 == ' ' //true 19 | null == undefined //true 20 | [1] == true //true 21 | ``` 22 | 23 | So they provided us with the triple equal operator '===' which is more strict and does not coerce operands, However comparing with '===' is not the best solution you can get: 24 | 25 | ``` javascript 26 | NaN === NaN //false 27 | ``` 28 | 29 | The great news that in ES6 there is the new 'Object.is()' which is better and more precise it has the same features as '===' and moreover it behaves well in some special cases: 30 | 31 | ``` javascript 32 | Object.is(0 , ' '); //false 33 | Object.is(null, undefined); //false 34 | Object.is([1], true); //false 35 | Object.is(NaN, NaN); //true 36 | ``` 37 | 38 | Mozilla team doesn't think that Object.is is "stricter" than '===', they say that we should think of how this method deal with NaN, -0 and +0 but overall I think it is now a good practice in real applications. 39 | 40 | Now this table illustrates.. 41 | 42 | ![differences of operators in equality comparisons javascript](http://i.imgur.com/pCyqkLc.png) 43 | 44 | ## References: 45 | [Equality comparisons and sameness](http://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness) 46 | 47 | -------------------------------------------------------------------------------- /_posts/en/javascript/2017-06-14-closures-inside-loops.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Closures inside loops 5 | tip-number: 76 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: Closure in a loop is an interesting topic and this is the tip to be a master of it 9 | 10 | categories: 11 | - en 12 | - javascript 13 | --- 14 | 15 | If you ever come across the likes of 16 | 17 | ```javascript 18 | var funcs = []; 19 | for (var i = 0; i < 3; i++) { 20 | funcs[i] = function() { 21 | console.log("i value is " + i); 22 | }; 23 | } 24 | 25 | for (var k = 0; k < 3; k++) { 26 | funcs[k](); 27 | } 28 | ``` 29 | 30 | You will notice that the expected output of 31 | 32 | ``` 33 | i value is 0 34 | i value is 1 35 | i value is 2 36 | ``` 37 | 38 | Doesn't match the actual output which will resemble 39 | 40 | ``` 41 | i value is 3 42 | i value is 3 43 | i value is 3 44 | ``` 45 | 46 | This is because of how the capturing mechanism of closures work and how `i` is represented internally. 47 | 48 | To solve this situation you can do as follows: 49 | 50 | ```javascript 51 | for (var i = 0; i < 3; i++) { 52 | funcs[i] = (function(value) { 53 | console.log("i value is " + i); 54 | })(i); 55 | } 56 | ``` 57 | 58 | Which effectively copies i by value by handing it to our closure or 59 | 60 | ```javascript 61 | for (let i = 0; i < 3; i++) { 62 | funcs[i] = function() { 63 | console.log("i value is " + i); 64 | } 65 | } 66 | ``` 67 | 68 | Where `let` scopes the variable to our `for` loop and produces a new value each iteration, thus `i` will be bound to different values on our closures as expected. 69 | -------------------------------------------------------------------------------- /_posts/en/javascript/2020-10-13-what-is-a-functional-inheritance.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: What is Functional Inheritance? 5 | tip-number: 75 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: Functional inheritance is the process of inheriting features by applying an augmenting function to an object instance. 9 | 10 | categories: 11 | - en 12 | - javascript 13 | --- 14 | 15 | Functional inheritance is the process of inheriting features by applying an augmenting function to an object instance. The function supplies a closure scope which you can use to keep some data private. The augmenting function uses dynamic object extension to extend the object instance with new properties and methods. 16 | 17 | Functional mixins are composable factory functions that add properties and behaviors to objects like stations in an assembly line. 18 | 19 | ```javascript 20 | // Base object constructor function 21 | function Animal(data) { 22 | var that = {}; // Create an empty object 23 | that.name = data.name; // Add it a "name" property 24 | return that; // Return the object 25 | }; 26 | 27 | // Create achild object, inheriting from the base Animal 28 | function Cat(data) { 29 | // Create the Animal object 30 | var that = Animal(data); 31 | // Extend base object 32 | that.sayHello = function() { 33 | return 'Hello, I\'m ' + that.name; 34 | }; 35 | return that; 36 | }; 37 | 38 | // Usage 39 | var myCat = Cat({ name: 'Rufi' }); 40 | console.log(myCat.sayHello()); 41 | // Output: "Hello, I'm Rufi" 42 | ``` 43 | 44 | 45 | -------------------------------------------------------------------------------- /_posts/en/javascript/2020-10-15-what-is-a-currying-function.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: What is a currying function? 5 | tip-number: 75 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: A currying function is a function that takes multiple arguments and turns it into a sequence of functions having only one argument at a time. 9 | 10 | categories: 11 | - en 12 | - javascript 13 | --- 14 | 15 | A currying function is a function that takes multiple arguments and turns it into a sequence of functions having only one argument at a time. 16 | 17 | In this way, an n-ary function becomes a unary function, and the last function returns the result of all the arguments together in a function. 18 | 19 | 20 | ```javascript 21 | // Normal definition 22 | function multiply(a, b, c) { 23 | return a * b * c; 24 | }; 25 | console.log(multiply(1, 2, 3)); 26 | // Output: 6 27 | 28 | // Simple curry function definition 29 | function multiply(a) { 30 | return (b) => { 31 | return (c) => { 32 | return a * b * c; 33 | }; 34 | }; 35 | }; 36 | console.log(multiply(1)(2)(3)); 37 | // Output: 6 38 | ``` 39 | 40 | ### Further readings: 41 | 42 | - [Currying in JavaScript](https://dev.to/suprabhasupi/currying-in-javascript-1k3l) 43 | - [Lodash curry](https://lodash.com/docs/#curry) 44 | - [JavaScript currying](http://zetcode.com/javascript/currying/) 45 | -------------------------------------------------------------------------------- /_posts/en/javascript/2020-10-20-what-is-the-temporal-dead-zone.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: What is the Temporal Dead Zone? 5 | tip-number: 76 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: Temporal Dead Zone is a JavaScript behavior while using variables declared using `let` and `const` keywords. 9 | 10 | categories: 11 | - en 12 | - javascript 13 | --- 14 | 15 | Temporal Dead Zone is a JavaScript behavior while using variables declared using `let` and `const` keywords. Since the keywords are block-scoped, the variables declared these keywords could not be accessed before the declaration, and then you will have to witness where variables will be said to be `undefined`. 16 | 17 | 18 | ```javascript 19 | function myFunc(){ 20 | console.log(greeting); 21 | var greeting = 'Hello World!' 22 | }; 23 | myFunc(); // Output: undefined 24 | 25 | function myFunc() { 26 | console.log(greeting); 27 | let greeting = 'Hello World!'; 28 | }; 29 | myFunc(); // Output: ReferenceError: greeting is not defined 30 | 31 | function myFunc() { 32 | console.log(greeting); 33 | const greeting = 'Hello World!'; 34 | } 35 | myFunc(); // Output: ReferenceError: greeting is not defined 36 | ``` -------------------------------------------------------------------------------- /_posts/en/javascript/2020-10-22-difference-between-target-and-currentTarget.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: What is the difference between Target and currentTarget in the event context? 5 | tip-number: 77 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: target refers to the element that triggers an event. currentTarget to the element that the event listener is listening on. 9 | 10 | categories: 11 | - en 12 | - javascript 13 | --- 14 | `target` refers to the DOM element that triggers an event. Otherwise, `currentTarget` refers to the DOM element that the event listener is listening on. 15 | 16 | ```html 17 | 20 | ``` 21 | 22 | ```js 23 | const list = document.querySelector(".todo-list"); 24 | 25 | list.addEventListener("click", e => { 26 | console.log(e.target); 27 | // Output:
  • Walk your dog
  • 28 | console.log(e.currentTarget); 29 | // Output: 30 | }); 31 | ``` -------------------------------------------------------------------------------- /_posts/en/javascript/2020-10-27-what-is-a-spread-operator.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: What is a spread operator? 5 | tip-number: 78 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: The spread operator is a useful syntax for manipulating arrays and objects. 9 | 10 | categories: 11 | - en 12 | - javascript 13 | --- 14 | The spread operator in JavaScript is a useful syntax for adding elements to an array, combining arrays into one larger one, spreading an array inside the arguments of a function, and more. 15 | 16 | ```js 17 | // Concatenating arrays and objects 18 | let arr1 = [1,2,3]; 19 | let arr2 = [4,5]; 20 | let newArray = [...arr1,...arr2]; 21 | console.log(newArray); 22 | // Output: [ 1, 2, 3, 4, 5 ] 23 | 24 | // Copying array elements 25 | let arr = ["a","b","c"]; 26 | let newArray = [...arr]; 27 | console.log(newArray); 28 | // Output: ["a", "b", "c"] 29 | 30 | // Expanding arrays 31 | let arr = ["a","b"]; 32 | let newArray = [...arr,"c","d"]; 33 | console.log(newArray); 34 | // Output: ["a", "b", "c", "d"] 35 | 36 | // Merging objects 37 | const userBasic = { 38 | name: "Jen", 39 | age: 22, 40 | }; 41 | const userMoreInfo = { 42 | country: "Argentina", 43 | city: "Córdoba", 44 | }; 45 | const user = {... userBasic, ... userMoreInfo}; 46 | // Output: { name: "Jen", age: 22, country: "Argentina", city: "Córdoba" } 47 | ``` -------------------------------------------------------------------------------- /_posts/en/javascript/2020-11-04-what-is-a-void-operator.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: What is a void operator? 5 | tip-number: 79 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: The void operator returns an undefined value from an evaluated expression 9 | 10 | categories: 11 | - en 12 | - javascript 13 | --- 14 | The `void` operator returns an `undefined` value from an evaluated expression, or in other words; the `void` operator specifies an expression to be evaluated without returning a value. It is commonly used in client-side JavaScript, where the browser should not display the value. 15 | 16 | ```js 17 | function getYear() { 18 | return 2020; 19 | }; 20 | 21 | console.log(getYear()); 22 | // Output: 2020 23 | 24 | console.log(void getYear()); 25 | // Output: undefined 26 | 27 | // Useful use case 28 | button.onclick = () => void getYear(); 29 | ``` 30 | -------------------------------------------------------------------------------- /_posts/en/javascript/2020-11-17-what-is-the-promise-executor.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: What is the promise executor? 5 | tip-number: 80 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: The method received as an argument for the promise. 9 | 10 | categories: 11 | - en 12 | - javascript 13 | --- 14 | All `Promise` instances accept a method as an argument called the executor. This executor takes two methods as arguments: resolve and reject. Within the executor, if resolve is called, the `Promise` instance becomes fulfilled. If an exception is thrown, reject is called instead, and the `Promise` instance becomes rejected. 15 | 16 | ```js 17 | const executor = (resolve, reject) => { 18 | setTimeout(() => resolve("I'm done"), 1000); 19 | }; 20 | 21 | new Promise(executor).then(result => { 22 | console.log(result); 23 | // Output after 1000ms: I'm done 24 | }); 25 | ``` 26 | -------------------------------------------------------------------------------- /_posts/en/javascript/2021-02-02-what-is-the-javascript-ternary-operator.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: What is the JavaScript ternary operator? 5 | tip-number: 81 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: The ternary operator is a shortcut for the if statement. 9 | 10 | categories: 11 | - en 12 | - javascript 13 | --- 14 | The ternary operator is a shortcut for the `if` statement. It consists of three operands; a question mark, a condition, and an expression to execute if the condition is true, followed by a colon and another expression to execute if it’s false. 15 | 16 | ```js 17 | let age = 26; 18 | 19 | // condition ? expression if true : expression if false 20 | let drink = (age >= 21) ? "Beer" : "Juice"; 21 | 22 | console.log(drink); // "Beer" 23 | 24 | // Equivalent to: 25 | let drink; 26 | if ((age >= 21)) { 27 | drink = "Beer"; 28 | } else { 29 | drink = "Juice"; 30 | } 31 | 32 | console.log(drink); // "Beer" 33 | ``` 34 | -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-01-05-differences-between-undefined-and-null.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Diferencias entre `undefined` y `null` 5 | tip-number: 05 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: Comprendiendo las diferencias entre `undefined` y `null`. 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /es_es/differences-between-undefined-and-null/ 13 | 14 | categories: 15 | - es_ES 16 | - javascript 17 | --- 18 | 19 | - `undefined` significa una variable no se ha declarado, o se ha declarado pero aún no se le ha asignado un valor 20 | - `null` es un valor de asignación que significa "no value" 21 | - Javascript establece variables no asignadas con un valor por defecto de `undefined` 22 | - Javascript nunca se setea un valor de `null`. Es utilizado por los programadores para indicar que un `var` no tiene ningún valor. 23 | - `undefined` no es válido en JSON, mientras que `null` si lo es 24 | - `undefined` typeof es `undefined` 25 | - `null` typeof es un `object`. [porque?](http://www.2ality.com/2013/10/typeof-null.html) 26 | - Ambos son primitivos 27 | - Ambos son [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) 28 | (`Boolean(undefined) // false`, `Boolean(null) // false`) 29 | - Se puede saber si una variable es [undefined](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined) 30 | 31 | ```javascript 32 | typeof variable === "undefined" 33 | ``` 34 | - Puede comprobar si una variable es [null](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null) 35 | 36 | ```javascript 37 | variable === null 38 | ``` 39 | - The **equality** operator considers them equal, but the **identity** doesn't 40 | El operador **igualdad** considera iguales, pero la **identidad** no lo hace 41 | 42 | ```javascript 43 | null == undefined // true 44 | 45 | null === undefined // false 46 | ``` -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-01-06-writing-a-single-method-for-arrays-and-a-single-element.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Escribir un método único para los arrays y elemento unico 5 | tip-number: 06 6 | tip-username: mattfxyz 7 | tip-username-profile: https://twitter.com/mattfxyz 8 | tip-tldr: En lugar de escribir métodos separados para manejar un array y un único parámetro elemento, escriba sus funciones para que puedan manejar ambos. Esto es similar a la forma en que algunas de las funciones de jQuery trabaja(`css` modificará todos los que coinciden con el selector). 9 | 10 | redirect_from: 11 | - /es_es/writing-a-single-method-for-arrays-and-a-single-element/ 12 | 13 | categories: 14 | - es_ES 15 | - javascript 16 | --- 17 | 18 | En lugar de escribir métodos separados para manejar un array y un único parámetro elemento, escriba sus funciones para que puedan manejar ambos. Esto es similar a la forma en que algunas de las funciones de jQuery trabaja(`css` modificará todos los que coinciden con el selector). 19 | 20 | Sólo tienes que concatenar todo en un array. `Array.concat` aceptará un array o un elemento único. 21 | 22 | ```javascript 23 | function printUpperCase(words) { 24 | var elements = [].concat(words); 25 | for (var i = 0; i < elements.length; i++) { 26 | console.log(elements[i].toUpperCase()); 27 | } 28 | } 29 | ``` 30 | 31 | `printUpperCase` ya está listo para aceptar un único nodo o un conjunto de nodos como su parámetro. 32 | 33 | ```javascript 34 | printUpperCase("cactus"); 35 | // => CACTUS 36 | printUpperCase(["cactus", "bear", "potato"]); 37 | // => CACTUS 38 | // BEAR 39 | // POTATO 40 | ``` 41 | -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-01-09-template-strings.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Template Strings 5 | tip-number: 09 6 | tip-username: JakeRawr 7 | tip-username-profile: https://github.com/JakeRawr 8 | tip-tldr: A partir de ES6, JS ahora tiene template strings. 9 | 10 | redirect_from: 11 | - /es_es/template-strings/ 12 | 13 | categories: 14 | - es_ES 15 | - javascript 16 | --- 17 | 18 | A partir de ES6, JS ahora tiene template strings 19 | 20 | Ejemplo: 21 | String normal 22 | 23 | ```javascript 24 | var firstName = 'Jake'; 25 | var lastName = 'Rawr'; 26 | console.log('My name is ' + firstName + ' ' + lastName); 27 | // My name is Jake Rawr 28 | ``` 29 | Template String 30 | 31 | ```javascript 32 | var firstName = 'Jake'; 33 | var lastName = 'Rawr'; 34 | console.log(`My name is ${firstName} ${lastName}`); 35 | // My name is Jake Rawr 36 | ``` 37 | 38 | Usted puede hacer strings multilínea sin `\n' y lógica simple (ie 2+3) en el interior `$ {}` en template strings. 39 | 40 | Usted también es capaz de modificar la salida de template strings utilizando una función; se les llama [template strings etiquetados](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings#Tagged_template_strings), por ejemplo los usos de cadenas de la plantilla etiquetados. 41 | 42 | Tambien puede leer mas sobre Template Strings [read](https://hacks.mozilla.org/2015/05/es6-in-depth-template-strings-2). -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-01-12-pseudomandatory-parameters-in-es6-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Pseudo parámetros obligatorios en funciones ES6 5 | tip-number: 12 6 | tip-username: Avraam Mavridis 7 | tip-username-profile: https://github.com/AvraamMavridis 8 | tip-tldr: En muchos lenguajes de programación, los parámetros de una función por defecto son obligatorios y el desarrollador tiene que definir explícitamente que un parámetro es opcional. 9 | 10 | redirect_from: 11 | - /es_es/pseudomandatory-parameters-in-es6-functions/ 12 | 13 | categories: 14 | - es_ES 15 | - javascript 16 | --- 17 | 18 | En muchos lenguajes de programación, los parámetros de una función por defecto son obligatorios y el desarrollador tiene que definir explícitamente que un parámetro es opcional. En Javascript, cada parámetro es opcional, pero puede hacer cumplir este comportamiento sin jugar con el propio cuerpo de una función, aprovechando [** valores predeterminados para los parámetros de es6's **] (http://exploringjs.com/es6/ch_parameter -handling.html # sec_parameter-valores por defecto). 19 | 20 | ```javascript 21 | const _err = function( message ){ 22 | throw new Error( message ); 23 | } 24 | 25 | const getSum = (a = _err('a is not defined'), b = _err('b is not defined')) => a + b 26 | 27 | getSum( 10 ) // throws Error, b is not defined 28 | getSum( undefined, 10 ) // throws Error, a is not defined 29 | ``` 30 | 31 | `_err` es una función que lanza inmediatamente un error. Si no se pasa ningún valor para uno de los parámetros, el valor predeterminado se va a utilizar, `_err` serán tratados y se emite un error. Se puede ver más ejemplos para **caracteristicas de parámetros por defecto** en [Mozilla's Developer Network ](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/default_parameters) -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-01-13-tip-to-measure-performance-of-a-javascript-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Tip para medir el rendimiento de un bloque de Javascript 5 | tip-number: 13 6 | tip-username: manmadareddy 7 | tip-username-profile: https://twitter.com/manmadareddy 8 | tip-tldr: Para medir rápidamente el rendimiento de un bloque de Javascript, podemos utilizar las funciones de la consola como `console.time(label)` y `console.timeEnd(label)` 9 | 10 | redirect_from: 11 | - /es_es/tip-to-measure-performance-of-a-javascript-block/ 12 | 13 | categories: 14 | - es_ES 15 | - javascript 16 | --- 17 | 18 | Para medir rápidamente el rendimiento de un bloque de Javascript, podemos utilizar las funciones de la consola como 19 | [`console.time(label)`](https://developer.chrome.com/devtools/docs/console-api#consoletimelabel) y [`console.timeEnd(label)`](https://developer.chrome.com/devtools/docs/console-api#consoletimeendlabel) 20 | 21 | ```javascript 22 | console.time("Array initialize"); 23 | var arr = new Array(100), 24 | len = arr.length, 25 | i; 26 | 27 | for (i = 0; i < len; i++) { 28 | arr[i] = new Object(); 29 | }; 30 | console.timeEnd("Array initialize"); // Outputs: Array initialize: 0.711ms 31 | ``` 32 | 33 | Más informacion: 34 | [Console object](https://github.com/DeveloperToolsWG/console-object), 35 | [Javascript benchmarking](https://mathiasbynens.be/notes/javascript-benchmarking) 36 | 37 | Demo: [jsfiddle](https://jsfiddle.net/meottb62/) - [codepen](http://codepen.io/anon/pen/JGJPoa) (outputs in browser console) -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-01-17-nodejs-run-a-module-if-it-is-not-required.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Node.js - ejecutar un módulo si no es `required` 5 | tip-number: 17 6 | tip-username: odsdq 7 | tip-username-profile: https://twitter.com/odsdq 8 | tip-tldr: En Node, puede decir que su programa va a hacer dos cosas diferentes dependiendo de si se ejecuta el código `require('./something.js')` o `node something.js`. Esto es útil si desea interactuar con uno de sus módulos de forma independiente. 9 | 10 | redirect_from: 11 | - /es_es/nodejs-run-a-module-if-it-is-not-required/ 12 | 13 | categories: 14 | - es_ES 15 | - javascript 16 | --- 17 | 18 | En Node, puede decir que su programa va a hacer dos cosas diferentes dependiendo de si se ejecuta el código `require('./something.js')` o `node something.js`. Esto es útil si desea interactuar con uno de sus módulos de forma independiente. 19 | 20 | ```js 21 | if (!module.parent) { 22 | // ran with `node something.js` 23 | app.listen(8088, function() { 24 | console.log('app listening on port 8088'); 25 | }) 26 | } else { 27 | // used with `require('/.something.js')` 28 | module.exports = app; 29 | } 30 | ``` 31 | 32 | Ver [the documentation for modules](https://nodejs.org/api/modules.html#modules_module_parent) para mas informacion. -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-01-19-safe-string-concatenation.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Concatenación de Strings segura 5 | tip-number: 19 6 | tip-username: gogainda 7 | tip-username-profile: https://twitter.com/gogainda 8 | tip-tldr: Suponga que tiene un par de variables con tipos desconocidos y desea concatenar en una cadena. Para asegurarse de que la operación aritmética no se puede aplicar durante la concatenación, utilizar concat 9 | 10 | redirect_from: 11 | - /es_es/safe-string-concatenation/ 12 | 13 | categories: 14 | - es_ES 15 | - javascript 16 | --- 17 | 18 | Suponga que tiene un par de variables con tipos desconocidos y desea concatenar en una cadena. Para asegurarse de que la operación aritmética no se puede aplicar durante la concatenación, utilizar 'concat': 19 | 20 | ```javascript 21 | var one = 1; 22 | var two = 2; 23 | var three = '3'; 24 | 25 | var result = ''.concat(one, two, three); //"123" 26 | ``` 27 | 28 | Esta forma de concatenación hace exactamente lo que se espera. Por el contrario, la concatenación con ventajas podría conducir a resultados inesperados: 29 | 30 | ```javascript 31 | var one = 1; 32 | var two = 2; 33 | var three = '3'; 34 | 35 | var result = one + two + three; //"33" instead of "123" 36 | ``` 37 | 38 | Hablando de rendimiento, en comparación con el `join` [type](http://www.sitepoint.com/javascript-fast-string-concatenation/) de concatenación, la velocidad de` concat` es más o menos lo mismo. 39 | 40 | Puede leer mas sobre `concat` en MDN [page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/concat). -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-01-20-return-objects-to-enable-chaining-of-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Devolver los objetos que permiten el encadenamiento de las funciones 5 | tip-number: 20 6 | tip-username: WakeskaterX 7 | tip-username-profile: https://twitter.com/WakeStudio 8 | tip-tldr: Al crear funciones en un objeto en Javascript orientado a objetos, devolver el objeto a la función le permitirá encadenar funciones. 9 | 10 | redirect_from: 11 | - /es_es/return-objects-to-enable-chaining-of-functions/ 12 | 13 | categories: 14 | - es_ES 15 | - javascript 16 | --- 17 | 18 | Al crear funciones en un objeto en Javascript orientado a objetos, devolver el objeto a la función le permitirá encadenar funciones. 19 | 20 | ```js 21 | function Person(name) { 22 | this.name = name; 23 | 24 | this.sayName = function() { 25 | console.log("Hello my name is: ", this.name); 26 | return this; 27 | }; 28 | 29 | this.changeName = function(name) { 30 | this.name = name; 31 | return this; 32 | }; 33 | } 34 | 35 | var person = new Person("John"); 36 | person.sayName().changeName("Timmy").sayName(); 37 | ``` -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-01-21-shuffle-an-array.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Mezclar un Array 5 | tip-number: 21 6 | tip-username: 0xmtn 7 | tip-username-profile: https://github.com/0xmtn/ 8 | tip-tldr: Fisher-Yates Shuffling es un algoritmo para mezclar un array. 9 | 10 | redirect_from: 11 | - /es_es/shuffle-an-array/ 12 | 13 | categories: 14 | - es_ES 15 | - javascript 16 | --- 17 | 18 | Este codigo utiliza [Fisher-Yates Shuffling](https://www.wikiwand.com/en/Fisher%E2%80%93Yates_shuffle) Algoritmo para mezclar un array. 19 | 20 | ```javascript 21 | function shuffle(arr) { 22 | var i, 23 | j, 24 | temp; 25 | for (i = arr.length - 1; i > 0; i--) { 26 | j = Math.floor(Math.random() * (i + 1)); 27 | temp = arr[i]; 28 | arr[i] = arr[j]; 29 | arr[j] = temp; 30 | } 31 | return arr; 32 | }; 33 | ``` 34 | Ejemplo: 35 | 36 | ```javascript 37 | var a = [1, 2, 3, 4, 5, 6, 7, 8]; 38 | var b = shuffle(a); 39 | console.log(b); 40 | // [2, 7, 8, 6, 5, 3, 1, 4] 41 | ``` -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-01-23-converting-to-number-fast-way.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Convertir a numero de la forma mas rapida 5 | tip-number: 23 6 | tip-username: sonnyt 7 | tip-username-profile: http://twitter.com/sonnyt 8 | tip-tldr: La conversión de cadenas en números es muy común. La forma más fácil y rápida de lograr sería utilizar el operador +. 9 | 10 | redirect_from: 11 | - /es_es/converting-to-number-fast-way/ 12 | 13 | categories: 14 | - es_ES 15 | - javascript 16 | --- 17 | 18 | La conversión de cadenas en números es muy común. La forma más rápida ([jsPref](https://jsperf.com/number-vs-parseint-vs-plus/29)) y más fácil de lograr que sería utilizar el operador `+` (mas). 19 | 20 | ```javascript 21 | var one = '1'; 22 | 23 | var numberOne = +one; // Number 1 24 | ``` 25 | 26 | You can also use the `-` (minus) operator which type-converts the value into number but also negates it. 27 | También se puede utilizar el operador `-` (menos) qué convierte el valor en número, sino también la niega. 28 | 29 | ```javascript 30 | var one = '1'; 31 | 32 | var negativeNumberOne = -one; // Number -1 33 | ``` -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-01-24-use_===_instead_of_==.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Utilizar === en lugar de == 5 | tip-number: 24 6 | tip-username: bhaskarmelkani 7 | tip-username-profile: https://www.twitter.com/bhaskarmelkani 8 | tip-tldr: El operador `==` (or `!=`) lleva a cabo una conversión automática de tipos si es necesario. El operador `===` (or `!==`) no va a realizar ninguna conversión. En él se compara el valor y el tipo, que podría considerarse más rápido ([jsPref](http://jsperf.com/strictcompare)) que `==`. 9 | 10 | redirect_from: 11 | - /es_es/use_===_instead_of_==/ 12 | 13 | categories: 14 | - es_ES 15 | - javascript 16 | --- 17 | 18 | El operador `==` (or `!=`) lleva a cabo una conversión automática de tipos si es necesario. El operador `===` (or `!==`) no va a realizar ninguna conversión. En él se compara el valor y el tipo, que podría considerarse más rápido ([jsPref](http://jsperf.com/strictcompare)) que `==`. 19 | 20 | ```js 21 | [10] == 10 // is true 22 | [10] === 10 // is false 23 | 24 | '10' == 10 // is true 25 | '10' === 10 // is false 26 | 27 | [] == 0 // is true 28 | [] === 0 // is false 29 | 30 | '' == false // is true but true == "a" is false 31 | '' === false // is false 32 | 33 | ``` 34 | -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-01-30-converting-truthy-falsy-values-to-boolean.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Convertir valores truthy/falsy a boolean 5 | tip-number: 30 6 | tip-username: hakhag 7 | tip-username-profile: https://github.com/hakhag 8 | tip-tldr: Los operadores lógicos son una parte fundamental de JavaScript, aquí se puede ver una manera de obtener siempre un verdadero o falso, no importa lo que se le dio a él. 9 | 10 | 11 | redirect_from: 12 | - /es_es/converting-truthy-falsy-values-to-boolean/ 13 | 14 | categories: 15 | - es_ES 16 | - javascript 17 | --- 18 | 19 | Puede convertir un valor [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) o [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) a verdadero booleano con el `!!` operador. 20 | 21 | ```js 22 | !!"" // false 23 | !!0 // false 24 | !!null // false 25 | !!undefined // false 26 | !!NaN // false 27 | 28 | !!"hello" // true 29 | !!1 // true 30 | !!{} // true 31 | !![] // true 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-02-02-create-range-0-n-easily-using-one-line.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | 5 | title: Crear rangos 0...(N-1) facilmente usando una linea 6 | tip-number: 33 7 | tip-username: SarjuHansaliya 8 | tip-username-profile: https://github.com/SarjuHansaliya 9 | tip-tldr: Podemos crear una función de rango que dará un rango entre 0...(N-1) utilizando una sola línea 10 | 11 | redirect_from: 12 | - /es_es/create-range-0-n-easily-using-one-line/ 13 | 14 | categories: 15 | - es_ES 16 | - javascript 17 | --- 18 | 19 | A continuación mostraremos como crear el rango 0...N-1). 20 | 21 | ```js 22 | Array.apply(null, {length: N}).map(Number.call, Number); 23 | ``` 24 | 25 | Vamos a descomponer esta línea en partes. Sabemos como la funcion `call ()` trabaja en javascript. Así que en `call ()` el primer argumento será contexto y los segundos argumentos, será una lista de argumentos de la función en la que estamos llamando `call()`. 26 | 27 | ```js 28 | function add(a, b){ 29 | return (a+b); 30 | } 31 | add.call(null, 5, 6); 32 | ``` 33 | Esto devolverá una suma de 5 y 6. 34 | 35 | `map()` del array en javascript toma dos argumentos, el primero `callback` y el segundo `thisArg(context)`. `callback` está tomando tres argumentos, `value`, `index` y todo el `array` sobre el que estamos iterando. Así es la sintaxis común: 36 | 37 | ```js 38 | [1, 2, 3].map(function(value, index, arr){ 39 | //Code 40 | }, this); 41 | ``` 42 | Debajo de la línea crea array de longitud dada. 43 | 44 | ```js 45 | Array.apply(null, {length: N}) 46 | ``` 47 | Poner todas las partes juntas a continuación es la solución. 48 | 49 | ```js 50 | Array.apply(null, {length: N}).map(Number.call, Number); 51 | ``` 52 | 53 | Si tiene un rango 1...N, que sera como este. 54 | 55 | ```js 56 | Array.apply(null, {length: N}).map(function(value, index){ 57 | return index+1; 58 | }); 59 | ``` 60 | -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-02-09-using-json-stringify.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Usando JSON.Stringify 5 | tip-number: 40 6 | tip-username: vamshisuram 7 | tip-username-profile: https://github.com/vamshisuram 8 | tip-tldr: Crear un string seleccionando propiedades de un objeto JSON. 9 | 10 | 11 | redirect_from: 12 | - /es_es/using-json-stringify/ 13 | 14 | categories: 15 | - es_ES 16 | - javascript 17 | --- 18 | 19 | Digamos que hay un objeto con propiedades"prop1", "prop2", "prop3". 20 | Podemos pasarle __patrametro adicional__ a __JSON.stringify__ a escribir propiedades selectiva del objeto a cadena como: 21 | 22 | ```javascript 23 | var obj = { 24 | 'prop1': 'value1', 25 | 'prop2': 'value2', 26 | 'prop3': 'value3' 27 | }; 28 | 29 | var selectedProperties = ['prop1', 'prop2']; 30 | 31 | var str = JSON.stringify(obj, selectedProperties); 32 | 33 | // str 34 | // {"prop1":"value1","prop2":"value2"} 35 | 36 | ``` 37 | 38 | __"str"__ sólo contendrá información sobre propiedades seleccionadas. 39 | 40 | En lugar de un array podemos pasar una función también. 41 | 42 | ```javascript 43 | 44 | function selectedProperties(key, val) { 45 | // the first val will be the entire object, key is empty string 46 | if (!key) { 47 | return val; 48 | } 49 | 50 | if (key === 'prop1' || key === 'prop2') { 51 | return val; 52 | } 53 | 54 | return; 55 | } 56 | ``` 57 | 58 | The last optional param it takes is to modify the way it writes the object to string. 59 | El último parámetro opcional se necesita si quiere modificar la forma en que se escribe el objeto de cadena. 60 | 61 | ```javascript 62 | var str = JSON.stringify(obj, selectedProperties, '\t\t'); 63 | 64 | /* str output with double tabs in every line. 65 | { 66 | "prop1": "value1", 67 | "prop2": "value2" 68 | } 69 | */ 70 | 71 | ``` 72 | 73 | -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-02-10-array-average-and-median.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Array media y promedio. 5 | tip-number: 41 6 | tip-username: soyuka 7 | tip-username-profile: https://github.com/soyuka 8 | tip-tldr: Calcula la media y el promedio de los valores de la matriz 9 | 10 | 11 | redirect_from: 12 | - /es_es/array-average-and-median/ 13 | 14 | categories: 15 | - es_ES 16 | - javascript 17 | --- 18 | 19 | Los siguientes ejemplos se basan en el siguiente array: 20 | 21 | ```javascript 22 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 23 | ``` 24 | 25 | Para obtener el promedio, tenemos que resumir los números y luego dividir por el número de valores. Los pasos son los siguientes: 26 | - obtener la longitud del array 27 | - sumar los valores 28 | - obtener el promedio (`suma/length`) 29 | 30 | ```javascript 31 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 32 | let sum = values.reduce((previous, current) => current += previous); 33 | let avg = sum / values.length; 34 | // avg = 28 35 | ``` 36 | 37 | O bien: 38 | 39 | ```javascript 40 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 41 | let count = values.length; 42 | values = values.reduce((previous, current) => current += previous); 43 | values /= count; 44 | // avg = 28 45 | ``` 46 | 47 | Ahora, para obtener media los pasos son los siguientes: 48 | - ordenar el array 49 | - obtener la media aritmética de los valores medios 50 | 51 | ```javascript 52 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 53 | values.sort((a, b) => a - b); 54 | let lowMiddle = Math.floor((values.length - 1) / 2); 55 | let highMiddle = Math.ceil((values.length - 1) / 2); 56 | let median = (values[lowMiddle] + values[highMiddle]) / 2; 57 | // median = 13,5 58 | ``` 59 | 60 | Con un operador de bits: 61 | 62 | ```javascript 63 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 64 | values.sort((a, b) => a - b); 65 | let median = (values[(values.length - 1) >> 1] + values[values.length >> 1]) / 2 66 | // median = 13,5 67 | ``` 68 | -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-02-12-use-destructuring-in-function-parameters.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Utilice la desestructuración de los parámetros de función 5 | tip-number: 43 6 | tip-username: dislick 7 | tip-username-profile: https://github.com/dislick 8 | tip-tldr: ¿Sabías que se puede utilizar una funcion de desestructuración de parametro parámetros? 9 | 10 | redirect_from: 11 | - /es_es/use-destructuring-in-function-parameters/ 12 | 13 | categories: 14 | - es_ES 15 | - javascript 16 | --- 17 | 18 | Estoy seguro que muchos de ustedes ya están familiarizados con el [ES6 Destructuring Assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment). ¿Sabías que también se puede utilizar en los parámetros de una función? 19 | 20 | ```javascript 21 | var sayHello = function({ name, surname }) { 22 | console.log(`Hello ${name} ${surname}! How are you?`); 23 | }; 24 | 25 | sayHello({ 26 | name: 'John', 27 | surname: 'Smith' 28 | }); 29 | ``` 30 | 31 | Esto es grande para las funciones que aceptan un objeto de opciones. 32 | 33 | > Tenga en cuenta que la asignación desestructurada aún no está disponible en Node.js y casi todos los navegadores. Sin embargo, puede usar `--harmony-destructuring` para Node.js si desea intentarlo por sí mismo ahora. -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-02-14-calculate-the-max-min-value-from-an-array.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Calcular el valor Max/Min de un array 5 | tip-number: 45 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: Formas de utilizar las funciones Math.max() y Math.min() con array de números 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /es_es/detect-document-ready-in-pure-js/ 13 | 14 | categories: 15 | - es_ES 16 | - javascript 17 | --- 18 | 19 | Las funciones [Math.max()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max) and [Math.min()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min) encontrar el valor máximo y mínimo de los argumentos, respectivamente. 20 | 21 | ```js 22 | Math.max(1, 2, 3, 4); // 4 23 | Math.min(1, 2, 3, 4); // 1 24 | ``` 25 | 26 | Estas funciones no funcionarán como tal con arrays de números. Sin embargo, hay algunas maneras de evitar esto. 27 | 28 | [`Function.prototype.apply()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) le permite llamar a una función con un determinado valor de `this` y un _array_ de argumentos. 29 | 30 | ```js 31 | var numbers = [1, 2, 3, 4]; 32 | Math.max.apply(null, numbers) // 4 33 | Math.min.apply(null, numbers) // 1 34 | ``` 35 | 36 | Pasando el array `numbers` como el segundo argumento de `apply()` resulta en la función invocados con todos los valores en le array como parámetros. 37 | 38 | Una manera sencilla con ES2015 de conseguir esto [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator). 39 | 40 | ```js 41 | var numbers = [1, 2, 3, 4]; 42 | Math.max(...numbers) // 4 43 | Math.min(...numbers) // 1 44 | ``` 45 | 46 | Este operador hace que los valores del array a ser ampliado, o "spread", dentro de argumentos de la función. 47 | -------------------------------------------------------------------------------- /_posts/es_ES/javascript/2016-02-15-detect-document-ready-in-pure-js.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Detectar cuando DOM esta listo en JS puro 5 | tip-number: 46 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: La forma cross-browser para comprobar si el DOM se ha cargado en JavaScript puro. 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /es_es/basics-declarations/ 13 | 14 | categories: 15 | - es_ES 16 | - javascript 17 | --- 18 | 19 | La forma cross-browser para comprobar si el documento se ha cargado en JavaScript puro utiliza [`readyState`](https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState). 20 | 21 | ```js 22 | if (document.readyState === 'complete') { 23 | // The page is fully loaded 24 | } 25 | ``` 26 | 27 | Como detectar cuando el document esta listo... 28 | 29 | 30 | ```js 31 | let stateCheck = setInterval(() => { 32 | if (document.readyState === 'complete') { 33 | clearInterval(stateCheck); 34 | // document ready 35 | } 36 | }, 100); 37 | ``` 38 | 39 | o con [onreadystatechange](https://developer.mozilla.org/en-US/docs/Web/Events/readystatechange)... 40 | 41 | 42 | ```js 43 | document.onreadystatechange = () => { 44 | if (document.readyState === 'complete') { 45 | // document ready 46 | } 47 | }; 48 | ``` 49 | 50 | Use `document.readyState === 'interactive'` para detectar cuando el DOM esta listo. 51 | -------------------------------------------------------------------------------- /_posts/zh_CN/angular/2016-01-01-angularjs-digest-vs-apply.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: AngularJs - $digest vs $apply 5 | tip-number: 01 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: JavaScript模块和构建步骤越来越复杂和多样化,但是新框架里的样板是什么样子的呢? 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_cn/angularjs-digest-vs-apply/ 13 | 14 | categories: 15 | - zh_CN 16 | - angular 17 | --- 18 | 19 | AngularJs最令人欣赏的特性之一就是双向数据绑定。AngularJs通过循环(`$digest`)检查model和view的变化实现此功能。想要理解框架底层的运行机制你需要理解这个概念。 20 | 21 | 当一个事件被触发时,Angular触发每个watcher. 这是我们已知的`$digest`循环。有时你需要强制手动运行一个新的循环,而且因为这是最影响性能的一方面,你必须选择一个正确的选项。 22 | 23 | ### `$apply` 24 | 这个核心方法可以让你显式启动`digest`循环。这意味着所有的watcher将会被检测;整个应用启动`$digest loop`。在内部在会执行一个可选的方法之后,会调用`$rootScope.$digest();`. 25 | 26 | ### `$digest` 27 | 这种情况下`$digest`方法在当前作用域和它的子作用域启动`$digest`循环。你需要注意他的父作用域将不会被检测也不会被影响。 28 | 29 | ### 推荐 30 | - 仅当浏览器DOM事件在AngularJS之外被触发时使用`$apply`或`$digest`。 31 | - 给`$apply`传递方法,它将包含错误处理机制而且允许整合在`digest`循环里的变化。 32 | 33 | ```javascript 34 | $scope.$apply(() => { 35 | $scope.tip = 'Javascript Tip'; 36 | }); 37 | ``` 38 | 39 | - 如果你只需要更新当前的作用域或者它的子作用域的话,使用`$digest`,而且要防止在整个应用里运行新的`digest`循环。这在性能上的好处是显而易见的。 40 | - `$apply()`对机器来说是一个困难的处理过程,在绑定过多的时候可能会引发性能问题。 41 | - 如果你正使用`>AngularJS 1.2.X`版本,使用`$evalAsync`, 这个方法将在当前循环或下一个循环执行表达式,这能提高你的应用的性能。 42 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-05-differences-between-undefined-and-null.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: undefined与null的区别 5 | tip-number: 05 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: 理解`undefined`与`null`的区别。 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_cn/differences-between-undefined-and-null/ 13 | 14 | categories: 15 | - zh_CN 16 | - javascript 17 | --- 18 | 19 | 20 | - `undefined`表示一个变量没有被声明,或者被声明了但没有被赋值 21 | - `null`是一个表示“没有值”的值 22 | - Javascript将未赋值的变量默认值设为`undefined` 23 | - Javascript从来不会将变量设为`null`。它是用来让程序员表明某个用`var`声明的变量时没有值的。 24 | - `undefined`不是一个有效的JSON,而`null`是 25 | - `undefined`的类型(typeof)是`undefined` 26 | - `null`的类型(typeof)是`object`. [为什么?](http://www.2ality.com/2013/10/typeof-null.html) 27 | - 它们都是基本类型 28 | - 他们都是[falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) 29 | (`Boolean(undefined) // false`, `Boolean(null) // false`) 30 | - 你可以这样判断一个变量是否是[undefined](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/undefined) 31 | 32 | ```javascript 33 | typeof variable === "undefined" 34 | ``` 35 | 36 | - 你可以这样判断一个变量是否是[null](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/null) 37 | 38 | ```javascript 39 | variable === null 40 | ``` 41 | 42 | - **双等号**比较时它们相等,但**三等号**比较时不相等 43 | 44 | ```javascript 45 | null == undefined // true 46 | 47 | null === undefined // false 48 | ``` 49 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-06-writing-a-single-method-for-arrays-and-a-single-element.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 可以接受单参数与数组的方法 5 | tip-number: 06 6 | tip-username: mattfxyz 7 | tip-username-profile: https://twitter.com/mattfxyz 8 | tip-tldr: 写一个方法可以接受单个参数也可以接受一个数组,而不是分开写两个方法。这和jQuery的一些方法的工作原理很像(`css` 可以修改任何匹配到的选择器). 9 | 10 | redirect_from: 11 | - /zh_cn/writing-a-single-method-for-arrays-and-a-single-element/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 写一个方法可以接受单个参数也可以接受一个数组,而不是分开写两个方法。这和jQuery的一些方法的工作原理很像(`css` 可以修改任何匹配到的选择器). 19 | 20 | 你只要把任何东西连接到一个数组. `Array.concat`可以接受一个数组也可以接受单个参数。 21 | 22 | ```javascript 23 | function printUpperCase(words) { 24 | var elements = [].concat(words || []); 25 | for (var i = 0; i < elements.length; i++) { 26 | console.log(elements[i].toUpperCase()); 27 | } 28 | } 29 | ``` 30 | 31 | 32 | `printUpperCase`现在可以接受单个单词或多个单词的数组作为它的参数。同时也可以避免在不传递参数时抛出的`TypeError`错误的隐患。 33 | 34 | ```javascript 35 | printUpperCase("cactus"); 36 | // => CACTUS 37 | printUpperCase(["cactus", "bear", "potato"]); 38 | // => CACTUS 39 | // BEAR 40 | // POTATO 41 | ``` 42 | 43 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-07-use-strict-and-get-lazy.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 使用"use strict" 变得懒惰 5 | tip-number: 07 6 | tip-username: nainslie 7 | tip-username-profile: https://twitter.com/nat5an 8 | tip-tldr: JavaScript的严格模式使开发者更容易写出“安全”的代码。 9 | 10 | redirect_from: 11 | - /zh_cn/use-strict-and-get-lazy/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | (译者注:此片翻译较渣,欢迎指正,建议大家[阅读原文](http://www.jstips.co/en/use-strict-and-get-lazy/)或直接阅读[MDN对严格模式的中文介绍](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode) 并欢迎PR) 19 | 20 | JavaScript的严格模式使开发者更容易写出“安全”的代码。 21 | 22 | 通常情况下,JavaScript允许程序员相当粗心,比如你可以引用一个从未用"var"声明的变量。或许对于一个刚入门的开发者来说这看起来很方便,但这也是变量拼写错误或者从作用域外引用变量时引发的一系列错误的原因。 23 | 24 | 程序员喜欢电脑帮我们做一些无聊的工作,喜欢它自动的检查我们工作上的错误。这就是"use strict"帮我们做的,它把我们的错误转变为了JavaScript错误。 25 | 26 | 我们把这个指令放在js文件顶端来使用它: 27 | 28 | ```javascript 29 | // 全脚本严格模式 30 | "use strict"; 31 | var v = "Hi! I'm a strict mode script!"; 32 | ``` 33 | 34 | 35 | 或者放在一个方法内: 36 | 37 | ```javascript 38 | function f() 39 | { 40 | 41 | // 方法级严格模式 42 | 'use strict'; 43 | function nested() { return "And so am I!"; } 44 | return "Hi! I'm a strict mode function! " + nested(); 45 | } 46 | function f2() { return "I'm not strict."; } 47 | ``` 48 | 49 | 50 | 通过在JavaScript文件或方法内引入此指令,使JavaScript引擎运行在严格模式下,这直接禁止了许多大项目中不受欢迎的操作。另外,严格模式也改变了以下行为: 51 | * 只有被"var"声明过的变量才可以引用 52 | * 试图写只读变量时将会报错 53 | * 只能通过"new"关键字调用构造方法 54 | * "this"不再隐式的指向全局变量 55 | * 对eval()有更严格的限制 56 | * 防止你使用预保留关键字命名变量 57 | 58 | 严格模式对于新项目来说是很棒的,但对于一些并没有使用它的老项目来说,引入它也是很有挑战性的。如果你把所有js文件都连接到一个大文件中的话,可能导致所有文件都运行在严格模式下,这可能也会有一些问题。 59 | 60 | 它不是一个声明,而是一个表达式,被低版本的JavaScript忽略。 61 | 严格模式的支持情况: 62 | * Internet Explorer 10+ 63 | * Firefox 4+ 64 | * Chrome 13+ 65 | * Safari 5.1+ 66 | * Opera 12+ 67 | 68 | 69 | [MDN对严格模式的全面介绍](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode) 70 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-08-converting-a-node-list-to-an-array.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 将Node List转换为数组(Array) 5 | tip-number: 08 6 | tip-username: Tevko 7 | tip-username-profile: https://twitter.com/tevko 8 | tip-tldr: 这是一个快速、安全、可重用的方法将node list转换为DOM元素的数组。 9 | 10 | redirect_from: 11 | - /zh_cn/converting-a-node-list-to-an-array/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | `querySelectorAll`方法返回一个类数组对象称为node list。这些数据结构被称为“类数组”,因为他们看似数组却没有类似`map`、`foreach`这样的数组方法。这是一个快速、安全、可重用的方法将node list转换为DOM元素的数组: 19 | 20 | ```javascript 21 | const nodelist = document.querySelectorAll('div'); 22 | const nodelistToArray = Array.apply(null, nodelist); 23 | 24 | 25 | //之后 .. 26 | 27 | nodelistToArray.forEach(...); 28 | nodelistToArray.map(...); 29 | nodelistToArray.slice(...); 30 | 31 | 32 | //等... 33 | ``` 34 | 35 | `apply`方法可以在指定`this`时以数组形式向方法传递参数。[MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)规定`apply`可以接受类数组对象,恰巧就是`querySelectorAll`方法所返回的内容。如果我们不需要指定方法内`this`的值时传`null`或`0`即可。返回的结果即包含所有数组方法的DOM元素数组。 36 | 37 | 另外你可以使用`Array.prototype.slice`结合`Function.prototype.call`或`Function.prototype.apply`, 将类数组对象当做`this`传入: 38 | 39 | ```javascript 40 | const nodelist = document.querySelectorAll('div'); 41 | const nodelistToArray = Array.prototype.slice.call(nodelist); // or equivalently Array.prototype.slice.apply(nodelist); 42 | 43 | //之后 .. 44 | 45 | nodelistToArray.forEach(...); 46 | nodelistToArray.map(...); 47 | nodelistToArray.slice(...); 48 | 49 | //等... 50 | ``` 51 | 52 | 53 | 如果你正在用ES2015你可以使用[展开运算符 `...`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_operator) 54 | 55 | ```js 56 | const nodelist = [...document.querySelectorAll('div')]; // 返回一个真正的数组 57 | 58 | //之后 .. 59 | 60 | nodelist.forEach(...); 61 | nodelist.map(...); 62 | nodelist.slice(...); 63 | 64 | 65 | //等... 66 | ``` 67 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-09-template-strings.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 模板字符串 5 | tip-number: 09 6 | tip-username: JakeRawr 7 | tip-username-profile: https://github.com/JakeRawr 8 | tip-tldr: ES6中,JS现在有了引号拼接字符串的替代品,模板字符串。 9 | 10 | redirect_from: 11 | - /zh_cn/template-strings/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 19 | ES6中,JS现在有了引号拼接字符串的替代品,模板字符串。 20 | 21 | 示例: 22 | 普通字符串 23 | 24 | ```javascript 25 | var firstName = 'Jake'; 26 | var lastName = 'Rawr'; 27 | console.log('My name is ' + firstName + ' ' + lastName); 28 | // My name is Jake Rawr 29 | ``` 30 | 31 | 模板字符串 32 | ```javascript 33 | var firstName = 'Jake'; 34 | var lastName = 'Rawr'; 35 | console.log(`My name is ${firstName} ${lastName}`); 36 | // My name is Jake Rawr 37 | ``` 38 | 39 | 在模板字符串中,你可以不用`\n`来生成多行字符串,在`${}`里做简单的逻辑运算(例如 2+3)甚至使用[逻辑运算符](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Conditional_Operator)。 40 | 41 | ```javascript 42 | var val1 = 1, val2 = 2; 43 | console.log(`${val1} is ${val1 < val2 ? 'less than': 'greater than'} ${val2}`) 44 | // 1 is less than 2 45 | ``` 46 | 47 | 你也可以使用函数修改末班字符串的输出内容;这被称为[带标签的模板字符串](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/template_strings#带标签的模板字符串),其中包含了带标签的模板字符串的示例. 48 | 49 | 50 | 或许你还想[阅读更多内容](https://hacks.mozilla.org/2015/05/es6-in-depth-template-strings-2)来了解模板字符串。 51 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-10-check-if-a-property-is-in-a-object.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 检查某对象是否有某属性 5 | tip-number: 10 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: 这是一些检查某对象是否有某属性的方法。 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_cn/check-if-a-property-is-in-a-object/ 13 | 14 | categories: 15 | - zh_CN 16 | - javascript 17 | --- 18 | 19 | 当你需要检查某属性是否存在于一个[对象](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Working_with_Objects),你可能会这样做: 20 | 21 | ```javascript 22 | var myObject = { 23 | name: '@tips_js' 24 | }; 25 | 26 | 27 | if (myObject.name) { ... } 28 | 29 | ``` 30 | 31 | 这是可以的,但是你需要知道有两种原生方法可以解决此类问题。[`in` 操作符](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/in) 和 [`Object.hasOwnProperty`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty),任何继承自`Object`的对象都可以使用这两种方法。 32 | 33 | ### 看一下较大的区别 34 | 35 | ```javascript 36 | var myObject = { 37 | name: '@tips_js' 38 | }; 39 | 40 | myObject.hasOwnProperty('name'); // true 41 | 'name' in myObject; // true 42 | 43 | 44 | myObject.hasOwnProperty('valueOf'); // false, valueOf 继承自原型链 45 | 'valueOf' in myObject; // true 46 | 47 | ``` 48 | 49 | 50 | 两者检查属性的深度不同,换言之`hasOwnProperty`只在本身有此属性时返回true,而`in`操作符不区分属性来自于本身或继承自原型链。 51 | 52 | 这是另一个例子 53 | 54 | ```javascript 55 | var myFunc = function() { 56 | this.name = '@tips_js'; 57 | }; 58 | myFunc.prototype.age = '10 days'; 59 | 60 | var user = new myFunc(); 61 | 62 | user.hasOwnProperty('name'); // true 63 | 64 | user.hasOwnProperty('age'); // false, 因为age来自于原型链 65 | ``` 66 | 67 | [在线示例](https://jsbin.com/tecoqa/edit?js,console)! 68 | 69 | 同样建议阅读关于检查对象是否包含属性时常见错误的[讨论](https://github.com/loverajoel/jstips/issues/62)。 70 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-11-hoisting.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 变量提升 5 | tip-number: 11 6 | tip-username: squizzleflip 7 | tip-username-profile: https://twitter.com/squizzleflip 8 | tip-tldr: 理解变量提升有助于管理函数作用域 9 | 10 | redirect_from: 11 | - /zh_cn/hoisting/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 理解[变量提升](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/var#var_hoisting)可以帮助你组织方法作用域。只要记住变量声明和方法声明都会被提升到顶部。变量的定义不会提升,即使你在同一行声明和定义一个变量。变量**声明**是让系统知道有这个变量存在而**定义**是给其赋值。 19 | 20 | ```javascript 21 | function doTheThing() { 22 | // ReferenceError: notDeclared is not defined 23 | console.log(notDeclared); 24 | 25 | // Outputs: undefined 26 | console.log(definedLater); 27 | var definedLater; 28 | 29 | definedLater = 'I am defined!' 30 | // Outputs: 'I am defined!' 31 | console.log(definedLater) 32 | 33 | // Outputs: undefined 34 | console.log(definedSimulateneously); 35 | var definedSimulateneously = 'I am defined!' 36 | // Outputs: 'I am defined!' 37 | console.log(definedSimulateneously) 38 | 39 | // Outputs: 'I did it!' 40 | doSomethingElse(); 41 | 42 | function doSomethingElse(){ 43 | console.log('I did it!'); 44 | } 45 | 46 | // TypeError: undefined is not a function 47 | functionVar(); 48 | 49 | var functionVar = function(){ 50 | console.log('I did it!'); 51 | } 52 | } 53 | ``` 54 | 55 | 56 | 为了让你的代码更易读,将所有的变量声明在函数的顶端,这样可以更清楚的知道变量来自哪个作用域。在使用变量之前声明变量。将方法定义在函数的底部。 57 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-12-pseudomandatory-parameters-in-es6-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: ES6中的伪强制参数 5 | tip-number: 12 6 | tip-username: Avraam Mavridis 7 | tip-username-profile: https://github.com/AvraamMavridis 8 | tip-tldr: 在许多编程语言中,方法的参数时默认强制需要的,开发人员需要明确定义一个可选的参数。 9 | 10 | redirect_from: 11 | - /zh_cn/tip-to-measure-performance-of-a-javascript-block/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 在许多编程语言中,方法的参数是默认强制需要的,开发人员必须明确定义一个可选的参数。在Javascript 中每一个参数都是可选的,但是我们可以利用[**es6参数默认值**](http://exploringjs.com/es6/ch_parameter-handling.html#sec_parameter-default-values)特性的优点来达到强制要求这种目的,并且不污染函数体本身。 19 | 20 | ``` javascript 21 | const _err = function( message ){ 22 | 23 | throw new Error( message ); 24 | 25 | } 26 | 27 | const getSum = (a = _err('a is not defined'), b = _err('b is not defined')) => a + b 28 | 29 | getSum( 10 ) // throws Error, b is not defined 30 | 31 | getSum( undefined, 10 ) // throws Error, a is not defined 32 | ``` 33 | 34 | `_err` 是一个即时抛出错误的方法。如果参数中的任何一个没有值,参数默认的值将会被使用, `_err`方法将被调用,并且会抛出一个错误。你可以从[MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Default_parameters)看到更多关于**默认参数特性**的例子。 -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-13-tip-to-measure-performance-of-a-javascript-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 测量javascript代码块性能的小知识 5 | tip-number: 13 6 | tip-username: manmadareddy 7 | tip-username-profile: https://twitter.com/manmadareddy 8 | tip-tldr: 快速的测量javascript的性能,我们可以使用console的方法,例如 ```console.time(label)```和 ```console.timeEnd(label)``` 9 | 10 | redirect_from: 11 | - /zh_cn/fat-arrow-functions/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 快速的测量javascript的性能,我们可以使用console的方法,例如 19 | [```console.time(label)```](https://developer.chrome.com/devtools/docs/console-api#consoletimelabel) 和 [```console.timeEnd(label)```](https://developer.chrome.com/devtools/docs/console-api#consoletimeendlabel) 20 | 21 | 22 | ```javascript 23 | console.time("Array initialize"); 24 | var arr = new Array(100), 25 | len = arr.length, 26 | i; 27 | 28 | for (i = 0; i < len; i++) { 29 | arr[i] = new Object(); 30 | }; 31 | console.timeEnd("Array initialize"); // Outputs: Array initialize: 0.711ms 32 | ``` 33 | 34 | 35 | 更多内容: 36 | [Console object](https://github.com/DeveloperToolsWG/console-object), 37 | [Javascript benchmarking](https://mathiasbynens.be/notes/javascript-benchmarking) 38 | 39 | Demo: [jsfiddle](https://jsfiddle.net/meottb62/) - [codepen](http://codepen.io/anon/pen/JGJPoa) (在浏览器控制台输出) 40 | 41 | > 注意:由于[Mozilla](https://developer.mozilla.org/zh-CN/docs/Web/API/Console/time)不建议将其使用在线上项目中,建议仅在开发中使用。 -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-16-passing-arguments-to-callback-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 向回调方法传递参数 5 | tip-number: 16 6 | tip-username: minhazav 7 | tip-username-profile: https://twitter.com/minhazav 8 | tip-tldr: 通常下,你并不能给回调函数传递参数,但是你可以借助Javascript闭包的优势来传递参数给回调函数。 9 | 10 | redirect_from: 11 | - /zh_cn/passing-arguments-to-callback-functions/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 通常下,你并不能给回调函数传递参数。 比如: 19 | 20 | ```js 21 | function callback() { 22 | console.log('Hi human'); 23 | } 24 | 25 | document.getElementById('someelem').addEventListener('click', callback); 26 | ``` 27 | 28 | 你可以借助Javascript闭包的优势来传递参数给回调函数。看这个例子: 29 | 30 | ```js 31 | function callback(a, b) { 32 | return function() { 33 | console.log('sum = ', (a+b)); 34 | } 35 | } 36 | 37 | var x = 1, y = 2; 38 | document.getElementById('someelem').addEventListener('click', callback(x, y)); 39 | ``` 40 | 41 | **什么是闭包?** 42 | 闭包是指函数有自由独立的变量。换句话说,定义在闭包中的函数可以“记忆”它创建时候的环境。想了解更多请[参考MDN的文档](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures)。 43 | 44 | 这种方法使参数`x`和`y`在回调方法被调用时处于其作用域内。 45 | 46 | 另一个办法是使用`bind`方法。比如: 47 | 48 | ```js 49 | var alertText = function(text) { 50 | alert(text); 51 | }; 52 | 53 | document.getElementById('someelem').addEventListener('click', alertText.bind(this, 'hello')); 54 | ``` 55 | 56 | 两种方法之间有着微小的性能差异,请看[jsperf](http://jsperf.com/bind-vs-closure-23). 57 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-17-nodejs-run-a-module-if-it-is-not-required.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Node.js - 运行未被引用的模块 5 | tip-number: 17 6 | tip-username: odsdq 7 | tip-username-profile: https://twitter.com/odsdq 8 | tip-tldr: 在Node里,你可以让你的程序根据其运行自`require('./something.js')`或者`node something.js`而做不同的处理。如果你想与你的一个独立的模块进行交互,这是非常有用的。 9 | 10 | redirect_from: 11 | - /zh_cn/nodejs-run-a-module-if-it-is-not-required/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 在Node里,你可以让你的程序根据其运行自`require('./something.js')`或者`node something.js`而做不同的处理。如果你想与你的一个独立的模块进行交互,这是非常有用的。 19 | 20 | ```js 21 | if (!module.parent) { 22 | // 通过 `node something.js` 启动 23 | app.listen(8088, function() { 24 | console.log('app listening on port 8088'); 25 | }) 26 | } else { 27 | // 通过 `require('/.something.js')` 被引用 28 | module.exports = app; 29 | } 30 | ``` 31 | 32 | 更多内容请看 [modules的文档](https://nodejs.org/api/modules.html#modules_module_parent) 33 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-19-safe-string-concatenation.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 安全的字符串拼接 5 | tip-number: 19 6 | tip-username: gogainda 7 | tip-username-profile: https://twitter.com/gogainda 8 | tip-tldr: 假如你需要拼接一些不确定类型的变量为字符串,你需要确保算术运算符在你拼接时不会起作用。使用concat 9 | 10 | redirect_from: 11 | - /zh_cn/safe-string-concatenation/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 假如你需要拼接一些不确定类型的变量为字符串,你需要确保算术运算符在你拼接时不会起作用。使用concat: 19 | 20 | ```javascript 21 | var one = 1; 22 | var two = 2; 23 | var three = '3'; 24 | 25 | var result = ''.concat(one, two, three); //"123" 26 | ``` 27 | 28 | 这应该就是你所期望的拼接结果。如果不这样,拼接时加号可能会导致你意想不到的结果: 29 | 30 | ```javascript 31 | var one = 1; 32 | var two = 2; 33 | var three = '3'; 34 | 35 | var result = one + two + three; //"33" instead of "123" 36 | ``` 37 | 38 | 关于性能,与用[```join```](http://www.sitepoint.com/javascript-fast-string-concatenation/)来拼接字符串相比 ```concat```的效率是几乎一样的。 39 | 40 | 你可以在[MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)了解更多关于```concat```方法的内容。 41 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-20-return-objects-to-enable-chaining-of-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 返回对象,使方法可以链式调用 5 | tip-number: 20 6 | tip-username: WakeskaterX 7 | tip-username-profile: https://twitter.com/WakeStudio 8 | tip-tldr: 在面向对象的Javascript中为对象建立一个方法时,返回当前对象可以让你在一条链上调用方法。 9 | 10 | redirect_from: 11 | - /zh_cn/return-objects-to-enable-chaining-of-functions/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 在面向对象的Javascript中为对象建立一个方法时,返回当前对象可以让你在一条链上调用方法。 19 | 20 | ```js 21 | function Person(name) { 22 | this.name = name; 23 | 24 | this.sayName = function() { 25 | console.log("Hello my name is: ", this.name); 26 | return this; 27 | }; 28 | 29 | this.changeName = function(name) { 30 | this.name = name; 31 | return this; 32 | }; 33 | } 34 | 35 | var person = new Person("John"); 36 | person.sayName().changeName("Timmy").sayName(); 37 | ``` 38 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-21-shuffle-an-array.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 对数组洗牌 5 | tip-number: 21 6 | tip-username: 0xmtn 7 | tip-username-profile: https://github.com/0xmtn/ 8 | tip-tldr: Fisher-Yates Shuffling 算法对数组进行洗牌 9 | 10 | redirect_from: 11 | - /zh_cn/shuffle-an-array/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 19 | 这段代码运用了[Fisher-Yates Shuffling](https://www.wikiwand.com/en/Fisher%E2%80%93Yates_shuffle)算法对数组进行洗牌。 20 | 21 | ```javascript 22 | function shuffle(arr) { 23 | var i, 24 | j, 25 | temp; 26 | for (i = arr.length - 1; i > 0; i--) { 27 | j = Math.floor(Math.random() * (i + 1)); 28 | temp = arr[i]; 29 | arr[i] = arr[j]; 30 | arr[j] = temp; 31 | } 32 | return arr; 33 | }; 34 | ``` 35 | 36 | 调用示例: 37 | 38 | ```javascript 39 | var a = [1, 2, 3, 4, 5, 6, 7, 8]; 40 | var b = shuffle(a); 41 | console.log(b); 42 | // [2, 7, 8, 6, 5, 3, 1, 4] 43 | ``` 44 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-22-two-ways-to-empty-an-array.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 清空数组的两种方法 5 | tip-number: 22 6 | tip-username: microlv 7 | tip-username-profile: https://github.com/microlv 8 | tip-tldr: 在JavaScript中清空一个数组有很多方法,但这是一个最高效的方法。 9 | 10 | redirect_from: 11 | - /zh_cn/two-ways-to-empty-an-array/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 如果你定义了一个数组,然后你想清空它。 19 | 通常,你会这样做: 20 | 21 | ```javascript 22 | // 定义一个数组 23 | var list = [1, 2, 3, 4]; 24 | function empty() { 25 | //清空数组 26 | list = []; 27 | } 28 | empty(); 29 | ``` 30 | 31 | 但是,这有一个效率更高的方法来清空数组。 32 | 你可以这样写: 33 | 34 | ```javascript 35 | var list = [1, 2, 3, 4]; 36 | function empty() { 37 | //empty your array 38 | list.length = 0; 39 | } 40 | empty(); 41 | ``` 42 | 43 | * `list = []` 将一个新的数组的引用赋值给变量,其他引用并不受影响。 44 | 这意味着以前数组的内容被引用的话将依旧存在于内存中,这将导致内存泄漏。 45 | 46 | * `list.length = 0` 删除数组里的所有内容,也将影响到其他引用。 47 | 48 | 然而,如果你复制了一个数组(A 和 Copy-A),如果你用`list.length = 0`清空了它的内容,复制的数组也会清空它的内容。 49 | 50 | 考虑一下将会输出什么: 51 | 52 | ```js 53 | var foo = [1,2,3]; 54 | var bar = [1,2,3]; 55 | var foo2 = foo; 56 | var bar2 = bar; 57 | foo = []; 58 | bar.length = 0; 59 | console.log(foo, bar, foo2, bar2); 60 | 61 | //[] [] [1, 2, 3] [] 62 | ``` 63 | 64 | 更多内容请看Stackoverflow: 65 | [difference-between-array-length-0-and-array](http://stackoverflow.com/questions/4804235/difference-between-array-length-0-and-array) 66 | 67 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-23-converting-to-number-fast-way.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 转换为数字的更快方法 5 | tip-number: 23 6 | tip-username: sonnyt 7 | tip-username-profile: http://twitter.com/sonnyt 8 | tip-tldr: 将字符串转换为数字是极为常见的。最简单和快速的方法是使用`+`(加号) 来实现。 9 | 10 | redirect_from: 11 | - /zh_cn/converting-to-number-fast-way/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 将字符串转换为数字是极为常见的。最简单和快速的方法([jsPref](https://jsperf.com/number-vs-parseint-vs-plus/29))`+`(加号) 来实现。 19 | 20 | ```javascript 21 | var one = '1'; 22 | 23 | var numberOne = +one; // Number 1 24 | ``` 25 | 26 | 你也可以用`-`(减号)将其转化为负数值。 27 | 28 | ```javascript 29 | var one = '1'; 30 | 31 | var negativeNumberOne = -one; // Number -1 32 | ``` 33 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-24-use_===_instead_of_==.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 使用 === 而不是 == 5 | tip-number: 24 6 | tip-username: bhaskarmelkani 7 | tip-username-profile: https://www.twitter.com/bhaskarmelkani 8 | tip-tldr: == (或者 `!=`) 操作在需要的情况下自动进行了类型转换。`===` (或 `!==`)操作不会执行任何转换。`===`在比较值和类型时,可以说比`==`更快。 9 | 10 | redirect_from: 11 | - /zh_cn/use_===_instead_of_==/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | `==` (或者 `!=`) 操作在需要的情况下自动进行了类型转换。`===` (或 `!==`)操作不会执行任何转换。`===`在比较值和类型时,可以说比`==`更快([jsPref](http://jsperf.com/strictcompare))。 19 | 20 | ```js 21 | [10] == 10 // 为 true 22 | [10] === 10 // 为 false 23 | 24 | '10' == 10 // 为 true 25 | '10' === 10 // 为 false 26 | 27 | [] == 0 // 为 true 28 | [] === 0 // 为 false 29 | 30 | '' == false // 为 true 但 true == "a" 为false 31 | '' === false // 为 false 32 | 33 | ``` 34 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-25-Using-immediately-invoked-function-expression.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 使用立即执行函数表达式 5 | tip-number: 25 6 | tip-username: rishantagarwal 7 | tip-username-profile: https://github.com/rishantagarwal 8 | tip-tldr: 立即执行函数表达式( IIFE - immediately invoked function expression)是一个立即执行的匿名函数表达式,它在Javascript中有一些很重要的用途。 9 | 10 | 11 | redirect_from: 12 | - /zh_cn/Using-immediately-invoked-function-expression/ 13 | 14 | categories: 15 | - zh_CN 16 | - javascript 17 | --- 18 | 19 | 立即执行函数表达式( IIFE - immediately invoked function expression)是一个立即执行的匿名函数表达式,它在Javascript中有一些很重要的用途。 20 | 21 | ```javascript 22 | 23 | (function() { 24 | // Do something​ 25 | } 26 | )() 27 | 28 | ``` 29 | 30 | 这是一个立即执行的匿名函数表达式,它在有JavaScript一些特别重要的用途。 31 | 32 | 两对括号包裹着一个匿名函数,使匿名函数变成了一个函数表达式。于是,我们现在拥有了一个未命名的函数表达式,而不是一个全局作用域下或在任何地方定义的的简单函数。 33 | 34 | 类似地,我们也可以创建一个命名过的立即执行函数表达式: 35 | 36 | ```javascript 37 | (someNamedFunction = function(msg) { 38 | console.log(msg || "Nothing for today !!") 39 | }) (); // 输出 --> Nothing for today !!​ 40 | ​ 41 | someNamedFunction("Javascript rocks !!"); // 输出 --> Javascript rocks !! 42 | someNamedFunction(); // 输出 --> Nothing for today !!​ 43 | ``` 44 | 45 | 更多内容, 请参考下面链接 - 46 | 1. [链接 1](https://blog.mariusschulz.com/2016/01/13/disassembling-javascripts-iife-syntax) 47 | 2. [链接 2](http://javascriptissexy.com/12-simple-yet-powerful-javascript-tips/) 48 | 49 | 效率: 50 | [jsPerf](http://jsperf.com/iife-with-call) -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-30-converting-truthy-falsy-values-to-boolean.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 将truthy/falsy转换为布尔值 5 | tip-number: 30 6 | tip-username: hakhag 7 | tip-username-profile: https://github.com/hakhag 8 | tip-tldr: 逻辑运算符是JavaScript的核心之一,在这里你将看到一种无论你传什么值都可以总是得到true或false的方法。 9 | 10 | 11 | redirect_from: 12 | - /zh_cn/converting-truthy-falsy-values-to-boolean/ 13 | 14 | categories: 15 | - zh_CN 16 | - javascript 17 | --- 18 | 19 | 你可以使用`!!`操作符将[truthy](https://developer.mozilla.org/zh-CN/docs/Glossary/Truthy)或[falsy](https://developer.mozilla.org/zh-CN/docs/Glossary/Falsy)值转换为布尔值。 20 | 21 | ```js 22 | !!"" // false 23 | !!0 // false 24 | !!null // false 25 | !!undefined // false 26 | !!NaN // false 27 | 28 | !!"hello" // true 29 | !!1 // true 30 | !!{} // true 31 | !![] // true 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-01-31-avoid-modifying-or-passing-arguments-into-other-functions—it-kills-optimization.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 避免修改和传递`arguments`给其他方法 — 影响优化 5 | tip-number: 31 6 | tip-username: berkana 7 | tip-username-profile: https://github.com/berkana 8 | tip-tldr: 在JavaScript的方法里,`arguments`参数可以让你访问传递给该方法的所有参数。`arguments`是一个*类数组对象*;`arguments`可是使用数组标记访问,而且它有*length*参数,但是它没有`filter`、`map`和`forEach`这样内建到数组内的方法。因此,如下代码是一个非常常见的将`arguments`转换为数组的办法 9 | 10 | 11 | redirect_from: 12 | - /zh_cn/avoid-modifying-or-passing-arguments-into-other-functions-it-kills-optimization/ 13 | 14 | categories: 15 | - zh_CN 16 | - javascript 17 | --- 18 | 19 | ### 背景 20 | 21 | 在JavaScript的方法里,[`arguments`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments)参数可以让你访问传递给该方法的所有参数。`arguments`是一个*类数组对象*;`arguments`可是使用数组标记访问,而且它有*length*参数,但是它没有`filter`、`map`和`forEach`这样内建到数组内的方法。因此,如下代码是一个非常常见的将`arguments`转换为数组的办法: 22 | 23 | ```js 24 | var args = Array.prototype.slice.call(arguments); 25 | ``` 26 | 27 | 将`arguments`传递给`Array`原型(prototype)上的`slice`方法;`slice`方法返回一个对`arguments`浅复制后的数组对象。更短的写法: 28 | 29 | ```js 30 | var args = [].slice.call(arguments); 31 | ``` 32 | 33 | 在这里,简单的调用了空数组的`slice`方法,而没有从`Array`的原型(prototype)上调用。 34 | 35 | ### 系统优化 36 | 37 | 不幸的是,传递`arguments`给任何参数,将导致Chrome和Node中使用的V8引擎跳过对其的优化,这也将使性能相当慢。看一下这篇文章[optimization killers](https://github.com/petkaantonov/bluebird/wiki/Optimization-killers)。传递`arguments`给任何方法被称为*leaking `arguments`*。 38 | 39 | 如果你想用一个包含参数(arguments)的数组,你需要求助于这个办法: 40 | 41 | ```js 42 | var args = new Array(arguments.length); 43 | for(var i = 0; i < args.length; ++i) { 44 | args[i] = arguments[i]; 45 | } 46 | ``` 47 | 48 | 没错,这很啰嗦,但是在生产环境中的代码里,为了系统性能优化,这是值得的。 -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-02-01-map-to-the-rescue-adding-order-to-object-properties.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Map()的营救;使对象属性有顺序 5 | tip-number: 32 6 | tip-username: loverajoel 7 | tip-username-profile: https://twitter.com/loverajoel 8 | tip-tldr: 对象是一个无序的对象集合。这意味着如果你想在对象里保存有序的数据,你需要重新处理它,因为对象里的数据不保证是有序的。 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_cn/map-to-the-rescue-adding-order-to-object-properties/ 13 | 14 | categories: 15 | - zh_CN 16 | - javascript 17 | --- 18 | 19 | ## 对象属性顺序 20 | 21 | > 一个对象是一个`Object`类型的实例。它是由一些未排序的元素组成的集合,其中包含了原始变量,对象,和函数。一个对象的属性所对应的函数被称为方法。[ECMAScript](http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf) 22 | 23 | 实际看一下 24 | 25 | ```js 26 | var myObject = { 27 | z: 1, 28 | '@': 2, 29 | b: 3, 30 | 1: 4, 31 | 5: 5 32 | }; 33 | console.log(myObject) // Object {1: 4, 5: 5, z: 1, @: 2, b: 3} 34 | 35 | for (item in myObject) {... 36 | // 1 37 | // 5 38 | // z 39 | // @ 40 | // b 41 | ``` 42 | 43 | 因为技术实现,每个浏览器在排序时都有自己的规则,顺序是不确定的。 44 | 45 | ## 怎么解决呢? 46 | 47 | ### Map 48 | 49 | 使用ES6的新特性Map。[Map](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map) 对象以插入的顺序遍历元素。`for...of`循环为每一次循环返回一个[key, value]数组。 50 | 51 | ```js 52 | var myObject = new Map(); 53 | myObject.set('z', 1); 54 | myObject.set('@', 2); 55 | myObject.set('b', 3); 56 | for (var [key, value] of myObject) { 57 | console.log(key, value); 58 | ... 59 | // z 1 60 | // @ 2 61 | // b 3 62 | ``` 63 | 64 | ### 攻克老浏览器 65 | 66 | Mozilla 建议: 67 | > 所以,如果过你想在跨浏览器环境中模拟一个有序的关联数组,你要么使用两个分开的数组(一个保存key,另一个保存value),要么构建一个单属性对象(single-property objects)的数组。 68 | 69 | ```js 70 | // 使用分开的数组 71 | var objectKeys = [z, @, b, 1, 5]; 72 | for (item in objectKeys) { 73 | myObject[item] 74 | ... 75 | 76 | // 构建一个单属性对象(single-property objects)的数组 77 | var myData = [{z: 1}, {'@': 2}, {b: 3}, {1: 4}, {5: 5}]; 78 | ``` -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-02-02-create-range-0-n-easily-using-one-line.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 仅用一行生成`[0, 1, ..., N-1]`数列 5 | tip-number: 33 6 | tip-username: SarjuHansaliya 7 | tip-username-profile: https://github.com/SarjuHansaliya 8 | tip-tldr: 我们可以创建一个函数,它可以仅用一行代码生成0...(N-1)数列。 9 | 10 | 11 | redirect_from: 12 | - /zh_cn/create-range-0-n-easily-using-one-line/ 13 | 14 | categories: 15 | - zh_CN 16 | - javascript 17 | --- 18 | 19 | 使用下面一行代码,我们就可以生成0...(N-1)数列。 20 | 21 | ### 方法1 (需要 ES5) 22 | 23 | ```js 24 | Array.apply(null, {length: N}).map(Function.call, Number); 25 | ``` 26 | 27 | #### 简要说明 28 | 29 | 1. `Array.apply(null, {length: N})` 返回一个由`undefined`填充的长度为`N`的数组(例如 `A = [undefined, undefined, ...]`)。 30 | 2. `A.map(Function.call, Number)` 返回一个长度为`N`的数组,它的索引为`I`的元素为`Function.call.call(Number, undefined, I, A)`的结果。 31 | 3. `Function.call.call(Number, undefined, I, A)`可转化为`Number(I)`,正好就是`I`。 32 | 4. 结果为:`[0, 1, ..., N-1]`。 33 | 34 | 更全面的介绍,请看[这里](https://github.com/gromgit/jstips-xe/blob/master/tips/33.md). 35 | 36 | ### 方法2 (需要 ES6) 37 | 38 | 这里用到了`Array.from` [https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/from](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/from) 39 | 40 | ```js 41 | Array.from(new Array(N),(val,index)=>index); 42 | ``` 43 | 44 | #### 简要说明 45 | 46 | 1. `A = new Array(N)` 返回一个有`N`个_小孔_的数组 (例如 `A = [,,,...]`, 但是对于`x` in `0...N-1`时`A[x] = undefined`)。 47 | 2. `F = (val,index)=>index` 即 `function F (val, index) { return index; }`。 48 | 3. `Array.from(A, F)` 返回一个长度为`N`的数组,它的索引为`I`的元素为`F(A[I], I)`的结果,也就是`I`。 49 | 4. 结果为:`[0, 1, ..., N-1]`。 50 | 51 | ### One More Thing 52 | 53 | 如果你需要[1, 2, ..., N]序列, **方法1** 可改为: 54 | 55 | ```js 56 | Array.apply(null, {length: N}).map(function(value, index){ 57 | return index + 1; 58 | }); 59 | ``` 60 | 61 | **方法2**可改为: 62 | 63 | ```js 64 | Array.from(new Array(N),(val,index)=>index+1); 65 | ``` -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-02-09-using-json-stringify.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 使用JSON.Stringify 5 | tip-number: 40 6 | tip-username: vamshisuram 7 | tip-username-profile: https://github.com/vamshisuram 8 | tip-tldr: 将JSON对象的参数选择性地生成字符串。 9 | 10 | 11 | redirect_from: 12 | - /zh_cn/using-json-stringify/ 13 | 14 | categories: 15 | - zh_CN 16 | - javascript 17 | --- 18 | 19 | 假如有一个对象具有参数"prop1", "prop2", "prop3"。 20 | 我们可以通过传递 __附加参数__ 给 __JSON.stringify__ 来选择性地将参数生成字符串,像这样: 21 | 22 | ```javascript 23 | var obj = { 24 | 'prop1': 'value1', 25 | 'prop2': 'value2', 26 | 'prop3': 'value3' 27 | }; 28 | 29 | var selectedProperties = ['prop1', 'prop2']; 30 | 31 | var str = JSON.stringify(obj, selectedProperties); 32 | 33 | // str 34 | // {"prop1":"value1","prop2":"value2"} 35 | 36 | ``` 37 | 38 | __"str"__ 将只包含选择的参数。 39 | 40 | 除了传递数组,我们也可以传递函数。 41 | 42 | ```javascript 43 | 44 | function selectedProperties(key, val) { 45 | // the first val will be the entire object, key is empty string 46 | if (!key) { 47 | return val; 48 | } 49 | 50 | if (key === 'prop1' || key === 'prop2') { 51 | return val; 52 | } 53 | 54 | return; 55 | } 56 | ``` 57 | 58 | 最后一个参数,可以修改生成字符串的方式。 59 | 60 | ```javascript 61 | var str = JSON.stringify(obj, selectedProperties, '\t\t'); 62 | 63 | /* str output with double tabs in every line. 64 | { 65 | "prop1": "value1", 66 | "prop2": "value2" 67 | } 68 | */ 69 | 70 | ``` 71 | 72 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-02-10-array-average-and-median.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 数组平均值与中值 5 | tip-number: 41 6 | tip-username: soyuka 7 | tip-username-profile: https://github.com/soyuka 8 | tip-tldr: 计算数组的平均值与中位数 9 | 10 | 11 | redirect_from: 12 | - /zh_cn/array-average-and-median/ 13 | 14 | categories: 15 | - zh_CN 16 | - javascript 17 | --- 18 | 19 | 下面的例子都基于如下数组: 20 | 21 | ```javascript 22 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 23 | ``` 24 | 25 | 要取得平均值,我们需要将数字求和,然后除以`values`的数目,步骤如下: 26 | - 取得数组长度(length) 27 | - 求和(sum) 28 | - 取得平均值(`sum/length`) 29 | 30 | ```javascript 31 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 32 | let sum = values.reduce((previous, current) => current += previous); 33 | let avg = sum / values.length; 34 | // avg = 28 35 | ``` 36 | 37 | 或者: 38 | 39 | ```javascript 40 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 41 | let count = values.length; 42 | values = values.reduce((previous, current) => current += previous); 43 | values /= count; 44 | // avg = 28 45 | ``` 46 | 47 | 取得中值的步骤是: 48 | - 将数组排序 49 | - 取得中位数 50 | 51 | ```javascript 52 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 53 | values.sort((a, b) => a - b); 54 | let lowMiddle = Math.floor((values.length - 1) / 2); 55 | let highMiddle = Math.ceil((values.length - 1) / 2); 56 | let median = (values[lowMiddle] + values[highMiddle]) / 2; 57 | // median = 13,5 58 | ``` 59 | 60 | 或者使用[无符号右移](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Right_shift)操作符: 61 | 62 | ```javascript 63 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 64 | values.sort((a, b) => a - b); 65 | let median = (values[(values.length - 1) >> 1] + values[values.length >> 1]) / 2 66 | // median = 23 67 | ``` 68 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-02-11-preventing-unapply-attacks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 预防unapply攻击 5 | tip-number: 42 6 | tip-username: emars 7 | tip-username-profile: https://twitter.com/marseltov 8 | tip-tldr: 冻结内置对象的原型方法。 9 | 10 | redirect_from: 11 | - /zh_cn/preventing-unapply-attacks/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 重写内置对象的原型方法,外部代码可以通过重写代码达到暴漏和修改已绑定参数的函数。这在es5的方法下使用`polyfill`时是一个严重的安全问题。 19 | 20 | ```js 21 | // bind polyfill 示例 22 | function bind(fn) { 23 | var prev = Array.prototype.slice.call(arguments, 1); 24 | return function bound() { 25 | var curr = Array.prototype.slice.call(arguments, 0); 26 | var args = Array.prototype.concat.apply(prev, curr); 27 | return fn.apply(null, args); 28 | }; 29 | } 30 | 31 | 32 | // unapply攻击 33 | function unapplyAttack() { 34 | var concat = Array.prototype.concat; 35 | Array.prototype.concat = function replaceAll() { 36 | Array.prototype.concat = concat; // restore the correct version 37 | var curr = Array.prototype.slice.call(arguments, 0); 38 | var result = concat.apply([], curr); 39 | return result; 40 | }; 41 | } 42 | ``` 43 | 44 | 上面的函数声明忽略了函数bind的`prev`参数,意味着调用`unapplyAttack`之后首次调用`.concat`将会抛出错误。 45 | 46 | 使用[Object.freeze](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze),可以使对象不可变,你可以防止任何内置对象原型方法被重写。 47 | 48 | 49 | ```js 50 | (function freezePrototypes() { 51 | if (typeof Object.freeze !== 'function') { 52 | throw new Error('Missing Object.freeze'); 53 | } 54 | Object.freeze(Object.prototype); 55 | Object.freeze(Array.prototype); 56 | Object.freeze(Function.prototype); 57 | }()); 58 | ``` 59 | 60 | 你可以[在这里](https://glebbahmutov.com/blog/unapply-attack/)阅读更多关于unapply攻击。 -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-02-13-know-the-passing-mechanism.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 了解传值机制 5 | tip-number: 44 6 | tip-username: bmkmanoj 7 | tip-username-profile: https://github.com/bmkmanoj 8 | tip-tldr: JavaScript理论上说只传递原始类型和对象(或引用)类型的值。在引用类型的情况下引用值本身通过值传递。 9 | 10 | redirect_from: 11 | - /zh_cn/know-the-passing-mechanism/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 理论上,JavaScript通过值传递。它既不是值传递也不是引用传递,具体取决于它的真实场景。要理解传值机制,看一下下面两个实例代码和解释。 19 | 20 | ### 实例 1 21 | 22 | ```js 23 | 24 | var me = { // 1 25 | 'partOf' : 'A Team' 26 | }; 27 | 28 | function myTeam(me) { // 2 29 | 30 | me = { // 3 31 | 'belongsTo' : 'A Group' 32 | }; 33 | } 34 | 35 | myTeam(me); 36 | console.log(me); // 4 : {'partOf' : 'A Team'} 37 | 38 | ``` 39 | 40 | 在上面的实例里`myTeam`被调用的时候,JavaScript *传递*`me`*对象的引用值,因为它是一个对象*。而且调用本身建立了同一个对象的两个独立的引用,(虽然在这里的的命名都是相同的,比如`me`, 这有些无调行,而且给我们一个这是单个引用的印象)因此,引用变量本身是独立的。 41 | 42 | 当我们在#`3`定义了一个新的对象,我们完全改变了`myTeam`函数内的引用值,这对此函数作用域外的原始对象是没有任何影响的,外作用域的引用仍保留在原始对象上,因此从#`4`输出去了。 43 | 44 | 45 | ### 实例 2 46 | 47 | ```js 48 | 49 | var me = { // 1 50 | 'partOf' : 'A Team' 51 | }; 52 | 53 | function myGroup(me) { // 2 54 | me.partOf = 'A Group'; // 3 55 | } 56 | 57 | myGroup(me); 58 | console.log(me); // 4 : {'partOf' : 'A Group'} 59 | 60 | ``` 61 | 62 | 当`myGroup`调用时,我们将对象`me`传给函数。但是与实例1的情况不同,我们没有指派`me`变量到任何新对象,有效的说明了`myGroup`函数作用域内的对象引用值依旧是原始对象的引用值,而且我们在作用域内修改对象的参数值同样有效的修改了原始对象的参数。因此你得到了#`7`的输出结果。 63 | 64 | 所以后面的例子是否说明javascript是引用传递呢?不,并没有。请记住,*如果是对象的话,JavaScript将引用按值传递*。这种混乱往往发生在我们没有完全理解什么通过引用传递的情况下。这就是确切的原因,有些人更愿意称它为*call-by-sharing*。 65 | 66 | 67 | *此文最初被作者发表在[js-by-examples](https://github.com/bmkmanoj/js-by-examples/blob/master/examples/js_pass_by_value_or_reference.md)* -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-02-14-calculate-the-max-min-value-from-an-array.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 计算数组中的最大值/最小值 5 | tip-number: 45 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: 对于纯数字数组,使用内置函数Math.max()和Math.min()的方法。 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_cn/calculate-the-max-min-value-from-an-array/ 13 | 14 | categories: 15 | - zh_CN 16 | - javascript 17 | --- 18 | 19 | 内置函数[Math.max()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math/max)和[Math.min()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math/min)可以分别找出参数中的最大值和最小值。 20 | 21 | ```js 22 | Math.max(1, 2, 3, 4); // 4 23 | Math.min(1, 2, 3, 4); // 1 24 | ``` 25 | 26 | 这些函数对于数字组成的数组是不能用的。但是,这有一些类似地方法。 27 | 28 | [`Function.prototype.apply()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)让你可以使用提供的`this`与参数组成的_数组(array)_来调用函数。 29 | 30 | ```js 31 | var numbers = [1, 2, 3, 4]; 32 | Math.max.apply(null, numbers) // 4 33 | Math.min.apply(null, numbers) // 1 34 | ``` 35 | 36 | 给`apply()`第二个参数传递`numbers`数组,等于使用数组中的所有值作为函数的参数。 37 | 38 | 一个更简单的,基于ES2015的方法来实现此功能,是使用[展开运算符](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_operator). 39 | 40 | ```js 41 | var numbers = [1, 2, 3, 4]; 42 | Math.max(...numbers) // 4 43 | Math.min(...numbers) // 1 44 | ``` 45 | 46 | 此运算符使数组中的值在函数调用的位置展开。 47 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-02-15-detect-document-ready-in-pure-js.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 纯JS监听document是否加载完成 5 | tip-number: 46 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: 跨浏览器且纯JavaScript检测document是否加载完成。 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_cn/detect-document-ready-in-pure-js/ 13 | 14 | categories: 15 | - zh_CN 16 | - javascript 17 | --- 18 | 19 | 跨浏览器且纯JavaScript检测document是否加载完成的方法是使用[`readyState`](https://developer.mozilla.org/zh-CN/docs/Web/API/Document/readyState). 20 | 21 | ```js 22 | if (document.readyState === 'complete') { 23 | // 页面已完全加载 24 | } 25 | ``` 26 | 27 | 这样可以在document完全加载时监测到…… 28 | 29 | 30 | ```js 31 | let stateCheck = setInterval(() => { 32 | if (document.readyState === 'complete') { 33 | clearInterval(stateCheck); 34 | // document ready 35 | } 36 | }, 100); 37 | ``` 38 | 39 | 或者使用[onreadystatechange](https://developer.mozilla.org/zh-CN/docs/Web/Events/readystatechange) 40 | 41 | 42 | ```js 43 | document.onreadystatechange = () => { 44 | if (document.readyState === 'complete') { 45 | // document ready 46 | } 47 | }; 48 | ``` 49 | 50 | 使用`document.readyState === 'interactive'`监听DOM是否加载完成。 51 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-02-26-extract-unix-timestamp-easily.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 简单获取unix时间戳 5 | tip-number: 49 6 | tip-username: nmrony 7 | tip-username-profile: https://github.com/nmrony 8 | tip-tldr: 在Javascript里,你可以简单的取得unix时间戳 9 | 10 | redirect_from: 11 | - /zh_cn/extract-unix-timestamp-easily/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 19 | 我们经常需要使用unix时间戳计算。有很多方法可以取得unix时间戳。目前取得unix时间戳最简单最快的方法是: 20 | 21 | ```js 22 | const dateTime = Date.now(); 23 | const timestamp = Math.floor(dateTime / 1000); 24 | ``` 25 | 或 26 | 27 | ```js 28 | const dateTime = new Date().getTime(); 29 | const timestamp = Math.floor(dateTime / 1000); 30 | ``` 31 | 32 | 要取得一个具体时间的unix时间戳,将`yyyy-mm-dd`或`YYYY-MM-DDT00:00:00Z`作为参数传递给`Date`构造函数。例如 33 | 34 | ```js 35 | const dateTime = new Date('2012-06-08').getTime(); 36 | const timestamp = Math.floor(dateTime / 1000); 37 | ``` 38 | 39 | 你还可以像下面一样,在声明`Date`对象的时候添加一个`+`号 40 | 41 | ```js 42 | const dateTime = +new Date(); 43 | const timestamp = Math.floor(dateTime / 1000); 44 | ``` 45 | 或者对于具体时间 46 | 47 | ```js 48 | const dateTime = +new Date('2012-06-08'); 49 | const timestamp = Math.floor(dateTime / 1000); 50 | ``` 51 | 52 | 在底层,运行时调用了`Date`对象的`valueOf`方法。然后一元操作符`+`调用了之前返回值的`toNumber()`方法。想要了解更多内容请参考下面链接 53 | 54 | * [Date.prototype.valueOf](http://es5.github.io/#x15.9.5.8) 55 | * [Unary + operator](http://es5.github.io/#x11.4.6) 56 | * [toNumber()](http://es5.github.io/#x9.3) 57 | * [Date Javascript MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) 58 | * [Date.parse()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse) 59 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-03-03-helpful-console-log-hacks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 实用的`log`技巧 5 | tip-number: 50 6 | tip-username: zackhall 7 | tip-username-profile: https://twitter.com/zthall 8 | tip-tldr: 运用`&&`与条件断点的实用的`log`技巧 9 | 10 | redirect_from: 11 | - /zh_cn/helpful-console-log-hacks/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | ## 使用条件断点输出`log` 19 | 20 | 如果你想当函数每次被调用时都在控制台打印一个值,你可以应用条件断点来实现。打开你的开发工具,找到你准备打印的值所在的函数然后使用如下条件设置一个条件断点: 21 | 22 | ```js 23 | console.log(data.value) && false 24 | ``` 25 | 26 | 条件断点只有在条件运行的结果为`true`时才会中断页面。所以使用`console.log('foo') && false`这样的条件,由于你把`false`放在了`AND`条件中,所以结果肯定是`false`。因此这并不会中断页面但是会打印`log`到控制台。这也可以应用在计算某个函数或回调被调用了多少次上面。 27 | 28 | 这里有各个平台下设置条件断点的方法:[Edge](https://dev.windows.com/en-us/microsoft-edge/platform/documentation/f12-devtools-guide/debugger/#setting-and-managing-breakpoints "Managing Breakpoints in Edge")、[Chrome](https://developer.chrome.com/devtools/docs/javascript-debugging#breakpoints "Managing Breakpoints in Chrome")、[Firefox](https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Set_a_conditional_breakpoint "Managing Breakpoints in Firefox")、[Safari](https://developer.apple.com/library/mac/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/Debugger/Debugger.html "Managing Breakpoints in Safari")。 29 | 30 | ## 打印函数到控制台 31 | 32 | 你曾经有过打算打印函数到控制台却不能看到函数的代码的情况吗?最快的方法查看函数的代码是将其与空字符串连接,从而将其强制转换为字符串。 33 | 34 | ```js 35 | console.log(funcVariable + ''); 36 | ``` -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-03-16-DOM-event-listening-made-easy.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 简单监听DOM事件 5 | tip-number: 51 6 | tip-username: octopitus 7 | tip-username-profile: https://github.com/octopitus 8 | tip-tldr: 简单而优雅地操作DOM事件的方法 9 | 10 | redirect_from: 11 | - /zh_cn/DOM-event-listening-made-easy/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 很多人还在这样做: 18 | 19 | - `element.addEventListener('type', obj.method.bind(obj))` 20 | - `element.addEventListener('type', function (event) {})` 21 | - `element.addEventListener('type', (event) => {})` 22 | 23 | 上面所有的例子都创建了一个匿名事件监控句柄,且在不需要时无法删除它。这在你不需要某句柄,而它却被用户或[事件冒泡](http://www.javascripter.net/faq/eventbubbling.htm)偶然触发时,可能会导致性能问题或不必要的逻辑问题。 24 | 25 | 更安全的事件处理方式如下: 26 | 27 | 使用引用: 28 | 29 | ```js 30 | const handler = function () { 31 | console.log("Tada!") 32 | } 33 | element.addEventListener("click", handler) 34 | // 之后 35 | element.removeEventListener("click", handler) 36 | ``` 37 | 38 | 命名的函数移除它本身: 39 | 40 | ```js 41 | element.addEventListener('click', function click(e) { 42 | if (someCondition) { 43 | return e.currentTarget.removeEventListener('click', click); 44 | } 45 | }); 46 | ``` 47 | 48 | 更好的写法: 49 | 50 | ```js 51 | function handleEvent (eventName, {onElement, withCallback, useCapture = false} = {}, thisArg) { 52 | const element = onElement || document.documentElement 53 | 54 | function handler (event) { 55 | if (typeof withCallback === 'function') { 56 | withCallback.call(thisArg, event) 57 | } 58 | } 59 | 60 | handler.destroy = function () { 61 | return element.removeEventListener(eventName, handler, useCapture) 62 | } 63 | 64 | element.addEventListener(eventName, handler, useCapture) 65 | return handler 66 | } 67 | 68 | // 你需要的时候 69 | const handleClick = handleEvent('click', { 70 | onElement: element, 71 | withCallback: (event) => { 72 | console.log('Tada!') 73 | } 74 | }) 75 | 76 | // 你想删除它的时候 77 | handleClick.destroy() 78 | ``` 79 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-04-05-return-values-with-the-new-operator.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: new的返回值 5 | tip-number: 52 6 | tip-username: Morklympious 7 | tip-username-profile: https://github.com/morklympious 8 | tip-tldr: 理解使用new与不使用new时将返回什么值 9 | 10 | redirect_from: 11 | - /zh_cn/return-values-with-the-new-operator/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 18 | 你将会遇到在JavaScript中使用`new`来分配新对象的一些情况。这将会扰乱你的思绪,除非你阅读了这篇文章并理解在内部发生了什么。 19 | 20 | JavaScript中的`new`操作在合理的情况下然会一个新的对象实例。我们来看,我们有一个构造函数: 21 | 22 | ````js 23 | function Thing() { 24 | this.one = 1; 25 | this.two = 2; 26 | } 27 | 28 | var myThing = new Thing(); 29 | 30 | myThing.one // 1 31 | myThing.two // 2 32 | ```` 33 | 34 | __提示__: `this`指向`new`产生的新对象。否则如果`Thing()`不是用`new`调用, __将不会生成新对象__, 而且`this` 将会指向全局对象,也就是`window`。这意味着: 35 | 36 | 1. 你突然有两个全局变量`one`和`two`。 37 | 2. `myThing`现在为`undefined`,因为`Thing()`中没有返回任何东西。 38 | 39 | 现在我们又有一个例子,而它却有些让人搞不懂。我们看我在构造函数里加了一条语句: 40 | 41 | ````js 42 | function Thing() { 43 | this.one = 1; 44 | this.two = 2; 45 | 46 | return 5; 47 | } 48 | 49 | var myThing = new Thing(); 50 | ```` 51 | 52 | 现在`myThing`等于什么呢?5?一个对象?还是我受伤的自我价值观?或许永远不知道! 53 | 54 | 除了能知道: 55 | 56 | ````js 57 | myThing.one // 1 58 | myThing.two // 2 59 | ```` 60 | 61 | 很有趣,我们构造函数里`返回`的5怎么找不到了?这很奇怪不是吗?函数都做了什么?5呢?让我们再试试别的。 62 | 63 | 我们返回一个非原始类型试一下,比如一个对象: 64 | 65 | ````js 66 | function Thing() { 67 | this.one = 1; 68 | this.two = 2; 69 | 70 | return { 71 | three: 3, 72 | four: 4 73 | }; 74 | } 75 | 76 | var myThing = new Thing(); 77 | ```` 78 | 79 | 让我们试一试。直接`console.log`出所有内容: 80 | 81 | ````js 82 | console.log(myThing); 83 | /* 84 | Object {three: 3, four: 4} 85 | this.one 和 this.two发生了什么!? 86 | 他们被覆盖了,朋友。 87 | */ 88 | ```` 89 | 90 | __我们了解到:__ 当你使用`new`关键字调用一个函数的时候,你可以使用`this`关键字给其设置参数(但这些你应该已经知道了)。使用`new`关键字调用一个返回原始变量的函数将不会返回你指定的值,而是返回函数的实例`this`(你指定参数的那个对象,像 `this.one = 1;`). 91 | 92 | 然而,返回一个非原始变量像`object`、`array`或`function`将会覆盖`this`实例,并返回那个非原始变量,有效的破坏了你分配给`this`的所有工作。 93 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-08-02-copy-to-clipboard.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 复制到粘贴板 5 | tip-number: 56 6 | tip-username: loverajoel 7 | tip-username-profile: https://twitter.com/loverajoel 8 | tip-tldr: 本周我做了一个简单的“复制到剪贴板”按钮,这是我第一次做这种功能,向大家分享一下我的实现方法。 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_cn/copy-to-clipboard/ 13 | 14 | categories: 15 | - zh_CN 16 | - javascript 17 | --- 18 | 19 | 这是一个简单的小知识,本周我做了一个简单的“复制到剪贴板”按钮,这是我第一次做这种功能,向大家分享一下我的实现方法。 20 | 21 | 这很简单,比较麻烦的是我们必须为需要复制的文本增加``标签。之后我们选择要复制的内容然后调用复制命令[execCommand](https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand). 22 | `execCommand('copy')` 将会复制被选择的内容。 23 | 24 | 此方法目前被所有最新版本的浏览器[支持](http://caniuse.com/#search=execCommand),它可以让我们执行如`复制`、`剪切`、`粘贴`等命令,还可以改变字体颜色、大小等。 25 | 26 | ```js 27 | document.querySelector('#input').select(); 28 | document.execCommand('copy'); 29 | ``` 30 | 31 | 具体表现看[这里](https://jsbin.com/huhozu/edit?html,js,output) 32 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-08-10-comma-operaton-in-js.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: JavaScript 的逗号操作符 5 | tip-number: 57 6 | tip-username: bhaskarmelkani 7 | tip-username-profile: https://www.twitter.com/bhaskarmelkani 8 | tip-tldr: 在一个表达式中,由左到右计算每个表达式并返回最后一个。 9 | 10 | redirect_from: 11 | - /zh_cn/comma-operaton-in-js/ 12 | 13 | categories: 14 | - zh_CN 15 | - javascript 16 | --- 17 | 除了分号之外,逗号允许你在同一个地方放多个语句。 18 | 例如: 19 | 20 | ```js 21 | for(var i=0, j=0; i<5; i++, j++, j++){ 22 | console.log("i:"+i+", j:"+j); 23 | } 24 | ``` 25 | 26 | 輸出: 27 | 28 | ```js 29 | i:0, j:0 30 | i:1, j:2 31 | i:2, j:4 32 | i:3, j:6 33 | i:4, j:8 34 | ``` 35 | 36 | 当放一个表达式时,它由左到右计算每个表达式,并传回最右边的表达式。 37 | 38 | 例如: 39 | 40 | ```js 41 | function a(){console.log('a'); return 'a';} 42 | function b(){console.log('b'); return 'b';} 43 | function c(){console.log('c'); return 'c';} 44 | 45 | var x = (a(), b(), c()); 46 | 47 | console.log(x); // 输出「c」 48 | ``` 49 | 输出: 50 | 51 | ```js 52 | "a" 53 | "b" 54 | "c" 55 | 56 | "c" 57 | ``` 58 | 59 | * 注意:逗号(`,`)操作符在 JavaScript 中所有的操作符里是最低的优先顺序,所以没有括号表达式将变为:`(x = a()), b(), c();`。 60 | 61 | ##### 实验 62 |
    63 | JS Bin on jsbin.com 64 |
    65 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2016-10-28-three-useful-hacks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 三个实用的javascript小技巧 5 | tip-number: 60 6 | tip-username: leandrosimoes 7 | tip-username-profile: https://github.com/leandrosimoes 8 | tip-tldr: 分享三个让开发变得更高效的实用语法糖 9 | 10 | 11 | redirect_from: 12 | - /zh_cn/three-useful-hacks/ 13 | 14 | categories: 15 | - zh_CN 16 | - javascript 17 | --- 18 | 19 | #### 从后向前获取数组元素 20 | 21 | 如果你想从后向前获取一个数组的元素,可以这样写: 22 | 23 | ```javascript 24 | var newArray = [1, 2, 3, 4] 25 | 26 | console.log(newArray.slice(-1)) // [4] 27 | console.log(newArray.slice(-2)) // [3, 4] 28 | console.log(newArray.slice(-3)) // [2, 3, 4] 29 | console.log(newArray.slice(-4)) // [1, 2, 3, 4] 30 | ``` 31 | 32 | #### 短路条件句 33 | 34 | 如果你想在某个条件逻辑值为`true`时,执行某个函数,就像这样: 35 | 36 | ```javascript 37 | if (condition) { 38 | dosomething() 39 | } 40 | ``` 41 | 42 | 这时,你可以这样子运用短路: 43 | 44 | ```javascript 45 | condition && dosomething() 46 | ``` 47 | 48 | #### 用操作符 "||" 来设置默认值 49 | 50 | 如果你必须给一个变量赋默认值,可以简单的这样写: 51 | 52 | ```javascript 53 | var a 54 | 55 | console.log(a) // undefined 56 | 57 | a = a || 'default value' 58 | 59 | console.log(a) // default value 60 | 61 | a = a || 'new value' 62 | 63 | console.log(a) // default value 64 | ``` 65 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2017-01-19-binding-objects-to-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 给函数 Bind 对象 5 | tip-number: 61 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: 理解在 JavaScript 中如何使用 `Bind` 方法绑定对象和函数 9 | 10 | 11 | redirect_from: 12 | - /zh_cn/binding-objects-to-functions/ 13 | 14 | categories: 15 | - zh_CN 16 | - javascript 17 | --- 18 | 19 | 我们常常需要将一个对象绑定到一个方法的 `this` 上。在 JS 中,如果你想要调用一个函数并指定它的 `this` 时可以使用 `bind` 方法。 20 | 21 | ### Bind 语法 22 | 23 | ```js 24 | fun.bind(thisArg[, arg1[, arg2[, ...]]]) 25 | ``` 26 | 27 | ## 参数 28 | **thisArg** 29 | 30 | 当绑定函数被调用时,该参数会作为原函数运行时的 this 指向。 31 | 32 | **arg1, arg2, ...** 33 | 34 | 当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。 35 | 36 | **返回值** 37 | 38 | 返回由指定的this值和初始化参数改造的原函数拷贝 39 | 40 | ### JS 中的实例 41 | 42 | ```js 43 | const myCar = { 44 | brand: 'Ford', 45 | type: 'Sedan', 46 | color: 'Red' 47 | }; 48 | 49 | const getBrand = function () { 50 | console.log(this.brand); 51 | }; 52 | 53 | const getType = function () { 54 | console.log(this.type); 55 | }; 56 | 57 | const getColor = function () { 58 | console.log(this.color); 59 | }; 60 | 61 | getBrand(); // object not bind,undefined 62 | 63 | getBrand(myCar); // object not bind,undefined 64 | 65 | getType.bind(myCar)(); // Sedan 66 | 67 | let boundGetColor = getColor.bind(myCar); 68 | boundGetColor(); // Red 69 | 70 | ``` -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2017-03-09-working-with-websocket-timeout.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 处理 Websocket 超时问题 5 | tip-number: 63 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: 一个控制超时的技巧 9 | 10 | categories: 11 | - zh_CN 12 | - javascript 13 | --- 14 | 15 | 在 websocket 连接被建立后,如果一段时间未活动,服务器或防火墙可能会超时或终止连接。想要解决这个问题, 我们可以周期性地给服务器发消息。我们需要两个方法实现:一个来确保连接不会中断,,另一个用来取消此设定。同我们也需要一个 ```timerID``` 变量. 16 | 17 | 让我们来看一下具体实现: 18 | 19 | ```js 20 | var timerID = 0; 21 | function keepAlive() { 22 | var timeout = 20000; 23 | if (webSocket.readyState == webSocket.OPEN) { 24 | webSocket.send(''); 25 | } 26 | timerId = setTimeout(keepAlive, timeout); 27 | } 28 | function cancelKeepAlive() { 29 | if (timerId) { 30 | clearTimeout(timerId); 31 | } 32 | } 33 | ``` 34 | 35 | 现在我们实现了我们需要的两个方法,我们可以在 ```onOpen()``` 的最后面调用 ```keepAlive()``` ,在```onClose()``` 的组后面调用 ```cancelKeepAlive()```。 36 | 37 | 好了!我们我们完美的解决了 websocket 超时的问题。 38 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2017-04-03-why-you-should-use-Object.is()-in-equality-comparison.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 为什么你应该在相等比较中使用 Object.is() 5 | tip-number: 68 6 | tip-username: TarekAlQaddy 7 | tip-username-profile: https://github.com/TarekAlQaddy 8 | tip-tldr: JavaScript 中一个很棒的相等比较解决方案 9 | 10 | categories: 11 | - zh_CN 12 | - javascript 13 | --- 14 | 15 | 我们都知道 JavasSript 是弱类型的,并且当我们使用 `==` 作比较时,在一些情况下由于类型转换或者说“把两个操作数中的一个转换成另一个,然后在比较”,会出现意想不到的结果。 16 | 17 | ``` javascript 18 | 0 == ' ' //true 19 | null == undefined //true 20 | [1] == true //true 21 | ``` 22 | 23 | 因此 JavaScript 中给我们提供了全等操作符 `===`, 它比不全等操作符更加严格并且不会发生类型转换。但是用 `===` 来进行比较并不是最好的解决方案。你可能会得到: 24 | 25 | ``` javascript 26 | NaN === NaN //false 27 | ``` 28 | 29 | 好消息是 ES6 中提供了新的 `Object.is()` 方法,它具有 `===` 的一些特点,而且更好、更精确,在一些特殊案例中表现的很好: 30 | 31 | ``` javascript 32 | Object.is(0 , ' '); //false 33 | Object.is(null, undefined); //false 34 | Object.is([1], true); //false 35 | Object.is(NaN, NaN); //true 36 | ``` 37 | 38 | Mozilla 团队并不认为 Object.is 比 `===` 更加“严格”,他们说我们应该考虑的是这个方法如何处理 NaN, -0 和 +0。但是总的来说, 我认为它在实际应用中是一个很好的实践。 39 | 40 | 现在来看看这张图表的对比... 41 | 42 | ![differences of operators in equality comparisons javascript](http://i.imgur.com/pCyqkLc.png) 43 | 44 | ## References: 45 | [Equality comparisons and sameness](http://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness) 46 | 47 | -------------------------------------------------------------------------------- /_posts/zh_CN/javascript/2017-04-05-picking-and-rejecting-object-properties.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 选择(picking)和反选(rejecting)对象的属性 5 | tip-number: 70 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: 有时候我们需要将一个对象的某些属性放到白名单里,这样来说,我们有一个数组代表了一张数据库表,并且为了一些功能我们需要从中选出(`select`)一些字段。 9 | 10 | categories: 11 | - zh_CN 12 | - javascript 13 | --- 14 | 15 | 16 | 有时候我们需要将一个对象的某些属性放到白名单里,这样来说,我们有一个数组代表了一张数据库表,并且为了一些功能我们需要从中选出(`select`)一些字段: 17 | 18 | ``` javascript 19 | function pick(obj, keys) { 20 | return keys.map(k => k in obj ? {[k]: obj[k]} : {}) 21 | .reduce((res, o) => Object.assign(res, o), {}); 22 | } 23 | 24 | const row = { 25 | 'accounts.id': 1, 26 | 'client.name': 'John Doe', 27 | 'bank.code': 'MDAKW213' 28 | }; 29 | 30 | const table = [ 31 | row, 32 | {'accounts.id': 3, 'client.name': 'Steve Doe', 'bank.code': 'STV12JB'} 33 | ]; 34 | 35 | pick(row, ['client.name']); // 取到了 client name 36 | 37 | table.map(row => pick(row, ['client.name'])); // 取到了一系列 client name 38 | ``` 39 | 40 | 在 pick 函数中用到了一点‘诡计’。首先,我们用 `map` 遍历了键名数组(keys), 每次都会返回一个包含当前键名(key)的对象(如果在目标对象(obj)中没有当前键名,就会返回空对象)。然后我们用 `reduce` 把返回的所有单个键-值对象和合并到一个对象中。 41 | 42 | 但是,如果我们想反选(`reject`)属性/键名呢?改造一下我们的函数就好了: 43 | 44 | ``` javascript 45 | function reject(obj, keys) { 46 | return Object.keys(obj) 47 | .filter(k => !keys.includes(k)) 48 | .map(k => ({[k]: obj[k]})) 49 | .reduce((res, o) => Object.assign(res, o), {}); 50 | } 51 | 52 | // 或者, 利用 pick 53 | function reject(obj, keys) { 54 | const vkeys = Object.keys(obj) 55 | .filter(k => !keys.includes(k)); 56 | return pick(obj, vkeys); 57 | } 58 | 59 | reject({a: 2, b: 3, c: 4}, ['a', 'b']); // => {c: 4} 60 | ``` -------------------------------------------------------------------------------- /_posts/zh_CN/more/2017-04-06-vuejs-how-vuejs-makes-a-copy-update-replace-inside-the-data-binding.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Vuejs在資料綁定時會複製更新並替換目標元素 5 | tip-number: 71 6 | tip-username: pansila 7 | tip-username-profile: https://github.com/pansila 8 | tip-tldr: 在這個提示中,我會通過一個例子向您展示Vue會如何與其它軟體衝突如果你不知道這一點。 9 | 10 | categories: 11 | - zh_CN 12 | --- 13 | 14 | ### 概述 15 | 16 | Vuejs是一款簡單而強大的軟體傑作,類似其它流行的UI框架,Angularjs和Reactjs,但不像這兩者令人生畏的複雜性,Vue非常簡單,在從入門到放棄之前,你能很快掌握它的全部知識並投入生產。 17 | 18 | 但是如果你不知道它怎麼工作的,有時候它也會難為你。這裡是一個和其它UI框架(Framework7)衝突的例子。 19 | 20 | ```html 21 | 22 |
    23 |
    24 | 25 | new page 26 |
    27 |
    28 | 29 | 30 |
    31 |
    32 |
    33 |

    {% raw %}{{content}}{% endraw %}

    34 |
    35 |
    36 |
    37 | ``` 38 | 39 | ```js 40 | var myApp = new Framework7(); 41 | myApp.onPageInit('test', function (page) { 42 | new Vue({ 43 | el: '#test', 44 | data: { 45 | content: 'hello world' 46 | } 47 | }); 48 | }); 49 | ``` 50 | 51 | 你可能會驚訝它竟然無法工作,新的page點擊後並沒有顯示出來。事實上,Vue內部會複製目標HTML元素,然後根據綁定的資料更新並替換原來的元素。當Framework7載入新的頁面時,它會調用`PageInit`回呼函數,這裡我們又調用了Vue在``元素上資料綁定,這之後DOM樹裡面包含的已經是新的``元素,但Framework7對此並不知情又接著在舊的``元素上完成剩下的初始化工作,比如最終顯示這個新的頁面,這就是根本原因。 52 | 53 | 為了繞過這個問題,不要讓Vue的元素選擇器錨定在``元素上,而是定在它的子元素,這樣Vue做資料綁定時就不會影響到整個頁面顯示。 54 | 55 | ```js 56 | var myApp = new Framework7(); 57 | myApp.onPageInit('test', function (page) { 58 | new Vue({ 59 | el: '#test1', 60 | data: { 61 | content: 'hello world' 62 | } 63 | }); 64 | }); 65 | ``` 66 | 67 | ### 更多資訊 68 | 69 | - [Vue](https://github.com/Vuejs/Vue) 70 | - [Vue教程] (https://cn.vuejs.org/) 71 | - [Framework7](https://framework7.io/) -------------------------------------------------------------------------------- /_posts/zh_CN/react/2016-01-02-keys-in-children-components-are-important.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 子容器的Key是很重要的 5 | tip-number: 02 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: key是必须传递给从数组中动态创建的所有组件的一个值。它是一个唯一且固定的id,用来识别DOM中的每个组件,也可以让我们区别它是否是同一个组件。使用key可以确保子容器是可保存而且不需要重复创建的,还可以防止奇怪的事情发生。 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_cn/keys-in-children-components-are-important/ 13 | 14 | categories: 15 | - zh_CN 16 | - react 17 | --- 18 | 19 | [key](https://facebook.github.io/react/docs/multiple-components.html#dynamic-children)必须传递给从数组中动态创建的所有组件的一个值。它是一个唯一且固定的id,用来识别DOM中的每个组件,也可以让我们区别它是否是同一个组件。使用key可以确保子容器是可保存而且不需要重复创建的,还可以防止奇怪的事情发生。 20 | 21 | > key跟效率不是很相关,它更与身份有关系(这间接的使效率更好)。随机的赋值或改变值将不能识别身份[Paul O’Shannessy](https://github.com/facebook/react/issues/1342#issuecomment-39230939) 22 | 23 | - 使用对象存在的的唯一值。 24 | - 在父组件定义key,而不是子组件。 25 | 26 | ```javascript 27 | //bad 28 | ... 29 | render() { 30 |
    {% raw %}{{item.name}}{% endraw %}
    31 | } 32 | ... 33 | 34 | //good 35 | 36 | ``` 37 | 38 | - [使用数组索引是一个坏习惯](https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318#.76co046o9) 39 | - `random()` 不会起作用 40 | 41 | ```javascript 42 | //bad 43 | 44 | ``` 45 | 46 | - 你可以创建以自己的唯一id。确定这个方法运行速度够快,把它附着到你的对象上。 47 | - 当子组件的数量很大或者包含重量级的组件时,使用key来提高性能。 48 | - [你必须提供key值给ReactCSSTransitionGroup的每个子组件](http://docs.reactjs-china.com/react/docs/animation.html) -------------------------------------------------------------------------------- /_posts/zh_TW/angular/2016-01-01-angularjs-digest-vs-apply.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: AngularJs - $digest vs $apply 5 | tip-number: 01 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: JavaScript 模組以及建構步驟變得更多更複雜,但對於新的框架樣板呢? 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_tw/angularjs-digest-vs-apply/ 13 | 14 | categories: 15 | - zh_TW 16 | - angular 17 | --- 18 | 19 | AngularJs 最令人欣賞的特性之一是雙向資料綁定。AngularJS 透過循環方式(`$digest`)來檢查模型和視圖變化來實現這個功能。想要理解框架底層的工作方式,你必須了解這個概念。 20 | 21 | 當一個事件被觸發時,Angular 會檢查每個 watcher 變化,這是我們所知的 `$digest` 循環。 22 | 有時候你需要強迫手動執行一個新的循環,你必須選擇正確的選項,因為這個階段是最影響效能之一。 23 | 24 | ### `$apply` 25 | 這個核心方法可以讓你明確地啟動 `$digest` 循環。意思說所有的 watchers 都會被確認;整個應用程式啟動 `$digest loop`。在內部,執行一個可選的功能參數,它會呼叫 `$rootScope.$digest();`。 26 | 27 | ### `$digest` 28 | 在這個情況下,`$digest` 方法在目前的 scope 和子 scope 啟動 `$digeset` 循環。你應該注意到父 scope 不會被檢查,也不會受影響。 29 | 30 | ### 建議 31 | - 當瀏覽器 DOM 事件觸發外部的 AngularJS 使用 `$apply` 或 `$digest`。 32 | - 傳送一個函式表達式給 `$apply`,這裡有一個錯誤處理機制,並且允許整合所有在 `$digest` 循環的變化。 33 | 34 | ```javascript 35 | $scope.$apply(() => { 36 | $scope.tip = 'Javascript Tip'; 37 | }); 38 | ``` 39 | 40 | - 如果你只要更新目前的 scope 和子 scope,使用 `$digest` 防止在整個應用程式執行新的 digest 循環。這在性能上的好處是相當明顯的。 41 | - `$apply()` 對電腦來說是一個相當複雜的處理程序,如果過多的 binding 會造成性能上的問題。 42 | - 如果你使用 >AngularJS 1.2.X,使用 `$evalAsync`,這是一個核心方法,可以在目前的循環或下一個循環執行表達式,可以增加你的應用程式效能。 43 | -------------------------------------------------------------------------------- /_posts/zh_TW/angular/2017-03-07-preventing-unwanted-scopes-creation-in-angularjs.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 在 AngularJs 防止不必要的 scope 建立 5 | tip-number: 62 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: 在這個 tip 我會示範如何在 scope 之件傳送資料,防止 `ng-repeat` 和 `ng-if` 建立不必要的 scope 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | categories: 12 | - zh_TW 13 | - angular 14 | --- 15 | 16 | AngularJs 最受歡迎的特性之一是理解和防止 ```ng-model``` 資料的 scope,這會是你經常遇到的主要挑戰之一。 17 | 在處理 ```ng-model``` 資料時,新的不必要的 scope 透過 ```ng-repeat``` 或 ```ng-if``` 程序被建立。 18 | 看看下面的例子: 19 | 20 | 21 | ```js 22 |
    23 | 24 |
    25 |
    26 | innerScope:{{data}} 27 |
    28 | outerScope:{{data}} 29 |
    30 | ``` 31 | 32 | 在上面的範例中,```innerScope``` 繼承了 ```outerScope``` 並傳送值到 ```outerScope```。 33 | 如果你輸入一個值到 ```innerScope``` 它將反映在 ```outerScope```。但是如果你編輯 ```outerScope```, 34 | ```innerScope``` 並不會反映與 ```outerScope``` 相同的值,因為 ```innerScope``` 建立了它本身的作用域,所以不再繼承自 ```outerScope```。 35 | 36 | 為了防止發生這件事,我們可以使用「Controller As」方式而不是使用 scope 作為一個 container 給所有資料和 function。但是一個更吸引人的解決方法是保持所有事物在 object,如下面範例: 37 | 38 | 39 | ```js 40 |
    41 | 42 |
    43 |
    44 | inner scope:{{data.text}} 45 |
    46 | outer scope:{{data.text}} 47 |
    48 | ``` 49 | 50 | 現在 ```innerScope``` 不再建立一個新的作用域,在 ```innerScope``` 或 ```outerScope``` 編輯數值將會反映到 ```innerScope``` 和 ```outerScope```。 51 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-05-differences-between-undefined-and-null.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: undefined 和 null 的差別 5 | tip-number: 05 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: 了解 `undefined` 和 `null` 的差別。 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_tw/differences-between-undefined-and-null/ 13 | 14 | categories: 15 | - zh_TW 16 | - javascript 17 | --- 18 | 19 | - `undefined` 意思是變數沒有被宣告,或者是已經宣告了,但是沒有賦值。 20 | - `null` 意思是「沒有值」的值。 21 | - Javascript 將未賦值的變數的預設值設為 `undefined`。 22 | - Javascript 從來不會將值設定為 `null`。這是讓開發者用來宣告 `var` 是沒有值的。 23 | - `undefined` 不是一個有效的 JSON,而 `null` 是有效的。 24 | - `undefined` 的類型(typeof) 是 `undefined`。 25 | - `null` 的類型(typeof)是一個 `object`。[為什麼?](http://www.2ality.com/2013/10/typeof-null.html) 26 | - 它們都是原始(primitives)型別。 27 | - 它們都是 [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) 28 | (`Boolean(undefined) // false`, `Boolean(null) // false`)。 29 | - 你可以判斷一個變數是否為 [undefined](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined)。 30 | 31 | ```javascript 32 | typeof variable === "undefined" 33 | ``` 34 | - 你可以判斷一個變數是否為 [null](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null)。 35 | 36 | ```javascript 37 | variable === null 38 | ``` 39 | - **雙等號**運算符認為它們是相等的,但是**三等號**比較時是不相等的。 40 | 41 | ```javascript 42 | null == undefined // true 43 | 44 | null === undefined // false 45 | ``` 46 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-06-writing-a-single-method-for-arrays-and-a-single-element.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 撰寫一個可以接受單一參數和陣列的方法 5 | tip-number: 06 6 | tip-username: mattfxyz 7 | tip-username-profile: https://twitter.com/mattfxyz 8 | tip-tldr: 你撰寫的函式要可以處理陣列或單一元素參數,而不是透過分開的方法來處理陣列和單一元素參數。這和 jQuery 一些函式工作原理相似(`css` 將會修改所有和 selector matched 的)。 9 | 10 | redirect_from: 11 | - /zh_tw/writing-a-single-method-for-arrays-and-a-single-element/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 你撰寫的函式要可以處理陣列或單一元素參數,而不是透過分開的方法來處理陣列和單一元素參數。這和 jQuery 一些函式工作原理相似(`css` 將會修改所有和 selector matched 的)。 19 | 20 | 首先,你只要將任何的東西 concat 到陣列上。`Array.concat` 將會接受陣列或是單一元素。 21 | 22 | ```javascript 23 | function printUpperCase(words) { 24 | var elements = [].concat(words || []); 25 | for (var i = 0; i < elements.length; i++) { 26 | console.log(elements[i].toUpperCase()); 27 | } 28 | } 29 | ``` 30 | 31 | `printUpperCase` 現在已經可以接收單一的 node 或是一個陣列 nodes 當作它的參數了。如果沒有傳送參數,它可以避免拋出潛在的 `TypeError`。 32 | 33 | ```javascript 34 | printUpperCase("cactus"); 35 | // => CACTUS 36 | printUpperCase(["cactus", "bear", "potato"]); 37 | // => CACTUS 38 | // BEAR 39 | // POTATO 40 | ``` 41 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-07-use-strict-and-get-lazy.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 在 JavaScript 使用嚴格模式 5 | tip-number: 07 6 | tip-username: nainslie 7 | tip-username-profile: https://twitter.com/nat5an 8 | tip-tldr: JavaScript 嚴格模式讓開發者可以寫出更「安全」的 JavaScript 程式碼。 9 | 10 | redirect_from: 11 | - /zh_tw/use-strict-and-get-lazy/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | JavaScript 嚴格模式讓開發者可以寫出更「安全」的 JavaScript 程式碼。 19 | 20 | 預設情況下,JavaScript 允許開發者的粗心行為,例如,當我們引用一個沒有要求我們由「var」宣告的變數。或許這個對於一個剛入門的開發者相當方便,當變數名稱拼寫錯誤或者是不小心參考到其他的 scope,這些都是許多錯誤的來源。 21 | 22 | 開發者喜歡讓電腦幫我們做一些無聊的工作,然後自動幫我們確認工作上的錯誤。這就是 JavaScript 的 「嚴格模式」(use strict)幫我們做的,將錯誤轉換成 JavaScript 錯誤。 23 | 24 | 我們把這個指令放在 js 檔案的頂端: 25 | 26 | ```javascript 27 | // 整個 script 使用嚴格模式 28 | "use strict"; 29 | var v = "Hi! I'm a strict mode script!"; 30 | ``` 31 | 32 | 或是在函式內: 33 | 34 | ```javascript 35 | function f() 36 | { 37 | // 函式內使用嚴格模式 38 | 'use strict'; 39 | function nested() { return "And so am I!"; } 40 | return "Hi! I'm a strict mode function! " + nested(); 41 | } 42 | function f2() { return "I'm not strict."; } 43 | ``` 44 | 45 | 透過 JavaScript 檔案或函式內引入這個指令,我們直接讓 JavaScript 引擎執行嚴格模式來禁止一些在大型 JavaScript 專案不良的行為。除了其他之外,嚴格模式改變了以下的行為: 46 | 47 | * 只有被宣告的「var」變數才可以被引用。 48 | * 嘗試寫入唯讀的變數會造成錯誤。 49 | * 你只能透過「new」keyword 才可以呼叫建構子。 50 | * 「this」不再隱式的綁定到全域的物件。 51 | * 對 eval() 有嚴格的限制。 52 | * 防止你使用保留字元或特殊字元當作變數名稱。 53 | 54 | 嚴格模式對於你的新專案是很棒的,但是對於引入一些大部分沒有使用舊的專案是一個挑戰。如果你將 js 檔案編譯在一起到你的大項目的話,可能會造成所有的檔案都執行在嚴格模式下,造成一些問題。 55 | 56 | 它不是一個語法,但它是一個文字上的表達,在早期版本的 JavaScript 被忽略了。 57 | 嚴格模式支援以下: 58 | 59 | * Internet Explorer from version 10. 60 | * Firefox from version 4. 61 | * Chrome from version 13. 62 | * Safari from version 5.1. 63 | * Opera from version 12. 64 | 65 | [嚴格模式的詳細說明,請參考 MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode)。 66 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-08-converting-a-node-list-to-an-array.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 將 Node List 轉換成陣列 5 | tip-number: 08 6 | tip-username: Tevko 7 | tip-username-profile: https://twitter.com/tevko 8 | tip-tldr: 這是快速,安全,可重複使用的方式,將 Node List 轉換成 DOM 元素的陣列。 9 | 10 | redirect_from: 11 | - /zh_tw/converting-a-node-list-to-an-array/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | `querySelectorAll` 方法回傳一個類似陣列的物件稱為 Node List。這些資料結構簡稱為「類陣列」,因為他們和陣列很相似,但是不能使用陣列的方法像是 `map` 和 `forEach`。這是快速,安全,可重複使用的方式,將 Node List 轉換成 DOM 元素的陣列: 19 | 20 | ```javascript 21 | const nodelist = document.querySelectorAll('div'); 22 | const nodelistToArray = Array.apply(null, nodelist); 23 | 24 | // 之後 .. 25 | 26 | nodelistToArray.forEach(...); 27 | nodelistToArray.map(...); 28 | nodelistToArray.slice(...); 29 | 30 | // 等等... 31 | ``` 32 | 33 | `apply` 方法將參數陣列傳送給一個函式與給定 this 的值。根據 [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) ,`apply` 採用類陣列物件,而這剛好就是 `querySelectorAll` 方法所回傳的內容。如果我們不需要在函式的上下文(context)中指定 `this` ,我們可以傳送 `null` 或 `0`。這個結果實際上是一個 DOM 元素陣列,包含所有可用的陣列方法。 34 | 35 | 或者,假設你使用 ES2015 你可以使用[展開運算符 `...`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator)。 36 | 37 | ```js 38 | const nodelist = [...document.querySelectorAll('div')]; // 回傳一個實際的陣列 39 | 40 | // 之後 .. 41 | 42 | nodelist.forEach(...); 43 | nodelist.map(...); 44 | nodelist.slice(...); 45 | 46 | // 等等... 47 | ``` 48 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-09-template-strings.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 模板字串 5 | tip-number: 09 6 | tip-username: JakeRawr 7 | tip-username-profile: https://github.com/JakeRawr 8 | tip-tldr: 由於 ES6 中有了模板字串,JavaScript 可以使用模板字串來替代原本我們使用的引號字元。 9 | 10 | redirect_from: 11 | - /zh_tw/template-strings/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 由於 ES6 中有了模板字串,JavaScript 可以使用模板字串來替代原本我們使用的引號字元。 19 | 20 | Ex: 21 | 正常的字串 22 | 23 | ```javascript 24 | var firstName = 'Jake'; 25 | var lastName = 'Rawr'; 26 | console.log('My name is ' + firstName + ' ' + lastName); 27 | // My name is Jake Rawr 28 | ``` 29 | 模板字串 30 | 31 | ```javascript 32 | var firstName = 'Jake'; 33 | var lastName = 'Rawr'; 34 | console.log(`My name is ${firstName} ${lastName}`); 35 | // My name is Jake Rawr 36 | ``` 37 | 38 | 在模板字串中,你不需要透過 `\n` 來產生多行的字串,只要簡單透過 `${}` 來替代就可以了,還可以計算簡單的邏輯,例如:`${2 + 3}`。 39 | 你也可以使用函式來修改你的輸出的內容;例如使用標籤模板字串,它們被稱為[標籤模板字串](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings#Tagged_template_strings)。 40 | 41 | 你或許想要[閱讀](https://hacks.mozilla.org/2015/05/es6-in-depth-template-strings-2)和了解更多關於模板字串。 42 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-10-check-if-a-property-is-in-a-object.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 檢查屬性是否存在物件內 5 | tip-number: 10 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: 這些方法都是檢查屬性是否存在目前的物件內。 9 | 10 | redirect_from: 11 | - /zh_tw/check-if-a-property-is-in-a-object/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 當你檢查屬性是否存在目前的[物件](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects)內,你或許可以這麼做: 19 | 20 | ```javascript 21 | var myObject = { 22 | name: '@tips_js' 23 | }; 24 | 25 | if (myObject.name) { ... } 26 | 27 | ``` 28 | 29 | 以上的方法是沒問題的,但是你必須知道對於這個問題有兩個原生的方法,[`in` 運算符](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in)和 [`Object.hasOwnProperty`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty)。任何繼承 `Object` 的都可以使用這兩種方法。 30 | 31 | ### 觀察之間較大的差別 32 | 33 | ```javascript 34 | var myObject = { 35 | name: '@tips_js' 36 | }; 37 | 38 | myObject.hasOwnProperty('name'); // true 39 | 'name' in myObject; // true 40 | 41 | myObject.hasOwnProperty('valueOf'); // false, valueOf 繼承自原型鏈結 42 | 'valueOf' in myObject; // true 43 | 44 | ``` 45 | 46 | 兩者不同的地方在於確認的屬性深度不同。換句話說,如果直接在物件內確認 key 是可用的話,`hasOwnProperty` 只會回傳 true。然而,在 `in` 運算符沒辦法分辨之間的屬性是建立在物件或是繼承自原型鏈結的。 47 | 48 | 這裡有其他的範例: 49 | 50 | ```javascript 51 | var myFunc = function() { 52 | this.name = '@tips_js'; 53 | }; 54 | myFunc.prototype.age = '10 days'; 55 | 56 | var user = new myFunc(); 57 | 58 | user.hasOwnProperty('name'); // true 59 | user.hasOwnProperty('age'); // false, 因為 age 是繼承自原型鏈結 60 | ``` 61 | 62 | 在[線上範例](https://jsbin.com/tecoqa/edit?js,console)確認吧! 63 | 確認屬性是否存在在物件內的問題常見錯誤,我推薦閱讀關於這個問題的[討論](https://github.com/loverajoel/jstips/issues/62)。 64 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-11-hoisting.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 提升變數 5 | tip-number: 11 6 | tip-username: squizzleflip 7 | tip-username-profile: https://twitter.com/squizzleflip 8 | tip-tldr: 了解 hoisting 可以幫助你組織你的函式 scope。 9 | 10 | redirect_from: 11 | - /zh_tw/hoisting/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 了解 [hoisting](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting) 將會幫助你編寫函式 scope。只要記得,變數宣告和函式定義都會被提升到頂端。變數定義則不會,即使你宣告和定義一個變數再同一行。變數**宣告**是讓系統知道變數的存在,而**定義**只是分配給它一個值。 19 | 20 | ```javascript 21 | function doTheThing() { 22 | // ReferenceError: notDeclared 沒有被定義 23 | console.log(notDeclared); 24 | 25 | // 輸出:undefine 26 | console.log(definedLater); 27 | var definedLater; 28 | 29 | definedLater = 'I am defined!' 30 | // 輸出:'I am defined!' 31 | console.log(definedLater) 32 | 33 | // 輸出:undefined 34 | console.log(definedSimulateneously); 35 | var definedSimulateneously = 'I am defined!' 36 | // 輸出:'I am defined!' 37 | console.log(definedSimulateneously) 38 | 39 | // 輸出:'I did it!' 40 | doSomethingElse(); 41 | 42 | function doSomethingElse(){ 43 | console.log('I did it!'); 44 | } 45 | 46 | // TypeError: undefined 不是一個函式 47 | functionVar(); 48 | 49 | var functionVar = function(){ 50 | console.log('I did it!'); 51 | } 52 | } 53 | ``` 54 | 55 | 為了讓你的程式碼更容易閱讀,將你所有的變數宣告在你的函式 scope 頂端,這樣可以更清楚知道變數是來自哪個 scope。在你使用變數之前請先定義。在你的 scope 底部定義函式,來保持它們的方式。 56 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-12-pseudomandatory-parameters-in-es6-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 在 ES6 函式內的預設參數 5 | tip-number: 12 6 | tip-username: Avraam Mavridis 7 | tip-username-profile: https://github.com/AvraamMavridis 8 | tip-tldr: 在許多程式設計語言函數的參數預設是強制需要的,而開發者也會明確定義一個可選的參數。 9 | 10 | redirect_from: 11 | - /zh_tw/pseudomandatory-parameters-in-es6-functions/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 在許多程式設計語言函數的參數預設值是強制需要的,而開發者也會明確定義一個可選的參數。在 JavaScript 中,每個參數都是可選的,利用 [**es6 參數預設值**](http://exploringjs.com/es6/ch_parameter-handling.html#sec_parameter-default-values)的特性,我們可以強制執行這個行為,而不會弄亂函數的主體。 19 | 20 | ```javascript 21 | const _err = function( message ){ 22 | throw new Error( message ); 23 | } 24 | 25 | const getSum = (a = _err('a is not defined'), b = _err('b is not defined')) => a + b 26 | 27 | getSum( 10 ) // 拋出錯誤,b 沒有被定義 28 | getSum( undefined, 10 ) // 拋出錯誤,a 沒有被定義 29 | ``` 30 | 31 | `_err` 是一個函式可以立即拋出錯誤。如果沒有傳送其中一個參數,函數預設值就會被使用,`_err` 將會被呼叫而且會拋出錯誤。你可以在 [Mozilla's Developer Network ](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/default_parameters) 看更多關於 **預設參數值特性** 的範例。 32 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-13-tip-to-measure-performance-of-a-javascript-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 測量 JavaScript 程式碼區塊性能的 tip 5 | tip-number: 13 6 | tip-username: manmadareddy 7 | tip-username-profile: https://twitter.com/manmadareddy 8 | tip-tldr: 如果要快速的測量 JavaScript 程式碼區塊性能的話,我們可以使用 console 函式像是 `console.time(label)` 和 `console.timeEnd(label)`。 9 | 10 | redirect_from: 11 | - /zh_tw/tip-to-measure-performance-of-a-javascript-block/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 如果要快速的測量 JavaScript 程式碼區塊性能的話,我們可以使用 console 函式像是 19 | [`console.time(label)`](https://developer.chrome.com/devtools/docs/console-api#consoletimelabel) 和 [`console.timeEnd(label)`](https://developer.chrome.com/devtools/docs/console-api#consoletimeendlabel)。 20 | 21 | ```javascript 22 | console.time("Array initialize"); 23 | var arr = new Array(100), 24 | len = arr.length, 25 | i; 26 | 27 | for (i = 0; i < len; i++) { 28 | arr[i] = new Object(); 29 | }; 30 | console.timeEnd("Array initialize"); // 輸出:陣列初始化:0.711ms 31 | ``` 32 | 33 | 更多資訊: 34 | [Console object](https://github.com/DeveloperToolsWG/console-object)、 35 | [Javascript benchmarking](https://mathiasbynens.be/notes/javascript-benchmarking)。 36 | 37 | 範例:[jsfiddle](https://jsfiddle.net/meottb62/) - [codepen](http://codepen.io/anon/pen/JGJPoa)(在瀏覽器 console 下輸出)。 38 | 39 | > 注意:根據 [Mozilla](https://developer.mozilla.org/en-US/docs/Web/API/Console/time) 建議,不該使用在上線環境下使用此方法,只能使用在開發環境。 40 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-16-passing-arguments-to-callback-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 將參數傳送到 callback 函式 5 | tip-number: 16 6 | tip-username: minhazav 7 | tip-username-profile: https://twitter.com/minhazav 8 | tip-tldr: 預設情況下,你不能傳送參數給 callback 函式,但是你可以利用 JavaScrip closure scope 的優點將參數傳給 callback 函式。 9 | 10 | redirect_from: 11 | - /zh_tw/passing-arguments-to-callback-functions/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 預設情況下,你不能傳送參數給 callback 函式。例如: 19 | 20 | ```js 21 | function callback() { 22 | console.log('Hi human'); 23 | } 24 | 25 | document.getElementById('someelem').addEventListener('click', callback); 26 | 27 | ``` 28 | 29 | 你可以利用 JavaScript 閉包(closure)scope 的優點傳送參數給 callback 函式。看一下這個範例: 30 | 31 | ```js 32 | function callback(a, b) { 33 | return function() { 34 | console.log('sum = ', (a+b)); 35 | } 36 | } 37 | 38 | var x = 1, y = 2; 39 | document.getElementById('someelem').addEventListener('click', callback(x, y)); 40 | 41 | ``` 42 | 43 | ### 什麼是閉包(closure)? 44 | 45 | Closures 指的是一個獨立的變數函式。換句話說,在閉包中定義的函式「記得」它被建立時的環境。在 [MDN 文件](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures)了解更多。 46 | 47 | 當 callback 函式被呼叫時,這些方法的參數 `x` 和 `y` 都會在 callback 函式的範圍內。 48 | 49 | 另一個方法你可以使用 `bind`。例如: 50 | 51 | ```js 52 | var alertText = function(text) { 53 | alert(text); 54 | }; 55 | 56 | document.getElementById('someelem').addEventListener('click', alertText.bind(this, 'hello')); 57 | ``` 58 | 兩種方法上有細微的性能上的差別,請參考 [jsperf](http://jsperf.com/bind-vs-closure-23)。 59 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-17-nodejs-run-a-module-if-it-is-not-required.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Node.js - 執行尚未被 required 的模組 5 | tip-number: 17 6 | tip-username: odsdq 7 | tip-username-profile: https://twitter.com/odsdq 8 | tip-tldr: 在 nodejs,你可以讓你的程式取決於 `require('./something.js')` 或 `node something.js` 這兩種不同的方式來執行你的程式碼。如果你想要將你的獨立模組交互使用是非常有用的。 9 | 10 | redirect_from: 11 | - /zh_tw/nodejs-run-a-module-if-it-is-not-required/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 在 nodejs,你可以讓你的程式取決於 `require('./something.js')` 或 `node something.js` 這兩種不同的方式來執行你的程式碼。如果你想要將你的獨立模組交互使用是非常有用的。 19 | 20 | ```js 21 | if (!module.parent) { 22 | // 透過 `node something.js` 執行 23 | app.listen(8088, function() { 24 | console.log('app listening on port 8088'); 25 | }) 26 | } else { 27 | // 使用 `require('/.something.js')` 方法 28 | module.exports = app; 29 | } 30 | ``` 31 | 32 | 更多資訊請參考 [nodejs modules 官方文件](https://nodejs.org/api/modules.html#modules_module_parent)。 33 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-19-safe-string-concatenation.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 安全的使用字串串接 5 | tip-number: 19 6 | tip-username: gogainda 7 | tip-username-profile: https://twitter.com/gogainda 8 | tip-tldr: 假設你有一些不確定的變數類型,而你想將它們串接成字串。可以確定的是,算術運算不是應用在串接的地方,使用 concat 來串接。 9 | 10 | redirect_from: 11 | - /zh_tw/safe-string-concatenation/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 假設你有一些不確定的變數類型,而你想將它們串接成字串。可以肯定的是,算術運算符不是在串接過程的運用,請使用 `concat`: 19 | 20 | ```javascript 21 | var one = 1; 22 | var two = 2; 23 | var three = '3'; 24 | 25 | var result = ''.concat(one, two, three); // "123" 26 | ``` 27 | 28 | 這個方法串接結果是你預期的。相反的,透過加號來串接會造成非預期的結果: 29 | 30 | ```javascript 31 | var one = 1; 32 | var two = 2; 33 | var three = '3'; 34 | 35 | var result = one + two + three; // "33" 而不是 "123" 36 | ``` 37 | 38 | 關於性能部分,與 `join` [類型](http://www.sitepoint.com/javascript-fast-string-concatenation/)比較,串接速度和 `concat` 是差不多的。 39 | 40 | 你可以在 MDN [網頁](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/concat)上閱讀到更多關於 `concat` 函式的資訊。 41 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-20-return-objects-to-enable-chaining-of-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 回傳物件並使用函式鏈結 5 | tip-number: 20 6 | tip-username: WakeskaterX 7 | tip-username-profile: https://twitter.com/WakeStudio 8 | tip-tldr: 在 JavaScript 物件導向中,我們在物件上建立函式,函式回傳的物件讓你可以將函式鏈結在一起。 9 | 10 | redirect_from: 11 | - /zh_tw/return-objects-to-enable-chaining-of-functions/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 在 JavaScript 物件導向中,我們在物件上建立函式,函式回傳的物件讓你可以將函式鏈結在一起。 19 | 20 | ```js 21 | function Person(name) { 22 | this.name = name; 23 | 24 | this.sayName = function() { 25 | console.log("Hello my name is: ", this.name); 26 | return this; 27 | }; 28 | 29 | this.changeName = function(name) { 30 | this.name = name; 31 | return this; 32 | }; 33 | } 34 | 35 | var person = new Person("John"); 36 | person.sayName().changeName("Timmy").sayName(); 37 | ``` 38 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-21-shuffle-an-array.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 將陣列洗牌 5 | tip-number: 21 6 | tip-username: 0xmtn 7 | tip-username-profile: https://github.com/0xmtn/ 8 | tip-tldr: Fisher-Yates Shuffling 是一個將陣列洗牌的演算法。 9 | 10 | redirect_from: 11 | - /zh_tw/shuffle-an-array/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 這段程式碼使用了 [Fisher-Yates Shuffling](https://www.wikiwand.com/en/Fisher%E2%80%93Yates_shuffle) 演算法將給定的陣列洗牌。 19 | 20 | ```javascript 21 | function shuffle(arr) { 22 | var i, 23 | j, 24 | temp; 25 | for (i = arr.length - 1; i > 0; i--) { 26 | j = Math.floor(Math.random() * (i + 1)); 27 | temp = arr[i]; 28 | arr[i] = arr[j]; 29 | arr[j] = temp; 30 | } 31 | return arr; 32 | }; 33 | ``` 34 | 範例: 35 | 36 | ```javascript 37 | var a = [1, 2, 3, 4, 5, 6, 7, 8]; 38 | var b = shuffle(a); 39 | console.log(b); 40 | // [2, 7, 8, 6, 5, 3, 1, 4] 41 | ``` 42 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-22-two-ways-to-empty-an-array.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 將陣列清空的兩種方法 5 | tip-number: 22 6 | tip-username: microlv 7 | tip-username-profile: https://github.com/microlv 8 | tip-tldr: 在 JavaScript 中當你相要清空陣列,有許多方法,但這是最具效能的方法。 9 | 10 | redirect_from: 11 | - /zh_tw/two-ways-to-empty-an-array/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 你定義了一個陣列然後你想清空陣列內的內容。 19 | 通常你會這麼做: 20 | 21 | ```javascript 22 | // 定義陣列 23 | var list = [1, 2, 3, 4]; 24 | function empty() { 25 | // 清空陣列 26 | list = []; 27 | } 28 | empty(); 29 | ``` 30 | 但是這裡有另一個更能具效能的清空陣列的方式。 31 | 32 | 你應該像這樣使用程式碼: 33 | 34 | ```javascript 35 | var list = [1, 2, 3, 4]; 36 | function empty() { 37 | // 清空陣列 38 | list.length = 0; 39 | } 40 | empty(); 41 | ``` 42 | 43 | * `list = []` 將分配一個新的參考陣列給變數,而其他的參考則不受影響。 44 | 這個意思是說,前面參考的陣列內容還存在記憶體中,導致記憶體洩漏。 45 | 46 | * `list.length = 0` 刪除陣列內所有的內容,也會影響到其他的參考。 47 | 48 | 換句話說,假設你有兩個變數且參考到同一個陣列(`a = [1,2,3]; a2 = a;`),而你使用 `list.length = 0` 刪除陣列的內容,兩個參考(a 和 a2)將指向相同的空陣列。(如果你不想讓 a2 內容變成空的陣列,請不要使用這個方法!) 49 | 50 | 思考一下這些會輸出什麼: 51 | 52 | ```js 53 | var foo = [1,2,3]; 54 | var bar = [1,2,3]; 55 | var foo2 = foo; 56 | var bar2 = bar; 57 | foo = []; 58 | bar.length = 0; 59 | console.log(foo, bar, foo2, bar2); 60 | 61 | // [] [] [1, 2, 3] [] 62 | ``` 63 | 64 | 在 Stackoverflow 了解更多的細節: 65 | [difference-between-array-length-0-and-array](http://stackoverflow.com/questions/4804235/difference-between-array-length-0-and-array) 66 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-23-converting-to-number-fast-way.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 轉換為數字更快的方式 5 | tip-number: 23 6 | tip-username: sonnyt 7 | tip-username-profile: http://twitter.com/sonnyt 8 | tip-tldr: 轉換字串為數字是相當常見的。最簡單和快速的方式是使用 + 運算子來實現。 9 | 10 | redirect_from: 11 | - /zh_tw/converting-to-number-fast-way/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 轉換字串為數字是相當常見的。最簡單和快速的方式是使用 `+` (加號)運算子來實現。([jsPerf](https://jsperf.com/number-vs-parseint-vs-plus/29)) 19 | 20 | ```javascript 21 | var one = '1'; 22 | 23 | var numberOne = +one; // Number 1 24 | ``` 25 | 26 | 你也可以使用 `-` (減號)運算子將數字類型轉換成負數。 27 | 28 | ```javascript 29 | var one = '1'; 30 | 31 | var negativeNumberOne = -one; // Number -1 32 | ``` 33 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-24-use_===_instead_of_==.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 使用 === 來替代 == 5 | tip-number: 24 6 | tip-username: bhaskarmelkani 7 | tip-username-profile: https://www.twitter.com/bhaskarmelkani 8 | tip-tldr: ==(或 !=)運算子如果在執行上需要的話,會自動將類型轉換。 `===`(或 `!==`)運算子則不會執行轉換。`===`(或 `!==`)用來比較數值和類型,相較於 `==` 更來的快速。 9 | 10 | redirect_from: 11 | - /zh_tw/use_===_instead_of_==/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | `==`(或 `!=`)運算子如果在執行上需要的話,會自動將類型轉換。 `===`(或 `!==`)運算子則不會執行轉換。`===`(或 `!==`)用來比較數值和類型,相較於 `==` 更來的快速。([jsPref](http://jsperf.com/strictcompare)) 19 | 20 | ```js 21 | [10] == 10 // is true 22 | [10] === 10 // is false 23 | 24 | '10' == 10 // is true 25 | '10' === 10 // is false 26 | 27 | [] == 0 // is true 28 | [] === 0 // is false 29 | 30 | '' == false // is true but true == "a" is false 31 | '' === false // is false 32 | 33 | ``` 34 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-25-Using-immediately-invoked-function-expression.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 使用立即函式表達式 5 | tip-number: 25 6 | tip-username: rishantagarwal 7 | tip-username-profile: https://github.com/rishantagarwal 8 | tip-tldr: 稱作「Iffy」(IIFE - immediately invoked function expression)是一個匿名函式表達式,而且可以立即被調用,在 JavaScript 中有一些相當重要的用途。 9 | 10 | 11 | redirect_from: 12 | - /zh_tw/Using-immediately-invoked-function-expression/ 13 | 14 | categories: 15 | - zh_TW 16 | - javascript 17 | --- 18 | 19 | 稱作「Iffy」(IIFE - immediately invoked function expression)是一個匿名函式表達式,而且可以立即被調用,在 JavaScript 中有一些相當重要的用途。 20 | 21 | ```javascript 22 | 23 | (function() { 24 | // Do something​ 25 | } 26 | )() 27 | 28 | ``` 29 | 30 | 它是一個匿名函式表達式,而且可以立即被調用,在 JavaScript 某些部分中相當重要。 31 | 32 | 一對括號包著匿名函式,將匿名函式變成函式表達式或變數表達式。我們現在有一個未命名的函式表達式,它不是一個在全域 scope 內的簡單匿名函式或者是其他任何被定義的函式。 33 | 34 | 同樣的,我們也可以為立即函式表達式命名: 35 | 36 | ```javascript 37 | (someNamedFunction = function(msg) { 38 | console.log(msg || "Nothing for today !!") 39 | })(); // 輸出 --> Nothing for today !!​ 40 | ​ 41 | someNamedFunction("Javascript rocks !!"); // 輸出 --> Javascript rocks !! 42 | someNamedFunction(); // 輸出 --> Nothing for today !!​ 43 | ``` 44 | 45 | 更多細節,請參考以下網址 - 46 | 1. [連結一](https://blog.mariusschulz.com/2016/01/13/disassembling-javascripts-iife-syntax) 47 | 2. [連結二](http://javascriptissexy.com/12-simple-yet-powerful-javascript-tips/) 48 | 49 | 效能: 50 | [jsPerf](http://jsperf.com/iife-with-call) 51 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-27-short-circiut-evaluation-in-js.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: JavaScript 中的捷徑計算 5 | tip-number: 27 6 | tip-username: bhaskarmelkani 7 | tip-username-profile: https://www.twitter.com/bhaskarmelkani 8 | tip-tldr: 捷徑計算意思是說,假設第一個參數不足以確定表達式的值,第二個參數才會被執行,當 AND 函數的第一個參數計算結果為 false,則所有結果則為 false;當 OR 函數的第一個參數計算結果為 true,則所有結果為 true。 9 | 10 | redirect_from: 11 | - /zh_tw/short-circiut-evaluation-in-js/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | [捷徑計算](https://en.wikipedia.org/wiki/Short-circuit_evaluation)意思是說,假設第一個參數不足以確定表達式的值,第二個參數才會被執行,當 AND 函數的第一個參數計算結果為 false,則所有結果則為 false;當 OR 函數的第一個參數計算結果為 true,則所有結果為 true。 19 | 20 | 對於以下的 `test` 條件和 `isTrue` 以及 `isFalse` 函式。 21 | 22 | ```js 23 | var test = true; 24 | var isTrue = function(){ 25 | console.log('Test is true.'); 26 | }; 27 | var isFalse = function(){ 28 | console.log('Test is false.'); 29 | }; 30 | 31 | ``` 32 | 使用 AND 邏輯 - `&&`。 33 | 34 | ```js 35 | // 一個正常的 if 條件式 36 | if (test){ 37 | isTrue(); // Test 是 true 38 | } 39 | 40 | // 上面可以使用 '&&' 作為 - 41 | 42 | ( test && isTrue() ); // Test 是 true 43 | ``` 44 | 使用 OR 邏輯 - `||`。 45 | 46 | ```js 47 | test = false; 48 | if (!test){ 49 | isFalse(); // Test 是 false. 50 | } 51 | 52 | ( test || isFalse()); // Test 是 false. 53 | ``` 54 | OR 邏輯可以用在為函式參數設定預設值。 55 | 56 | ```js 57 | function theSameOldFoo(name){ 58 | name = name || 'Bar' ; 59 | console.log("My best friend's name is " + name); 60 | } 61 | theSameOldFoo(); // My best friend's name is Bar 62 | theSameOldFoo('Bhaskar'); // My best friend's name is Bhaskar 63 | ``` 64 | 當屬性尚未被定義的時候,邏輯 AND 可以避免異常情況。 65 | 例如: 66 | 67 | ```js 68 | var dog = { 69 | bark: function(){ 70 | console.log('Woof Woof'); 71 | } 72 | }; 73 | 74 | // 呼叫 dog.bark(); 75 | dog.bark(); // Woof Woof. 76 | 77 | // 但是如果 dog 尚未被定義,dog.bark() 將會發生「無法讀取尚未定義的屬性 'bark'」的錯誤。 78 | // 為了防止這個問題,我們使用 &&。 79 | 80 | dog && dog.bark(); // 如果 dog 被定義了,那我們就可以呼叫 dog.bark()。 81 | 82 | ``` 83 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-30-converting-truthy-falsy-values-to-boolean.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 將 truthy 和 falsy 轉換成布林值 5 | tip-number: 30 6 | tip-username: hakhag 7 | tip-username-profile: https://github.com/hakhag 8 | tip-tldr: 邏輯運算子是 JavaScript 核心之一 ,在這裡你可以發現這個方式,不管你給他什麼值,都會得到 true 或 false 。 9 | 10 | 11 | redirect_from: 12 | - /zh_tw/converting-truthy-falsy-values-to-boolean/ 13 | 14 | categories: 15 | - zh_TW 16 | - javascript 17 | --- 18 | 19 | 你可以使用 `!!` 運算子將 [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) 或 [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) 轉換成布林值。 20 | 21 | ```js 22 | !!"" // false 23 | !!0 // false 24 | !!null // false 25 | !!undefined // false 26 | !!NaN // false 27 | 28 | !!"hello" // true 29 | !!1 // true 30 | !!{} // true 31 | !![] // true 32 | ``` 33 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-01-31-avoid-modifying-or-passing-arguments-into-other-functions—it-kills-optimization.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 避免修改或傳送 arguments 到其他函式 - 它會影響優化 5 | tip-number: 31 6 | tip-username: berkana 7 | tip-username-profile: https://github.com/berkana 8 | tip-tldr: 在 JavaScript 的函式,變數名稱 `arguments` 讓你可以存取所有傳送到函式的參數。`arguments` 是一個 *類陣列物件*;`arguments` 可以使用陣列表示來存取,而且它有 *length* 屬性,但不具備陣列的 `filter` 和 `map` 以及 `forEach` 的方法。以下程式碼是轉換 `arguments` 到陣列相當普遍的做法。 9 | 10 | 11 | redirect_from: 12 | - /zh_tw/avoid-modifying-or-passing-arguments-into-other-functions-it-kills-optimization/ 13 | 14 | categories: 15 | - zh_TW 16 | - javascript 17 | --- 18 | 19 | ### 背景 20 | 21 | 在 JavaScript 的函式,變數名稱 [`arguments`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments) 讓你可以存取所有傳送到函式的參數。`arguments` 是一個 *類陣列物件*;`arguments` 可以使用陣列表示來存取,而且它有 *length* 屬性,但不具備陣列的 `filter` 和 `map` 以及 `forEach` 的方法。以下程式碼是轉換 `arguments` 到陣列相當普遍的做法。 22 | 23 | ```js 24 | var args = Array.prototype.slice.call(arguments); 25 | ``` 26 | 將 `arguments` 傳送到 `Array` 原型的上的 `slice` 方法;`slice` 方法回傳淺拷貝的 `arguments` 當作新的陣列物件。一般常見的簡寫方法: 27 | 28 | ```js 29 | var args = [].slice.call(arguments); 30 | ``` 31 | 在這個情況下,只是呼叫一個空陣列陣列,而不是從 `Array` 原型上呼叫 `slice` 方法。 32 | 33 | ### 優化 34 | 35 | 不幸的是,傳送到任何函式呼叫的 `arguments`,造成在 Chrome 和 Node 跳過 JavaScript V8 引擎的優化功能,這可能會導致性能降低。參考這篇 [optimization killers](https://github.com/petkaantonov/bluebird/wiki/Optimization-killers) 文章。傳送 `arguments` 到函式稱為 *leaking `arguments`*。 36 | 37 | 相反的,假設你需要包含參數的陣列,你可以藉助這個方法: 38 | 39 | ```js 40 | var args = new Array(arguments.length); 41 | for(var i = 0; i < args.length; ++i) { 42 | args[i] = arguments[i]; 43 | } 44 | ``` 45 | 46 | 雖然程式碼更冗長,但是在上線環境增進了效能的優化,所以是值得的。 47 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-02-01-map-to-the-rescue-adding-order-to-object-properties.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 透過 Map() 在你的物件屬性加入排序 5 | tip-number: 32 6 | tip-username: loverajoel 7 | tip-username-profile: https://twitter.com/loverajoel 8 | tip-tldr: 物件是一個沒有排序的屬性集合...意思說,如果你想嘗試在你的物件儲存已排序的資料,你需要重新檢查,因為屬性在物件不保證是有排序的。 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_tw/map-to-the-rescue-adding-order-to-object-properties/ 13 | 14 | categories: 15 | - zh_TW 16 | - javascript 17 | --- 18 | 19 | ## 物件屬性的順序 20 | 21 | > 一個物件是一個 `Object` 的類型。它是包含原始值、物件、或是函式這些尚未排序屬性的集合。一個物件的屬性儲存了一個函式稱為方法。 [ECMAScript](http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf) 22 | 23 | 實際看一下範例 24 | 25 | ```js 26 | var myObject = { 27 | z: 1, 28 | '@': 2, 29 | b: 3, 30 | 1: 4, 31 | 5: 5 32 | }; 33 | console.log(myObject) // Object {1: 4, 5: 5, z: 1, @: 2, b: 3} 34 | 35 | for (item in myObject) {... 36 | // 1 37 | // 5 38 | // z 39 | // @ 40 | // b 41 | ``` 42 | 因為每個瀏覽器有自己排序物件的規則,所以順序是不確定的。 43 | 44 | ## 要如何解決這個問題? 45 | 46 | ### Map 47 | 48 | 使用 ES6 的新特性 - Map。[Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) 物件迭代元素插入的順序。`for...of` 迴圈每次迭代回傳一個 [key, value] 的陣列。 49 | 50 | ```js 51 | var myObject = new Map(); 52 | myObject.set('z', 1); 53 | myObject.set('@', 2); 54 | myObject.set('b', 3); 55 | for (var [key, value] of myObject) { 56 | console.log(key, value); 57 | ... 58 | // z 1 59 | // @ 2 60 | // b 3 61 | ``` 62 | 63 | ### 對舊的瀏覽器 Hack 64 | 65 | Mozilla 建議: 66 | > 所以,如果你想要在跨瀏覽器的環境模擬一個有排序的關聯陣列,你要麼強制使用兩個分離的陣列(其中一個給 keys,另一個給 values),或者建立一個單一屬性的物件陣列,等等。 67 | 68 | ```js 69 | // 使用兩個分離的陣列 70 | var objectKeys = [z, @, b, 1, 5]; 71 | for (item in objectKeys) { 72 | myObject[item] 73 | ... 74 | 75 | // 建立一個單一屬性的物件陣列 76 | var myData = [{z: 1}, {'@': 2}, {b: 3}, {1: 4}, {5: 5}]; 77 | ``` 78 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-02-02-create-range-0-n-easily-using-one-line.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 使用一行程式碼建立一個 `[0, 1, ..., N - 1]` 的陣列 5 | tip-number: 33 6 | tip-username: SarjuHansaliya 7 | tip-username-profile: https://github.com/SarjuHansaliya 8 | tip-tldr: 使用一行程式碼,來產生有順序性的陣列。 9 | 10 | 11 | redirect_from: 12 | - /zh_tw/create-range-0-n-easily-using-one-line/ 13 | 14 | categories: 15 | - zh_TW 16 | - javascript 17 | --- 18 | 19 | 這裡有兩種 compact 程式碼序列方式,來產生一個 `[0, 1, ..., N-1]` 的 `N` 個元素的陣列: 20 | 21 | ### 方法一(ES5) 22 | 23 | ```js 24 | Array.apply(null, {length: N}).map(Function.call, Number); 25 | ``` 26 | 27 | #### 簡要說明 28 | 29 | 1. `Array.apply(null, {length: N)` 回傳一個 `N` 個元素的陣列,裡面陣列元素都是為 `undefined`(i.e. `A = [undefined, undefined, ...]`)。 30 | 2. `A.map(Function.call, Number)` 回傳一個 `N` 個元素的陣列,索引 `I` 從 `Function.call.call(Number, undefined, I, A)` 取得結果。 31 | 3. `Function.call.call(Number, undefined, I, A)` 轉變成 `Number(I)`,這剛好就是 `I`。 32 | 4. 結果:`[0, 1, ..., N-1]`。 33 | 34 | 更深入的解釋,請前往[這裡](https://github.com/gromgit/jstips-xe/blob/master/tips/33.md)。 35 | 36 | ### 方法二(ES6) 37 | 38 | ```js 39 | Array.from(new Array(N), (val, index) => index); 40 | ``` 41 | 42 | #### 簡要說明 43 | 44 | 1. `A = new Array(N)` 回傳一個有 `N` 個 _holes_ 的陣列(i.e. `A = [,,,...]`,但是 `x` 在 `0...N-1` 時 `A[x] = undefined`)。 45 | 2. `F = (val, index) => index` 等同於 `function F (val, index) { return index; }`。 46 | 3. `Array.from(A, F)` 回傳一個 `N` 個元素的陣列,索引 `I` 取得 `F(A[I], I)` 的結果,也就是 `I`。 47 | 4. 結果:`[0, 1, ..., N-1]`。 48 | 49 | ### 還有一件事情 50 | 51 | 如果你真的想要排序 [1, 2, ..., N],**方法一**改為: 52 | 53 | ```js 54 | Array.apply(null, {length: N}).map(function(value, index){ 55 | return index + 1; 56 | }); 57 | ``` 58 | 59 | 和 **方法二**: 60 | 61 | ```js 62 | Array.from(new Array(N), (val, index) => index + 1); 63 | ``` 64 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-02-03-implementing-asynchronous-loops.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 實作非同步迴圈 5 | tip-number: 34 6 | tip-username: madmantalking 7 | tip-username-profile: https://github.com/madmantalking 8 | tip-tldr: 你或許可以實作非同步迴圈,但是執行時可能會遇到問題。 9 | 10 | redirect_from: 11 | - /zh_tw/implementing-asynchronous-loops/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 讓我們嘗試撰寫一個非同步的函式,在每秒列印出迴圈的索引值。 19 | 20 | ```js 21 | for (var i = 0; i < 5; i++) { 22 | setTimeout(function(){ 23 | console.log(i); 24 | }, 1000 * (i + 1)); 25 | } 26 | ``` 27 | 上面的程式將會輸出以下的結果: 28 | 29 | ```js 30 | > 5 31 | > 5 32 | > 5 33 | > 5 34 | > 5 35 | ``` 36 | 所以這肯定是不能執行的。 37 | 38 | **原因** 39 | 40 | 每個 timeout 指向到原來的 `i`,而非拷貝的。所以在迴圈下 `i` 會增加直到 5,然後 timeout 執行並使用目前的 `i` 數值(i 是 5)。 41 | 42 | 當然,這個問題看似簡單。一個直接的解決方法就是將迴圈的索引暫存到變數。 43 | 44 | ```js 45 | for (var i = 0; i < 5; i++) { 46 | var temp = i; 47 | setTimeout(function(){ 48 | console.log(temp); 49 | }, 1000 * (i + 1)); 50 | } 51 | ``` 52 | 但以上的程式輸出的結果是: 53 | 54 | ```js 55 | > 4 56 | > 4 57 | > 4 58 | > 4 59 | > 4 60 | ``` 61 | 62 | 所以,一樣不能執行,因為區塊初始化時沒有建立一個範圍和變數,把它們提升到 scope 的頂部。事實上,在前面的程式碼也是相同的: 63 | 64 | ```js 65 | var temp; 66 | for (var i = 0; i < 5; i++) { 67 | temp = i; 68 | setTimeout(function(){ 69 | console.log(temp); 70 | }, 1000 * (i + 1)); 71 | } 72 | ``` 73 | **解決辦法** 74 | 75 | 這裡有一些不同的方式來複製 `i`。一般的方式是建立一個 closure,宣告一個函式並將 `i` 作為一個參數傳送。在這裡我們做了一個立即函式。 76 | 77 | ```js 78 | for (var i = 0; i < 5; i++) { 79 | (function(num){ 80 | setTimeout(function(){ 81 | console.log(num); 82 | }, 1000 * (i + 1)); 83 | })(i); 84 | } 85 | ``` 86 | 在 JavaScript,參數是透過傳值方式給函數。所以原始的類型像是數字、日期、和字串基本上都是被複製的。如果你想要再函式內改變他們,它是不會影響外部的範圍。物件比較特別:假設內部函數改變屬性,這個改變會影響所有範圍。 87 | 88 | 其他解決方法可以使用 `let`。它是 `ES6` 其中一種變數的宣告方式,它和 `var` 不一樣,只在區塊內作用。 89 | 90 | ```js 91 | for (let i = 0; i < 5; i++) { 92 | var temp = i; 93 | setTimeout(function(){ 94 | console.log(temp); 95 | }, 1000 * (i + 1)); 96 | } 97 | ``` 98 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-02-09-using-json-stringify.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 使用 JSON.Stringify 5 | tip-number: 40 6 | tip-username: vamshisuram 7 | tip-username-profile: https://github.com/vamshisuram 8 | tip-tldr: 從 JSON 物件中,將被選到的屬性建立成字串。 9 | 10 | 11 | redirect_from: 12 | - /zh_tw/using-json-stringify/ 13 | 14 | categories: 15 | - zh_TW 16 | - javascript 17 | --- 18 | 19 | 假設有一個物件有「prop1」、「prop2」、「prop3」屬性。 20 | 我們傳送__額外的參數__到 __JSON.stringify__ 將物件的屬性變成字串,像是: 21 | 22 | ```javascript 23 | var obj = { 24 | 'prop1': 'value1', 25 | 'prop2': 'value2', 26 | 'prop3': 'value3' 27 | }; 28 | 29 | var selectedProperties = ['prop1', 'prop2']; 30 | 31 | var str = JSON.stringify(obj, selectedProperties); 32 | 33 | // str 34 | // {"prop1":"value1","prop2":"value2"} 35 | 36 | ``` 37 | 38 | __"str"__ 只包含被選擇到的屬性的資訊。 39 | 40 | 除了傳送陣列,我們也可以傳送函式。 41 | 42 | ```javascript 43 | 44 | function selectedProperties(key, val) { 45 | // 第一個數值是整個物件,key 是空的字串 46 | if (!key) { 47 | return val; 48 | } 49 | 50 | if (key === 'prop1' || key === 'prop2') { 51 | return val; 52 | } 53 | 54 | return; 55 | } 56 | ``` 57 | 58 | 最後一個可選參數式是修改物件寫入字串的方式。 59 | 60 | ```javascript 61 | var str = JSON.stringify(obj, selectedProperties, '\t\t'); 62 | 63 | /* str 每個輸出會有 doube tabs。 64 | { 65 | "prop1": "value1", 66 | "prop2": "value2" 67 | } 68 | */ 69 | 70 | ``` 71 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-02-10-array-average-and-median.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 陣列平均值和中間值 5 | tip-number: 41 6 | tip-username: soyuka 7 | tip-username-profile: https://github.com/soyuka 8 | tip-tldr: 計算陣列的平均值和中間值。 9 | 10 | 11 | redirect_from: 12 | - /zh_tw/array-average-and-median/ 13 | 14 | categories: 15 | - zh_TW 16 | - javascript 17 | --- 18 | 19 | 以下範例基於一個陣列: 20 | 21 | ```javascript 22 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 23 | ``` 24 | 25 | 如果要取得平均,我們必須加總所有數字和再除以數字的個數。步驟是: 26 | - 取得陣列長度 27 | - 加總數值 28 | - 取得平均(`數值總和 / 陣列長度`) 29 | 30 | ```javascript 31 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 32 | let sum = values.reduce((previous, current) => current += previous); 33 | let avg = sum / values.length; 34 | // avg = 28 35 | ``` 36 | 37 | 或: 38 | 39 | ```javascript 40 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 41 | let count = values.length; 42 | values = values.reduce((previous, current) => current += previous); 43 | values /= count; 44 | // avg = 28 45 | ``` 46 | 47 | 現在,如果要取得中間值的步驟: 48 | - 將陣列排序 49 | - 取得中間值的算術平均值 50 | 51 | ```javascript 52 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 53 | values.sort((a, b) => a - b); 54 | let lowMiddle = Math.floor((values.length - 1) / 2); 55 | let highMiddle = Math.ceil((values.length - 1) / 2); 56 | let median = (values[lowMiddle] + values[highMiddle]) / 2; 57 | // median = 13,5 58 | ``` 59 | 60 | 隨著位元運算符: 61 | 62 | ```javascript 63 | let values = [2, 56, 3, 41, 0, 4, 100, 23]; 64 | values.sort((a, b) => a - b); 65 | let median = (values[(values.length - 1) >> 1] + values[values.length >> 1]) / 2 66 | // median = 13,5 67 | ``` 68 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-02-11-preventing-unapply-attacks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 防止 Unapply 攻擊 5 | tip-number: 42 6 | tip-username: emars 7 | tip-username-profile: https://twitter.com/marseltov 8 | tip-tldr: 凍結內建的屬性。 9 | 10 | redirect_from: 11 | - /zh_tw/preventing-unapply-attacks/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 透過覆寫內建的原型,攻擊者可以重寫程式碼來暴露或更改綁定的參數。這是一個嚴重的安全漏洞,利用 es5 polyfill 的方法。 19 | 20 | ```js 21 | // 綁定 polyfill 範例 22 | function bind(fn) { 23 | var prev = Array.prototype.slice.call(arguments, 1); 24 | return function bound() { 25 | var curr = Array.prototype.slice.call(arguments, 0); 26 | var args = Array.prototype.concat.apply(prev, curr); 27 | return fn.apply(null, args); 28 | }; 29 | } 30 | 31 | 32 | // unapply 攻擊 33 | function unapplyAttack() { 34 | var concat = Array.prototype.concat; 35 | Array.prototype.concat = function replaceAll() { 36 | Array.prototype.concat = concat; // 恢復正確的版本 37 | var curr = Array.prototype.slice.call(arguments, 0); 38 | var result = concat.apply([], curr); 39 | return result; 40 | }; 41 | } 42 | ``` 43 | 44 | 以上的函式拋棄了綁定的 `prev` 陣列,任何 `.concat` 在第一個 `concat` 被呼叫之後使用 unapply 攻擊會拋出錯誤。 45 | 46 | 使用 [Object.freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) 讓物件保持不變,你可以防止任何內建物件原型被覆寫。 47 | 48 | 49 | ```js 50 | (function freezePrototypes() { 51 | if (typeof Object.freeze !== 'function') { 52 | throw new Error('Missing Object.freeze'); 53 | } 54 | Object.freeze(Object.prototype); 55 | Object.freeze(Array.prototype); 56 | Object.freeze(Function.prototype); 57 | }()); 58 | ``` 59 | 60 | 你可以在[這裡](https://glebbahmutov.com/blog/unapply-attack/)閱讀更多關於 unapply 攻擊。 61 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-02-13-know-the-passing-mechanism.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 了解傳送機制 5 | tip-number: 44 6 | tip-username: bmkmanoj 7 | tip-username-profile: https://github.com/bmkmanoj 8 | tip-tldr: JavaScript 技術上只傳送原始和物件類型的值(或參考)。在參考的類型下,參考值本身是 passed by value。 9 | 10 | redirect_from: 11 | - /zh_tw/know-the-passing-mechanism/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | JavaScript 技術上是透過 pass-by-value。它既不是傳值(pass-by-value)也不是傳參考(pass-by-reference),要理解這些術語的意義,你要了它們傳送的機制,透過以下的範例程式碼和解釋了解它們的意義。 18 | 19 | ### 範例一 20 | 21 | ```js 22 | 23 | var me = { // 1 24 | 'partOf' : 'A Team' 25 | }; 26 | 27 | function myTeam(me) { // 2 28 | 29 | me = { // 3 30 | 'belongsTo' : 'A Group' 31 | }; 32 | } 33 | 34 | myTeam(me); 35 | console.log(me); // 4 : {'partOf' : 'A Team'} 36 | 37 | ``` 38 | 39 | 在上方的範例,當 `myTeam` 函式被調用,JavaScript *將 `me` 物件當作 passing the reference 作為值*,調用本身建立了兩個獨立的參考在相同的物件,(雖然在這邊名稱相同,例如 `me`,這是一個誤導讓我們以為它是單一參考物件的印象。),因此,參考變數它們都是獨立的。 40 | 41 | 當我們在 #`3` 給了一個新的物件,我們完全改變 `myTeam` 函式內的參考值,在函式之外的原始物件不會受到影響,從這裡物件參考到外部保留了原始物件的值,並傳入函式內,因此可以從 #`4` 看到輸出值。 42 | 43 | 44 | ### 範例二 45 | 46 | ```js 47 | 48 | var me = { // 1 49 | 'partOf' : 'A Team' 50 | }; 51 | 52 | function myGroup(me) { // 2 53 | me.partOf = 'A Group'; // 3 54 | } 55 | 56 | myGroup(me); 57 | console.log(me); // 4 : {'partOf' : 'A Group'} 58 | 59 | ``` 60 | 61 | 在這個例子 `myGroup` 被調用,我們傳送了物件 `me`。但不像範例一的程式碼,我們沒有給予 `me` 變數到任何的新物件,當我們在 `myGroup` 函式內修改物件的屬性,物件參考值一直是參考到原始的值,這是可以有效的改變物件的屬性。因此你可以從 #`7` 看到輸出值。 62 | 63 | 所以最後一個情況也不能證明 JavaScript 是 pass-by-reference 嗎?不,它不是的。記住,*如果是物件的情況下,JavaScript 將 passes the reference 作為值*。這裡會產生困惑,所以我們往往不能完全理解什麼是傳參考。這是明確的原因,有些人喜歡稱它們為 *call-by-sharing*。 64 | 65 | 66 | *本文最早被作者發表於 [js-by-examples](https://github.com/bmkmanoj/js-by-examples/blob/master/examples/js_pass_by_value_or_reference.md)* 67 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-02-14-calculate-the-max-min-value-from-an-array.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 從陣列計算最大和最小值 5 | tip-number: 45 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: 在數字陣列使用內建的 Max.max() 和 Max.min() 函式的方式。 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_tw/calculate-the-max-min-value-from-an-array/ 13 | 14 | categories: 15 | - zh_TW 16 | - javascript 17 | --- 18 | 19 | 內建函式 [Math.max()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max) 和 [Math.min()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min) 分別可以從參數中找到最大值和最小值。 20 | 21 | ```js 22 | Math.max(1, 2, 3, 4); // 4 23 | Math.min(1, 2, 3, 4); // 1 24 | ``` 25 | 26 | 這些函式對於數字陣列是無法作用的。然而,這裡有些解決辦法。 27 | 28 | [`Function.prototype.apply()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) 允許你呼叫函式並給定一個 `this` 和一個_陣列_的參數。 29 | 30 | ```js 31 | var numbers = [1, 2, 3, 4]; 32 | Math.max.apply(null, numbers) // 4 33 | Math.min.apply(null, numbers) // 1 34 | ``` 35 | 36 | 傳送 `numbers` 陣列當作 `apply()` 的第二個參數,函式會呼叫陣列內所有的值當作函式的參數。 37 | 38 | 更簡單的方式,透過 ES2015 的[展開運算子](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator)來完成。 39 | 40 | ```js 41 | var numbers = [1, 2, 3, 4]; 42 | Math.max(...numbers) // 4 43 | Math.min(...numbers) // 1 44 | ``` 45 | 46 | 這個運算子可以在函式的參數中把陣列內的數值「展開」。 47 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-02-15-detect-document-ready-in-pure-js.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 使用 pure JavaScript 檢查文件是否準備 5 | tip-number: 46 6 | tip-username: loverajoel 7 | tip-username-profile: https://www.twitter.com/loverajoel 8 | tip-tldr: 可以跨瀏覽器,而且使用 pure JavaScript 來確認文件是否已經載入完成。 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_tw/detect-document-ready-in-pure-js/ 13 | 14 | categories: 15 | - zh_TW 16 | - javascript 17 | --- 18 | 19 | 可以跨瀏覽器,而且使用 pure JavaScript 來確認文件是否已經載入完成的方式是使用 [`readyState`](https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState)。 20 | 21 | ```js 22 | if (document.readyState === 'complete') { 23 | // 網頁已經完全載入 24 | } 25 | ``` 26 | 27 | 當文件載入後,你可以檢查文件是否載入完成... 28 | 29 | 30 | ```js 31 | let stateCheck = setInterval(() => { 32 | if (document.readyState === 'complete') { 33 | clearInterval(stateCheck); 34 | // 文件載入 35 | } 36 | }, 100); 37 | ``` 38 | 39 | 或使用 [onreadystatechange](https://developer.mozilla.org/en-US/docs/Web/Events/readystatechange)... 40 | 41 | 42 | ```js 43 | document.onreadystatechange = () => { 44 | if (document.readyState === 'complete') { 45 | // 文件載入 46 | } 47 | }; 48 | ``` 49 | 50 | 當 DOM 載入後,使用 `document.readyState === 'interactive'` 來檢查是否載入完成。 51 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-02-26-extract-unix-timestamp-easily.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 在 JavaScript 簡單取得 unix timestamp 5 | tip-number: 49 6 | tip-username: nmrony 7 | tip-username-profile: https://github.com/nmrony 8 | tip-tldr: 在 JavaScript 你可以簡單取得 unix timestamp 9 | 10 | redirect_from: 11 | - /zh_tw/extract-unix-timestamp-easily/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | 我們經常需要計算 unix 的 timestamp。有許多方式可以取得 timestamp。目前取得 unix timestamp 最簡單和快速的方式是: 19 | 20 | ```js 21 | const dateTime = Date.now(); 22 | const timestamp = Math.floor(dateTime / 1000); 23 | ``` 24 | 25 | 或 26 | 27 | ```js 28 | const dateTime = new Date().getTime(); 29 | const timestamp = Math.floor(dateTime / 1000); 30 | ``` 31 | 32 | 如果要取得特定的 unix timestamp 傳送一個 `YYYY-MM-DD` 或 `YYYY-MM-DDT00:00:00Z` 參數到 `Date` 的建構子。例如: 33 | 34 | ```js 35 | const timestamp = new Date('2012-06-08').getTime() 36 | ``` 37 | 38 | 當你宣告一個 `Date` 物件,也可以加上 `+` 符號: 39 | 40 | ```js 41 | const dateTime = +new Date(); 42 | const timestamp = Math.floor(dateTime / 1000); 43 | ``` 44 | 或指定日期 45 | 46 | ```js 47 | const dateTime = +new Date('2012-06-08'); 48 | const timestamp = Math.floor(dateTime / 1000); 49 | ``` 50 | 在執行時呼叫了 `Date` 物件的 `valueOf` 方法。`+` 運算子呼叫了 `toNumber()` 和回傳的值。更多細節的說明請參考以下的連結。 51 | 52 | * [Date.prototype.valueOf](http://es5.github.io/#x15.9.5.8) 53 | * [Unary + operator](http://es5.github.io/#x11.4.6) 54 | * [toNumber()](http://es5.github.io/#x9.3) 55 | * [Date Javascript MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) 56 | * [Date.parse()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse) 57 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-03-03-helpful-console-log-hacks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 實用的 Console Logging 技巧 5 | tip-number: 50 6 | tip-username: zackhall 7 | tip-username-profile: https://twitter.com/zthall 8 | tip-tldr: 使用條件中斷點的 logging 實用技巧。 9 | 10 | redirect_from: 11 | - /zh_tw/helpful-console-log-hacks/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 18 | ## 使用條件中斷點來記錄資料 19 | 20 | 當函式被呼叫時,如果你想要在 console 顯示每次記錄 的值,你可以透過條件中斷點來記錄。打開你的開發工具,找到你要 console 出來資料的函式,並設定以下的條件中斷點: 21 | 22 | ```js 23 | console.log(data.value) && false 24 | ``` 25 | 26 | 如果條件中斷點為 true 才會停止頁面。所以,使用條件像是 console.log('foo') && false 可以保證為 false,因為在 AND 條件下有一個 false。所以這不會停止你的頁面,但是還是會 console 你記錄的資料。這也可以使用在記錄你的函式或 callback 被呼叫了多少次。 27 | 28 | 這裡有一些各個瀏覽器如何設定條件中斷點:[Edge](https://dev.windows.com/en-us/microsoft-edge/platform/documentation/f12-devtools-guide/debugger/#setting-and-managing-breakpoints "Managing Breakpoints in Edge")、[Chrome](https://developer.chrome.com/devtools/docs/javascript-debugging#breakpoints "Managing Breakpoints in Chrome") 和 [Firefox](https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Set_a_conditional_breakpoint "Managing Breakpoints in Firefox") 和 [Safari](https://developer.apple.com/library/mac/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/Debugger/Debugger.html "Managing Breakpoints in Safari")。 29 | 30 | ## 在 console 顯示函式的變數 31 | 32 | 你曾經想要 console 顯示函式的變數,但是卻無法看到函式的程式碼嗎?最快速看到函式的程式碼的方式是將函式的變數串接一個空字串強制把它轉成字串來顯示。 33 | 34 | ```js 35 | console.log(funcVariable + ''); 36 | ``` -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-03-16-DOM-event-listening-made-easy.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 簡單的監聽 DOM 事件 5 | tip-number: 51 6 | tip-username: octopitus 7 | tip-username-profile: https://github.com/octopitus 8 | tip-tldr: 一個優雅和簡單的方式來處理 DOM 事件。 9 | 10 | redirect_from: 11 | - /zh_tw/DOM-event-listening-made-easy/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 很多人仍然透過以下方法來處理 DOM 事件︰ 18 | 19 | - `element.addEventListener('type', obj.method.bind(obj))` 20 | - `element.addEventListener('type', function (event) {})` 21 | - `element.addEventListener('type', (event) => {})` 22 | 23 | 當你不需要這些處理函式時,使用者可能因為交互事件或[冒泡事件](http://www.javascripter.net/faq/eventbubbling.htm)而不小心觸發意外。 24 | 25 | 安全的事件處理模式包含以下這些: 26 | 27 | 使用一個參考: 28 | 29 | ```js 30 | const handler = function () { 31 | console.log("Tada!") 32 | } 33 | element.addEventListener("click", handler) 34 | // 之後 35 | element.removeEventListener("click", handler) 36 | ``` 37 | 38 | 命名函式刪除本身: 39 | 40 | ```js 41 | element.addEventListener('click', function click(e) { 42 | if (someCondition) { 43 | return e.currentTarget.removeEventListener('click', click); 44 | } 45 | }); 46 | ``` 47 | 48 | 更好的方式: 49 | 50 | ```js 51 | function handleEvent (eventName, {onElement, withCallback, useCapture = false} = {}, thisArg) { 52 | const element = onElement || document.documentElement 53 | 54 | function handler (event) { 55 | if (typeof withCallback === 'function') { 56 | withCallback.call(thisArg, event) 57 | } 58 | } 59 | 60 | handler.destroy = function () { 61 | return element.removeEventListener(eventName, handler, useCapture) 62 | } 63 | 64 | element.addEventListener(eventName, handler, useCapture) 65 | return handler 66 | } 67 | 68 | // 任何你需要的時候 69 | const handleClick = handleEvent('click', { 70 | onElement: element, 71 | withCallback: (event) => { 72 | console.log('Tada!') 73 | } 74 | }) 75 | 76 | // 任何時候你想要將它移除 77 | handleClick.destroy() 78 | ``` 79 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-08-02-copy-to-clipboard.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 複製到剪貼版 5 | tip-number: 56 6 | tip-username: loverajoel 7 | tip-username-profile: https://twitter.com/loverajoel 8 | tip-tldr: 本週我建立了一個常見的「複製到剪貼版」按鈕,我以前不曾做過這樣的功能,我想分享我如何實作它。 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_tw/copy-to-clipboard/ 13 | 14 | categories: 15 | - zh_TW 16 | - javascript 17 | --- 18 | 19 | 這是一個簡單的 tip,本週我建立了一個常見的「複製到剪貼版」按鈕,我以前不曾做過這樣的功能,我想分享我如何實作它。 20 | 它很簡單,比較麻煩的是我們必須加入一個 `` 與文字複製到 DOM。我們選擇內容並執行 [execCommand](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand) 複製指令。 21 | `execCommand('copy')` 將複製時間被選擇的內容 22 | 23 | 這個指令目前[支援](http://caniuse.com/#search=execCommand)所有最新的瀏覽器,允許我們執行其他系統指令,像是:`copy`、`cut`、`paste` 和改變字體顏色、大小等等。 24 | 25 | ```js 26 | document.querySelector('#input').select(); 27 | document.execCommand('copy'); 28 | ``` 29 | 30 | 具體呈現請看參考[這裡](https://jsbin.com/huhozu/edit?html,js,output) 31 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-08-10-comma-operaton-in-js.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: JavaScript 的逗號操作符 5 | tip-number: 57 6 | tip-username: bhaskarmelkani 7 | tip-username-profile: https://www.twitter.com/bhaskarmelkani 8 | tip-tldr: 在一個表達式中,由左到右計算每個表達式並回傳最後的一個。 9 | 10 | redirect_from: 11 | - /zh_tw/comma-operaton-in-js/ 12 | 13 | categories: 14 | - zh_TW 15 | - javascript 16 | --- 17 | 除了分號之外,逗號允許你在同一個地方放多個語句。 18 | 例如: 19 | 20 | ```js 21 | for(var i=0, j=0; i<5; i++, j++, j++){ 22 | console.log("i:"+i+", j:"+j); 23 | } 24 | ``` 25 | 26 | 輸出: 27 | 28 | ```js 29 | i:0, j:0 30 | i:1, j:2 31 | i:2, j:4 32 | i:3, j:6 33 | i:4, j:8 34 | ``` 35 | 36 | 當放置一個表達式時,它由左到右計算每個表達式,並回傳最右邊的表達式。 37 | 38 | 例如: 39 | 40 | ```js 41 | function a(){console.log('a'); return 'a';} 42 | function b(){console.log('b'); return 'b';} 43 | function c(){console.log('c'); return 'c';} 44 | 45 | var x = (a(), b(), c()); 46 | 47 | console.log(x); // 輸出「c」 48 | ``` 49 | 輸出: 50 | 51 | ```js 52 | "a" 53 | "b" 54 | "c" 55 | 56 | "c" 57 | ``` 58 | 59 | * 注意:逗號(`,`)操作符在 JavaScript 所有 的操作符是最低的優先順序,所以如果沒有括號表達式將變成:`(x = a()), b(), c();`。 60 | 61 | ##### Playground 62 | 65 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2016-10-28-three-useful-hacks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 三個有用的技巧 5 | tip-number: 60 6 | tip-username: leandrosimoes 7 | tip-username-profile: https://github.com/leandrosimoes 8 | tip-tldr: 三個非常有用的技巧來加速你的開發速度。 9 | 10 | 11 | redirect_from: 12 | - /zh_tw/three-useful-hacks/ 13 | 14 | categories: 15 | - zh_TW 16 | - javascript 17 | --- 18 | 19 | #### 由後往前取得陣列數值: 20 | 21 | 如果你想要由後往前取得陣列的數值,可以這麼做: 22 | 23 | ```javascript 24 | var newArray = [1, 2, 3, 4]; 25 | 26 | console.log(newArray.slice(-1)); // [4] 27 | console.log(newArray.slice(-2)); // [3, 4] 28 | console.log(newArray.slice(-3)); // [2, 3, 4] 29 | console.log(newArray.slice(-4)); // [1, 2, 3, 4] 30 | ``` 31 | 32 | #### Short-circuits 狀態 33 | 34 | 如果你有一個 function,它的狀態為 `true`,像是這樣: 35 | 36 | ```javascript 37 | if (condition){ 38 | dosomething(); 39 | } 40 | ``` 41 | 42 | 你可以像這樣使用 short-circuit: 43 | 44 | ```javascript 45 | condition && dosomething(); 46 | ``` 47 | 48 | 49 | #### 使用「||」設定變數的預設值 50 | 51 | 52 | 如果你要在變數設定一個預設值,你可以這麼做: 53 | 54 | ```javascript 55 | var a; 56 | 57 | console.log(a); //undefined 58 | 59 | a = a || 'default value'; 60 | 61 | console.log(a); //default value 62 | 63 | a = a || 'new value'; 64 | 65 | console.log(a); //default value 66 | ``` 67 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2017-01-19-binding-objects-to-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Bind 物件到 function 5 | tip-number: 61 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: 了解在 JavaScript 中如何使用 `Bind` 方法和物件以及 function 9 | 10 | 11 | redirect_from: 12 | - /zh_tw/binding-objects-to-functions/ 13 | 14 | categories: 15 | - zh_TW 16 | - javascript 17 | --- 18 | 19 | 很多時候,我們需要 bind 一個物件到一個 function 的 this 物件。當 this 明確的被指定在 JS 的 bind 方法且我們需要調用所需的方法。 20 | 21 | ### Bind 語法 22 | 23 | ```js 24 | fun.bind(thisArg[, arg1[, arg2[, ...]]]) 25 | ``` 26 | 27 | ## 參數 28 | **thisArg** 29 | 30 | `this` 參數值可以被傳送到目標的 function 同時呼叫 被 `bind` 的 function。 31 | 32 | **arg1, arg2, ...** 33 | 34 | 前置參數被傳送到被 `bind` 的 function 同時調用目標 function。 35 | 36 | **回傳值** 37 | 38 | 一個給定 function 的副本以及指定的 `this` 值和初始參數。 39 | 40 | ### 在 JS 的 action 中 Bind 方法 41 | 42 | ```js 43 | const myCar = { 44 | brand: 'Ford', 45 | type: 'Sedan', 46 | color: 'Red' 47 | }; 48 | 49 | const getBrand = function () { 50 | console.log(this.brand); 51 | }; 52 | 53 | const getType = function () { 54 | console.log(this.type); 55 | }; 56 | 57 | const getColor = function () { 58 | console.log(this.color); 59 | }; 60 | 61 | getBrand(); // object not bind,undefined 62 | 63 | getBrand(myCar); // object not bind,undefined 64 | 65 | getType.bind(myCar)(); // Sedan 66 | 67 | let boundGetColor = getColor.bind(myCar); 68 | boundGetColor(); // Red 69 | 70 | ``` 71 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2017-03-09-working-with-websocket-timeout.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 處理 Websocket 超時 5 | tip-number: 63 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: 一個控制 timeout 的技巧 9 | 10 | categories: 11 | - zh_TW 12 | - javascript 13 | --- 14 | 15 | 在 websocket 連接被建立的情況下,如果一段時間處於非活動狀態,伺服器或防火牆可能超時或終止連接。為了要處理這個情況,我們向伺服器週期性的傳送訊息。為了控制超時,我們將新增兩個 function 再我們的程式碼:一是確認連接持久連線(keep alive),另一個則是取消持久連線。我們也還需要一個共同的 `timerID` 變數。 16 | 讓我們來實作看看: 17 | 18 | ```js 19 | var timerID = 0; 20 | function keepAlive() { 21 | var timeout = 20000; 22 | if (webSocket.readyState == webSocket.OPEN) { 23 | webSocket.send(''); 24 | } 25 | timerId = setTimeout(keepAlive, timeout); 26 | } 27 | function cancelKeepAlive() { 28 | if (timerId) { 29 | cancelTimeout(timerId); 30 | } 31 | } 32 | ``` 33 | 34 | 現在我們在 task 有兩個我們需要的 function,我們將放置 ```keepAlive()``` function 在 ```onOpen()``` 方法的 websocket 連接之後以及 ```cancelKeepAlive()``` function 在 ```onClose()``` 方法的 websocket 連接後面。 35 | 36 | 沒錯!我們完美實作了 websocket 超時問題的方法。 37 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2017-03-12-3-array-hacks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 使用 Array 的三個技巧 5 | tip-number: 64 6 | tip-username: hassanhelfi 7 | tip-username-profile: https://twitter.com/hassanhelfi 8 | tip-tldr: 在 JavaScript 中隨處都可以看見陣列,ECMAScript 6 介紹了展開運算符(spread operator),你可以透過它來處理陣列。在這篇 tip,我將示範三個有用的技巧,當你在寫程式時可以使用。 9 | 10 | categories: 11 | - zh_TW 12 | - javascript 13 | --- 14 | 15 | 在 JavaScript 中隨處都可以看見陣列,ECMAScript 6 中介紹到了[展開運算符](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Spread_operator),你可以透過它來處理陣列。在這篇 tip,我將示範三個有用的技巧,當你在寫程式時可以使用。 16 | 17 | ### 1. 迭代一個空的陣列 18 | 19 | JavaScript 陣列特性是鬆散的,所以在這裡有許多坑。嘗試使用陣列的建構子建立一個陣列,你會明白我的意思。 20 | 21 | ```javascript 22 | > const arr = new Array(4); 23 | [undefined, undefined, undefined, undefined] 24 | ``` 25 | 26 | 你可能發現到,迭代一個鬆散的陣列並應用在某些轉換是相當困難的。 27 | 28 | ```javascript 29 | > const arr = new Array(4); 30 | > arr.map((elem, index) => index); 31 | [undefined, undefined, undefined, undefined] 32 | ``` 33 | 34 | 為了解決這個問題,當你在建立陣列時你可以使用 `Array.apply`。 35 | 36 | ```javascript 37 | > const arr = Array.apply(null, new Array(4)); 38 | > arr.map((elem, index) => index); 39 | [0, 1, 2, 3] 40 | ``` 41 | 42 | ### 2. 傳送一個空的參數到方法 43 | 44 | 如果你想要呼叫一個方法並忽略其中一個參數,如果你將參數為空的話,JavaScript 會告訴你發生錯誤。 45 | 46 | ```javascript 47 | > method('parameter1', , 'parameter3'); 48 | Uncaught SyntaxError: Unexpected token , 49 | ``` 50 | 51 | 通常我們會採取傳送一個 `null` 或 `undefined` 的處理方式。 52 | 53 | ```javascript 54 | > method('parameter1', null, 'parameter3') // 或者 55 | > method('parameter1', undefined, 'parameter3'); 56 | ``` 57 | 58 | 我個人不喜歡使用 `null`,由於 JavaScript 會它當作一個 object,那是很奇怪的。隨著採用 ES6 的展開運算符,有一個更簡潔的方法將空參數傳送給方法。如我們先前所提到的,陣列的特性是鬆散的而且傳送空的值是可行的。我們將利用這個優勢來使用。 59 | 60 | ```javascript 61 | > method(...['parameter1', , 'parameter3']); // 成功! 62 | ``` 63 | 64 | ### 唯一的陣列值 65 | 66 | 我總是在想為什麼陣列建構子沒辦法指定的方法,方便的使用唯一的陣列值。展開運算符在這裡解救了我。使用展開運算符與 `Set` 建構子來產生唯一的陣列值。 67 | 68 | ```javascript 69 | > const arr = [...new Set([1, 2, 3, 3])]; 70 | [1, 2, 3] 71 | ``` 72 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2017-03-16-tapping-for-quick-debugging.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 使用監聽(tap)來快速 debug 5 | tip-number: 65 6 | tip-username: loverajoel 7 | tip-username-profile: https://twitter.com/loverajoel 8 | tip-tldr: 一個相當有用 function 用來快速 debung 一連串的 function 呼叫、匿名函式,實際上你可能只是想要列印而已。 9 | 10 | categories: 11 | - zh_TW 12 | - javascript 13 | --- 14 | 15 | 一個相當有用 function 用來快速 debung 一連串的 function 呼叫、匿名函式,實際上你可能只是想要列印而已。 16 | 17 | ``` javascript 18 | function tap(x) { 19 | console.log(x); 20 | return x; 21 | } 22 | ``` 23 | 24 | 為什麼你不使用 `console.log` 的老方式呢?讓我示範一個範例: 25 | 26 | ``` javascript 27 | bank_totals_by_client(bank_info(1, banks), table) 28 | .filter(c => c.balance > 25000) 29 | .sort((c1, c2) => c1.balance <= c2.balance ? 1 : -1 ) 30 | .map(c => 31 | console.log(`${c.id} | ${c.tax_number} (${c.name}) => ${c.balance}`)); 32 | ``` 33 | 34 | 現在,假設你從一連串的 function 呼叫確沒有得到任何東西(可能是一個錯誤)。 35 | 哪裡失敗了?或許是 `bank_info` 沒有回傳任何東西,所以我們將監聽它: 36 | 37 | ``` javascript 38 | bank_totals_by_client(tap(bank_info(1, banks)), table) 39 | ``` 40 | 41 | 根據我們部份的實作,它可能會列印出一些東西或者什麼都沒有。 42 | 我假設我們監聽得到的資訊是正確的,因此 bank_info 並不會產生任何結果。 43 | 44 | 我們必須移到下一個 filter function。 45 | 46 | ``` javascript 47 | .filter(c => tap(c).balance > 25000) 48 | ``` 49 | 50 | 我們實際上有接收到任何的 client 資訊嗎?如果有,bank_totals_by_client 正常的工作。或許它是 filter 內的條件? 51 | 52 | ``` javascript 53 | .filter(c => tap(c.balance > 25000)) 54 | ``` 55 | 56 | 啊!我們沒看到其他東西,但是 `false` 被列印出來,所以沒有 client 是大於 25000,這也是為什麼 function 沒有回傳任何東西。 57 | 58 | ## 更進階的監聽 59 | 60 | ``` javascript 61 | function tap(x, fn = x => x) { 62 | console.log(fn(x)); 63 | return x; 64 | } 65 | ``` 66 | 67 | 現在我們討論一個更進階的,如果我們想要執行某個運算符*事先*到 tap(監聽)?例如,我需要存取目前 object 的屬性,執行一個邏輯運算等等。與被我們監聽的 object?然後我們呼叫 tap 和一個額外的參數,在監聽的時候應用這個 function。 68 | 69 | ``` javascript 70 | tap(3, x => x + 2) === 3; // 列印 5,但是表達是計算為 true,為什麼 :-)? 71 | ``` 72 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2017-04-03-why-you-should-use-Object.is()-in-equality-comparison.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 為什麼在做相等比較的時候,你應該使用 Object.is() 5 | tip-number: 68 6 | tip-username: TarekAlQaddy 7 | tip-username-profile: https://github.com/TarekAlQaddy 8 | tip-tldr: 在 JavaScript 中對於較鬆散的相等比較,有更好的解決方式 9 | 10 | categories: 11 | - zh_TW 12 | - javascript 13 | --- 14 | 15 | 我們都知道 JavaScript 是一個較鬆散的型別,在某些情況它特別是在 `==` 的情況,當你透過 `==` 來做比較時,常常會得到意外的結果,基於這個原因我們會強制轉換或建立新的變數來「將兩個操作變數中的其中一個轉換為其他類型,然後進行比較」。 16 | 17 | ``` javascript 18 | 0 == ' ' //true 19 | null == undefined //true 20 | [1] == true //true 21 | ``` 22 | 23 | 所以他們提供我們三等號 `===` 的相等操作符,它更嚴格而且不強制去轉換變數,然而 `===` 比較不是一個比較好的解決方式,你可以得到這樣的結果: 24 | 25 | ``` javascript 26 | NaN === NaN //false 27 | ``` 28 | 29 | 好消息是在 ES6 有一個新的 `Object.is()`,它是更精確而且和 `===` 有相同的功能,在某些特殊情況下也運作的很好: 30 | 31 | ``` javascript 32 | Object.is(0 , ' '); //false 33 | Object.is(null, undefined); //false 34 | Object.is([1], true); //false 35 | Object.is(NaN, NaN); //true 36 | ``` 37 | 38 | Mozilla 團隊 不認為 `Object.is` 比 `===` 更嚴格,他們宣稱我們應該思考這些方法如何處理 `NaN`、`-0` 和 `+0`,但是整體來說我認為它在實際的應用程式中是一個好的解決方式。 39 | 40 | 現在我們來看看這個比較表: 41 | 42 | ![differences of operators in equality comparisons javascript](http://i.imgur.com/pCyqkLc.png) 43 | 44 | ## 參考: 45 | [Equality comparisons and sameness](http://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness) 46 | -------------------------------------------------------------------------------- /_posts/zh_TW/javascript/2017-04-05-picking-and-rejecting-object-properties.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 選擇或是拋棄物件屬性 5 | tip-number: 70 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: 有時候我們需要列出物件中某些屬性,假設我們有一個陣列來表達一個資料表,我們需要有些 function 來 `select` 欄位。 9 | 10 | categories: 11 | - zh_TW 12 | - javascript 13 | --- 14 | 15 | 16 | 有時候我們需要列出物件中某些屬性,假設我們有一個陣列來表達一個資料表,我們需要有些 function 來 `select` 欄位: 17 | 18 | ``` javascript 19 | function pick(obj, keys) { 20 | return keys.map(k => k in obj ? {[k]: obj[k]} : {}) 21 | .reduce((res, o) => Object.assign(res, o), {}); 22 | } 23 | 24 | const row = { 25 | 'accounts.id': 1, 26 | 'client.name': 'John Doe', 27 | 'bank.code': 'MDAKW213' 28 | }; 29 | 30 | const table = [ 31 | row, 32 | {'accounts.id': 3, 'client.name': 'Steve Doe', 'bank.code': 'STV12JB'} 33 | ]; 34 | 35 | pick(row, ['client.name']); // 取得 Client 名稱 36 | 37 | table.map(row => pick(row, ['client.name'])); // 取得一些 client 名稱的列表 38 | ``` 39 | 40 | 在 pick 我們透過一個小手段,首先,我們 `map` 一個 function,每次透過目前的 key 只有該屬性的物件被回傳(或者,如果在物件內沒有任何的屬性會回傳一個空的物件)。然後透過 merge 物件,我們 `reduce` 這些單一屬性的集合物件。 41 | 42 | 但是如果我們想要 `reject` 屬性呢?好吧,function 需要一些改變: 43 | 44 | ``` javascript 45 | function reject(obj, keys) { 46 | return Object.keys(obj) 47 | .filter(k => !keys.includes(k)) 48 | .map(k => Object.assign({}, {[k]: obj[k]})) 49 | .reduce((res, o) => Object.assign(res, o), {}); 50 | } 51 | 52 | // 或者恢復 pick 53 | function reject(obj, keys) { 54 | const vkeys = Object.keys(obj) 55 | .filter(k => !keys.includes(k)); 56 | return pick(obj, vkeys); 57 | } 58 | 59 | reject({a: 2, b: 3, c: 4}, ['a', 'b']); // => {c: 4} 60 | ``` 61 | -------------------------------------------------------------------------------- /_posts/zh_TW/more/2017-04-06-vuejs-how-vuejs-makes-a-copy-update-replace-inside-the-data-binding.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: Vuejs 如何在資料綁定時,拷貝、更新並取代原來的資料 5 | tip-number: 71 6 | tip-username: pansila 7 | tip-username-profile: https://github.com/pansil 8 | tip-tldr: 在這篇 Tip,我將介紹一個範例來示範 Vuejs 可能和其他框架產生的衝突。 9 | 10 | categories: 11 | - zh_TW 12 | - more 13 | --- 14 | 15 | ### 概觀 16 | 17 | Vuejs 是一個相當優雅的軟體,相對於其他流行的框架像是 Angularjs 和 Reactjs,它讓你保持簡潔而且強大。 18 | 你以前可能因為害怕而放棄那些複雜的框架,但是 Vuejs 不像上面那些框架這麼複雜,你可以很快速的上手。 19 | 20 | 如果你不知道它是如何運作的,你可能會時常在踩地雷。這裡是另一個簡單而且受歡迎的 Framework7 UI 框架衝突的範例。 21 | 22 | ```html 23 | 24 |
    25 |
    26 | 27 | new page 28 |
    29 |
    30 | 31 | 32 |
    33 |
    34 |
    35 |

    {% raw %}{{content}}{% endraw %}

    36 |
    37 |
    38 |
    39 | ``` 40 | 41 | ```js 42 | var myApp = new Framework7(); 43 | myApp.onPageInit('test', function (page) { 44 | new Vue({ 45 | el: '#test', 46 | data: { 47 | content: 'hello world' 48 | } 49 | }); 50 | }); 51 | ``` 52 | 53 | 你可能會很驚訝它不能正常的運作,在新的頁面載入後沒有任何的改變。事實上,Vue 內部拷貝了目標 HTML template 元素,在透過綁定後,新的拷貝資料會取代原先的舊資料。當頁面載入時,Framework7 調用 `PageInit` callback,接著 Vue 在 `` 元素進行更新。現在 DOM Tree 有了新的 `` 拷貝元素,而 Framework7 在不知情的情況下持續執行剩餘的初始化工作在舊的 `` 元素,最後顯示出來這就是根本的原因。 54 | 55 | 為了要解決它,別讓 Vue selector 目標在 `` 元素,而是在它的子元素。這樣 Vuejs 在做資料綁定時不會影響整個頁面了。 56 | 57 | ```js 58 | var myApp = new Framework7(); 59 | myApp.onPageInit('test', function (page) { 60 | new Vue({ 61 | el: '#test1', 62 | data: { 63 | content: 'hello world' 64 | } 65 | }); 66 | }); 67 | ``` 68 | 69 | ### 更多資訊 70 | 71 | - [Vue](https://github.com/Vuejs/Vue) 72 | - [Framework7](https://framework7.io/) 73 | -------------------------------------------------------------------------------- /_posts/zh_TW/react/2016-01-02-keys-in-children-components-are-important.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | 4 | title: 在子元件 Keys 是很重要的 5 | tip-number: 02 6 | tip-username: loverajoel 7 | tip-username-profile: https://github.com/loverajoel 8 | tip-tldr: 你可以從陣列動態建立 key 屬性並傳送到所有的元件(component)。它是一個唯一以及固定的 id,React 用來識別 DOM 裡面的每個元件,並區別它是否為同一個元件。使用 keys 可以確保子元件被保護而不會被重覆建立,也可以防止奇怪的事件發生。 9 | tip-writer-support: https://www.coinbase.com/loverajoel 10 | 11 | redirect_from: 12 | - /zh_tw/keys-in-children-components-are-important/ 13 | 14 | categories: 15 | - zh_TW 16 | - react 17 | --- 18 | 19 | 你可以從陣列動態建立 [key](https://facebook.github.io/react/docs/multiple-components.html#dynamic-children) 屬性並傳送到所有的元件(component)。它是一個唯一以及固定的 id,React 用來識別 DOM 裡面的每個元件,並區別它是否為同一個元件。使用 keys 可以確保子元件被保護而不會被重覆建立,也可以防止奇怪的事件發生。 20 | 21 | > Key 跟效能不太相關,它跟元件識別較有關係(反之,它間接提升了效能)。隨機賦值和改變數值將無法識別。[Paul O’Shannessy](https://github.com/facebook/react/issues/1342#issuecomment-39230939) 22 | 23 | - 使用物件內存在的唯一值。 24 | - 在你的父元件定義 keys,而不是子元件。 25 | 26 | ```javascript 27 | //bad 28 | ... 29 | render() { 30 |
    {% raw %}{{item.name}}{% endraw %}
    31 | } 32 | ... 33 | 34 | //good 35 | 36 | ``` 37 | - [使用陣列索引是不好的習慣。](https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318#.76co046o9) 38 | - `random()` 將無法使用。 39 | 40 | ```javascript 41 | //bad 42 | 43 | ``` 44 | 45 | 46 | - 你可以建立你自己唯一的 id。確認這個方法夠快速可以附加到你的物件上。 47 | - 當你的子元件數量很多或者含有龐大的元件,使用 keys 可以提高效能。 48 | - [你必須提供 key 屬性給 ReactCSSTransitionGroup 的所有子元件。](http://docs.reactjs-china.com/react/docs/animation.html) 49 | --------------------------------------------------------------------------------