Repository: loverajoel/jstips
Branch: master
Commit: 44a1df45df96
Files: 296
Total size: 603.4 KB
Directory structure:
gitextract_f1dq9svt/
├── 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
================================================
FILE CONTENTS
================================================
================================================
FILE: CONTRIBUTING.md
================================================
# How to submit your tip
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`.
Use [this format](POST_TEMPLATE.md) when writing your tip.
### Requirements
- The tip should be readable in less than two minutes
- Adding links to other sites or videos that give more insight is welcome
- Mark JS code with ```js
- Don't mention "JavaScript" in the title (as our tips are about it anyway)
- Use backticks (`) to mark code in the **title** and/or **tip-tldr** fields. _Warning_: Both values must not start with backticks!
- 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.
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).
## Notes
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.
## Tip flow
**Tip proposal** ⇒ **Tip under review** ⇒ **Tip ready to merge**
- When you send a tip, it has to pass the review process and while that happens, its status is `under review`.
- 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`.
We are looking forward to your contribution!
================================================
FILE: CONTRIBUTING_es_ES.md
================================================
# Como enviar tu tip
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'.
Utilice [este formato](https://github.com/loverajoel/jstips/blob/gh-pages/POST_TEMPLATE.md) para escribir su tip.
### Requisitos
- Su tip debe ser legible en menos de dos minutos.
- Puede añadir enlaces a otros sitios o videos que dan una visión más clara es bienvenido.
- Se marcará el código JS con ```js
- No Mencione "JavaScript" en el título (como nuestros consejos son respecto de todos modos)
- Use comillas invertidas (`) para marcar código en el campos **title** y/o **tip-tldr**. _Precaucion_: Ambos valores no deben comenzar con acentos abiertos!
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).
# Notas
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.
# Flujo del Tip
**Tip proposal** ⇒ **Tip under review** ⇒ **Tip ready to merge**
- Cuando se envía un tip, tiene que pasar el proceso de revisión y mientras eso sucede, su estado es `under review`.
- Después de que el tip sea revisado por 5 personas y han dado (:shipit:), el tip esta `ready to merge`.
================================================
FILE: CONTRIBUTING_zh_CN.md
================================================
# 如何提交小知识
将小知识提交到本列表,`fork`此仓库(repository)然后将的小知识放到对应文件夹(根据语言)的新文件中。新文件的名字应该像`2016-xx-xx-name-of-your-tip`这样。
书写小知识时请按照[这个格式](https://github.com/loverajoel/jstips/blob/gh-pages/POST_TEMPLATE.md)。
### 要求
- 小知识可以在两分钟内阅读完。
- 增加其他网站或视频的链接提供更深讲解更佳
- 使用 ```js 标记JS代码
- 无序在标题处提及"JavaScript"(因为我们的小知识全是关于它的)
- 使用反引号(`) 标记**标题**或**tip-tldr**中的代码 ‐ _警告_:它们都不能以反引号开头
当你的小知识准备就绪了, 根据这个[PR 模板](https://github.com/loverajoel/jstips/blob/gh-pages/GIT_TEMPLATE.md),[发布一个pull request](https://help.github.com/articles/using-pull-requests/)你的小知识将被审查(见下文)。
# 提示
将时间和小知识number保留为**xx**。当PR为`ready to merge`状态时,我们将告诉你正确的数字。请同时[squash](https://davidwalsh.name/squash-commits-git)你的commits.
# 工作流程
**Tip 提交** ⇒ **Tip 审查** ⇒ **Tip 通过并发布**
- 当你提交 tip 时,如果 tip 正在通过审查,此时 tip 状态为 `under review`。
- 如果 tip 经过5个人的审查,而且他們都给了 :shipit:,tip 将会被合并(`merge`)到 tip 列表中。
期待您的贡献!
================================================
FILE: CONTRIBUTING_zh_TW.md
================================================
# 如何提交你的 tip
如果要提交 tip 到目錄,fork 這個儲存庫(repository)並加入你的 tip 到檔案內,放入到正確的資料夾(根據語系)。檔案名稱應該為 `2016-xx-xx-name-of-your-tip`。
當你撰寫你的 tip 時,請使用[這個格式](POST_TEMPLATE.md)。
### 要求
- tip 應該至少可以在兩分鐘內讀懂。
- 你可以連結到其他的網站或者是影片讓我們了解更多。
- 程式碼區塊使用 ```js。
- 避免在 title 提到「JavaScript」(因為我們的 tips 都是與 JavaScript 相關的)。
- 使用反引號(`)來標記程式碼 - _警告_:tip **標題**和 **tip-tldr** 不要使用反引號。
當你的 tip 準備好了,依據這個 [PR 樣板](PULL_REQUEST_TEMPLATE.md),[發送一個 PR](https://help.github.com/articles/using-pull-requests/) 你的 tip 將會被校閱。每天都會有 tip 從可用的 PR 中被合併(merged)。
## 注意
使用 **xx** 為日期和 tip 的編號。當我們決定合併你的 PR 你可以把它們增加並 [squash](https://davidwalsh.name/squash-commits-git) 到你的 commits。
## Tip 工作流程
**Tip 發送** ⇒ **Tip 審查** ⇒ **Tip 接受並發布**
- 當你提交 tip 時,如果 tip 正在校閱流程,則 tip 狀態為 `under-review`。
- 如果 tip 經過 5 位專業的人士校閱,而且他們都給了 :shipit:,tip 將會被合併(`merge`)到 tip 清單。
================================================
FILE: LICENSE.md
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
================================================
FILE: POST_TEMPLATE.md
================================================
---
layout: *post
title: Demo post
tip-number: xx
tip-username: tip_js
tip-username-profile: https://twitter.com/tips_js
tip-tldr: Just a demo
categories:
- en
---
content here
### Subtitles format
================================================
FILE: PULL_REQUEST_TEMPLATE.md
================================================
## [Title here]
## TL;DR;
[content here]
## Username
[twitter account link or github account link ej: [@tips-js](https://twitter.com/tips_js)]
## Extra
[content here]
================================================
FILE: README.md
================================================
[](https://www.jstips.co/book/?utm_source=github&utm_medium=header&utm_campaign=book&utm_content=pro)
# JS Tips [](https://github.com/sindresorhus/awesome)
> Useful JavaScript tips
This is an awesome project about short and useful JavaScript tips that will help you improve your code writing. In less than 2 minutes, you can read about performance, conventions, hacks, interview questions and all the items that the future of this awesome language holds for us.
Tips are added frequently (read further if you want to stay in touch).
## Support the community
If you found a JS Tip useful or if you like a writer of the community, you can show your support and respect with a tip!
### Can you help us enrich it?
Sure, you can help the project in two ways: sending a tip or reviewing future tips.
Any improvements or suggestions are more than welcome!
[Instructions are here](https://github.com/loverajoel/jstips/blob/master/CONTRIBUTING.md).
### Let’s keep in touch
There are a lot of ways to get updates:
- [Official Blog](http://www.jstips.co)
- [Official Twitter Account](https://twitter.com/tips_js)
- [Hubot](https://github.com/dggriffin/hubot-jstips)
- [Slackbot](https://github.com/radibit/js-tips-slack-bot)
- [iOS App](https://goo.gl/Y9WiBc)
> Don't forget to Star★ the repo, as this helps promote the project!
# Tips list
- 74 - [Check the reason make your page re-render by changed props and state](http://www.jstips.co/en/react/trace-the-reason-make-your-page-rerender/)
- 73 - [Hash maps without side effects](http://www.jstips.co/en/javascript/hash-maps-without-side-effects/)
- 72 - [Adventurers Guide to React (Part I)](http://www.jstips.co/en/react/adventurers-guide-to-react/)
- 71 - [VueJS, How VueJS makes a copy-update-replace inside the data binding](http://www.jstips.co/en/more/vuejs-how-vuejs-makes-a-copy-update-replace-inside-the-data-binding/)
- 70 - [Picking and rejecting object properties](http://www.jstips.co/en/javascript/picking-and-rejecting-object-properties/)
- 69 - [Enhancing React components, Composition](http://www.jstips.co/en/react/enhancing-react-components-composition/)
- 68 - [Why you should use Object.is() in equality comparison](http://www.jstips.co/en/javascript/why-you-should-use-Object.is()-in-equality-comparison/)
- 67 - [Recursion, iteration and tail calls in JS](http://www.jstips.co/en/javascript/recursion-iteration-and-tail-calls-in-js/)
- 66 - [State to Props maps with memory](http://www.jstips.co/en/react/state-to-props-maps-with-memory/)
- 65 - [Tapping for quick debugging](http://www.jstips.co/en/javascript/tapping-for-quick-debugging/)
- 64 - [3 Array Hacks](http://www.jstips.co/en/javascript/3-array-hacks/)
- 63 - [Working With Websocket Timeout](http://www.jstips.co/en/javascript/working-with-websocket-timeout/)
- 62 - [Preventing Unwanted Scopes Creation in AngularJs](http://www.jstips.co/en/angular/preventing-unwanted-scopes-creation-in-angularjs/)
- 61 - [Binding objects to functions](http://www.jstips.co/en/javascript/binding-objects-to-functions/)
- 60 - [Three useful hacks](http://www.jstips.co/en/javascript/three-useful-hacks/)
- 59 - [ES6, var vs let](http://www.jstips.co/en/javascript/keyword-var-vs-let/)
- 58 - [Breaking or continuing loop in functional programming](http://www.jstips.co/en/javascript/break-continue-loop-functional/)
- 57 - [Comma operator in JS](http://www.jstips.co/en/javascript/comma-operaton-in-js/)
- 56 - [Copy to Clipboard](http://www.jstips.co/en/javascript/copy-to-clipboard/)
- 55 - [Create an easy loop using an array](http://www.jstips.co/en/javascript/make-easy-loop-on-array/)
- 54 - [How to use optional arguments in functions (with optional callback)](http://www.jstips.co/en/javascript/use-optional-arguments/)
- 53 - [Get File Extension](http://www.jstips.co/en/javascript/get-file-extension/)
- 52 - [Return Values with the 'new' Operator](http://www.jstips.co/en/javascript/return-values-with-the-new-operator/)
- 51 - [DOM event listening made easy](http://www.jstips.co/en/javascript/DOM-event-listening-made-easy/)
- 50 - [Helpful Console Logging Tricks](http://www.jstips.co/en/javascript/helpful-console-log-hacks/)
- 49 - [Easiest way to extract Unix timestamps](http://www.jstips.co/en/javascript/extract-unix-timestamp-easily/)
- 48 - [Reduce builtin function usage](http://www.jstips.co/en/javascript/reminders-about-reduce-function-usage/)
- 47 - [Basics: Declarations](http://www.jstips.co/en/javascript/basics-declarations/)
- 46 - [Detect document ready in pure JS](http://www.jstips.co/en/javascript/detect-document-ready-in-pure-js/)
- 45 - [Calculate the Max/Min value from an array](http://www.jstips.co/en/javascript/calculate-the-max-min-value-from-an-array/)
- 44 - [Know the passing mechanism](http://www.jstips.co/en/javascript/know-the-passing-mechanism/)
- 43 - [Use destructuring in function parameters](http://www.jstips.co/en/javascript/use-destructuring-in-function-parameters/)
- 42 - [Preventing Unapply Attacks](http://www.jstips.co/en/javascript/preventing-unapply-attacks/)
- 41 - [Array average and median](http://www.jstips.co/en/javascript/array-average-and-median/)
- 40 - [Using JSON.stringify](http://www.jstips.co/en/javascript/using-json-stringify/)
- 39 - [Advanced Properties](http://www.jstips.co/en/javascript/advanced-properties/)
- 38 - [Flattening multidimensional Arrays](http://www.jstips.co/en/javascript/flattening-multidimensional-arrays-in-javascript/)
- 37 - [Deduplicate an Array](http://www.jstips.co/en/javascript/deduplicate-an-array/)
- 36 - [Observe DOM changes in extensions](http://www.jstips.co/en/javascript/observe-dom-changes/)
- 35 - [Assignment Operators](http://www.jstips.co/en/javascript/assignment-shorthands/)
- 34 - [Implementing asynchronous loop](http://www.jstips.co/en/javascript/implementing-asynchronous-loops/)
- 33 - [Create Range 0...N easily using one line](http://www.jstips.co/en/javascript/create-range-0-n-easily-using-one-line/)
- 32 - [`Map()` to the rescue: adding order to Object properties](http://www.jstips.co/en/javascript/map-to-the-rescue-adding-order-to-object-properties/)
- 31 - [Avoid modifying or passing `arguments` into other functions — it kills optimization](http://www.jstips.co/en/javascript/avoid-modifying-or-passing-arguments-into-other-functions-it-kills-optimization/)
- 30 - [Converting truthy/falsy values to boolean](http://www.jstips.co/en/javascript/converting-truthy-falsy-values-to-boolean/)
- 29 - [Speed up recursive functions with memoization](http://www.jstips.co/en/javascript/speed-up-recursive-functions-with-memoization/)
- 28 - [Currying vs partial application](http://www.jstips.co/en/javascript/curry-vs-partial-application/)
- 27 - [Short circuit evaluation](http://www.jstips.co/en/javascript/short-circuit-evaluation-in-js/)
- 26 - [Filtering and sorting a list of Strings](http://www.jstips.co/en/javascript/filtering-and-sorting-a-list-of-strings/)
- 25 - [Using immediately invoked function expression](http://www.jstips.co/en/javascript/Using-immediately-invoked-function-expression/)
- 24 - [Use `===` instead of `==`](http://www.jstips.co/en/javascript/use_===_instead_of_==/)
- 23 - [Converting to number fast way](http://www.jstips.co/en/javascript/converting-to-number-fast-way/)
- 22 - [Empty an Array](http://www.jstips.co/en/javascript/two-ways-to-empty-an-array/)
- 21 - [Shuffle an Array](http://www.jstips.co/en/javascript/shuffle-an-array/)
- 20 - [Return objects to enable chaining of functions](http://www.jstips.co/en/javascript/return-objects-to-enable-chaining-of-functions/)
- 19 - [Safe String concatenation](http://www.jstips.co/en/javascript/safe-string-concatenation/)
- 18 - [Truncating the fast (but risky) way](http://www.jstips.co/en/javascript/rounding-the-fast-way/)
- 17 - [Node.js: Run a module if it is not "required"](http://www.jstips.co/en/javascript/nodejs-run-a-module-if-it-is-not-required/)
- 16 - [Passing arguments to callback functions](http://www.jstips.co/en/javascript/passing-arguments-to-callback-functions/)
- 15 - [Even simpler way of using `indexOf` as a contains clause](http://www.jstips.co/en/javascript/even-simpler-way-of-using-indexof-as-a-contains-clause/)
- 14 - [Fat Arrow Functions #ES6](http://www.jstips.co/en/javascript/fat-arrow-functions/)
- 13 - [Measure performance of a code block](http://www.jstips.co/en/javascript/tip-to-measure-performance-of-a-javascript-block/)
- 12 - [Pseudomandatory parameters in ES6 functions #ES6](http://www.jstips.co/en/javascript/pseudomandatory-parameters-in-es6-functions/)
- 11 - [Hoisting](http://www.jstips.co/en/javascript/hoisting/)
- 10 - [Check if a property is in an Object](http://www.jstips.co/en/javascript/check-if-a-property-is-in-a-object/)
- 09 - [Template Strings](http://www.jstips.co/en/javascript/template-strings/)
- 08 - [Converting a Node List to an Array](http://www.jstips.co/en/javascript/converting-a-node-list-to-an-array/)
- 07 - ["use strict" and get lazy](http://www.jstips.co/en/javascript/use-strict-and-get-lazy/)
- 06 - [Writing a single method for arrays and a single element](http://www.jstips.co/en/javascript/writing-a-single-method-for-arrays-and-a-single-element/)
- 05 - [Differences between `undefined` and `null`](http://www.jstips.co/en/javascript/differences-between-undefined-and-null/)
- 04 - [Sorting Strings with accented characters](http://www.jstips.co/en/javascript/sorting-strings-with-accented-characters/)
- 03 - [Improve Nested Conditionals](http://www.jstips.co/en/javascript/improve-nested-conditionals/)
- 02 - [ReactJS - Keys in children components are important](http://www.jstips.co/en/react/keys-in-children-components-are-important/)
- 01 - [AngularJS: `$digest` vs `$apply`](http://www.jstips.co/en/angular/angularjs-digest-vs-apply/)
- 00 - [Insert item inside an Array](http://www.jstips.co/en/javascript/insert-item-inside-an-array/)
### License
[GNU GENERAL PUBLIC LICENSE](https://github.com/loverajoel/jstips/blob/master/LICENSE.md)
================================================
FILE: _posts/en/angular/2016-01-01-angularjs-digest-vs-apply.md
================================================
---
layout: post
title: AngularJs - `$digest` vs `$apply`
tip-number: 01
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: JavaScript modules and build steps are getting more numerous and complicated, but what about boilerplate in new frameworks?
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /en/angularjs-digest-vs-apply/
categories:
- en
- angular
---
One of the most appreciated features of AngularJs is the two-way data binding. In order to make this work AngularJs evaluates the changes between the model and the view through cycles(`$digest`). You need to understand this concept in order to understand how the framework works under the hood.
Angular evaluates each watcher whenever one event is fired. This is the known `$digest` cycle.
Sometimes you have to force it to run a new cycle manually and you must choose the correct option because this phase is one of the most influential in terms of performance.
### `$apply`
This core method lets you to start the digestion cycle explicitly. That means that all watchers are checked; the entire application starts the `$digest loop`. Internally, after executing an optional function parameter, it calls `$rootScope.$digest();`.
### `$digest`
In this case the `$digest` method starts the `$digest` cycle for the current scope and its children. You should notice that the parent's scopes will not be checked.
and not be affected.
### Recommendations
- Use `$apply` or `$digest` only when browser DOM events have triggered outside of AngularJS.
- Pass a function expression to `$apply`, this has an error handling mechanism and allows integrating changes in the digest cycle.
```javascript
$scope.$apply(() => {
$scope.tip = 'Javascript Tip';
});
```
- If you only need to update the current scope or its children, use `$digest`, and prevent a new digest cycle for the whole application. The performance benefit is self-evident.
- `$apply()` is a hard process for the machine and can lead to performance issues when there is a lot of binding.
- If you are using >AngularJS 1.2.X, use `$evalAsync`, which is a core method that will evaluate the expression during the current cycle or the next. This can improve your application's performance
================================================
FILE: _posts/en/angular/2017-03-07-preventing-unwanted-scopes-creation-in-angularjs.md
================================================
---
layout: post
title: Preventing Unwanted Scopes Creation in AngularJs
tip-number: 62
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: In this tip I am going to show how to pass data between scopes preventing unwanted scopes created by `ng-repeat` and `ng-if`
tip-writer-support: https://www.coinbase.com/loverajoel
categories:
- en
- angular
---
One of the most appreciated features of AngularJs is thUnderstanding and preventing ```ng-model``` data scope is one of the main challenge you get quite often.
While working with ```ng-model``` data, new unwanted scope can be created by ```ng-repeat``` or ```ng-if``` procedures.
Take a look on following example-
```js
innerScope:{{data}}
outerScope:{{data}}
```
In the above example, ```innerScope``` inherits from ```outerScope``` and pass the value in ```outerScope```.
If you input a value in ```innerScope``` it will reflect in ```outerScope```. But if you edit ```outerScope```,
```innerScope``` doesn’t reflect the same value as ```outerScope``` because ```innerScope``` creates its own field
so no longer inherits from ```outerScope```.
To prevent this to happen we can use “Controller As” approach instead of using scope as a container
for all data and functions. But one more catchy solution is to keep everything in objects as shown is below example-
```js
inner scope:{{data.text}}
outer scope:{{data.text}}
```
Now ```innerScope``` is no longer creates a new field and editing value in either ```innerScope``` or ```outerScope``` will
reflect in both ```innerScope``` and ```outerScope```.
================================================
FILE: _posts/en/javascript/2015-12-29-insert-item-inside-an-array.md
================================================
---
layout: post
title: Insert item inside an Array
tip-number: 00
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: Inserting an item into an existing array is a daily common task. You can add elements to the end of an array using push, to the beginning using unshift, or to the middle using splice.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /en/insert-item-inside-an-array/
categories:
- en
- javascript
---
# Inserting an item into an existing array
Inserting an item into an existing array is a daily common task. You can add elements to the end of an array using push, to the beginning using unshift, or to the middle using splice.
Those are known methods, but it doesn't mean there isn't a more performant way. Here we go:
## Adding an element at the end
Adding an element at the end of the array is easy with push(), but it can be done in different ways.
```javascript
var arr = [1,2,3,4,5];
var arr2 = [];
arr.push(6);
arr[arr.length] = 6;
arr2 = arr.concat([6]);
```
Both first methods modify the original array. Don't believe me? Check the [jsperf](http://jsperf.com/push-item-inside-an-array)
### Performance on mobile :
#### Android (v4.2.2)
1. _arr.push(6);_ and _arr[arr.length] = 6;_ have the same performance // 3 319 694 ops/sec
3. _arr2 = arr.concat([6]);_ 50.61 % slower than the other two methods
#### Chrome Mobile (v33.0.0)
1. _arr[arr.length] = 6;_ // 6 125 975 ops/sec
2. _arr.push(6);_ 66.74 % slower
3. _arr2 = arr.concat([6]);_ 87.63 % slower
#### Safari Mobile (v9)
1. _arr[arr.length] = 6;_ // 7 452 898 ops/sec
2. _arr.push(6);_ 40.19 % slower
3. _arr2 = arr.concat([6]);_ 49.78 % slower
```javascript
Final victor
1. arr[arr.length] = 6; // with an average of 5 632 856 ops/sec
2. arr.push(6); // 35.64 % slower
3. arr2 = arr.concat([6]); // 62.67 % slower
```
### Performance on desktop
#### Chrome (v48.0.2564)
1. _arr[arr.length] = 6;_ // 21 602 722 ops/sec
2. _arr.push(6);_ 61.94 % slower
3. _arr2 = arr.concat([6]);_ 87.45 % slower
#### Firefox (v44)
1. _arr.push(6);_ // 56 032 805 ops/sec
2. _arr[arr.length] = 6;_ 0.52 % slower
3. _arr2 = arr.concat([6]);_ 87.36 % slower
#### IE (v11)
1. _arr[arr.length] = 6;_ // 67 197 046 ops/sec
2. _arr.push(6);_ 39.61 % slower
3. _arr2 = arr.concat([6]);_ 93.41 % slower
#### Opera (v35.0.2066.68)
1. _arr[arr.length] = 6;_ // 30 775 071 ops/sec
2. _arr.push(6);_ 71.60 % slower
3. _arr2 = arr.concat([6]);_ 83.70 % slower
#### Safari (v9.0.3)
1. _arr.push(6);_ // 42 670 978 ops/sec
2. _arr[arr.length] = 6;_ 0.80 % slower
3. _arr2 = arr.concat([6]);_ 76.07 % slower
```javascript
Final victor
1. arr[arr.length] = 6; // with an average of 42 345 449 ops/sec
2. arr.push(6); // 34.66 % slower
3. arr2 = arr.concat([6]); // 85.79 % slower
```
## Add an element at the beginning
Now if we are trying to add an item to the beginning of the array:
```javascript
var arr = [1,2,3,4,5];
arr.unshift(0);
[0].concat(arr);
```
Here is a little more detail: unshift edits the original array; concat returns a new array. [jsperf](http://jsperf.com/unshift-item-inside-an-array)
### Performance on mobile :
#### Android (v4.2.2)
1. _[0].concat(arr);_ // 1 808 717 ops/sec
2. _arr.unshift(0);_ 97.85 % slower
#### Chrome Mobile (v33.0.0)
1. _[0].concat(arr);_ // 1 269 498 ops/sec
2. _arr.unshift(0);_ 99.86 % slower
#### Safari Mobile (v9)
1. _arr.unshift(0);_ // 3 250 184 ops/sec
2. _[0].concat(arr);_ 33.67 % slower
```javascript
Final victor
1. [0].concat(arr); // with an average of 4 972 622 ops/sec
2. arr.unshift(0); // 64.70 % slower
```
### Performance on desktop
#### Chrome (v48.0.2564)
1. _[0].concat(arr);_ // 2 656 685 ops/sec
2. _arr.unshift(0);_ 96.77 % slower
#### Firefox (v44)
1. _[0].concat(arr);_ // 8 039 759 ops/sec
2. _arr.unshift(0);_ 99.72 % slower
#### IE (v11)
1. _[0].concat(arr);_ // 3 604 226 ops/sec
2. _arr.unshift(0);_ 98.31 % slower
#### Opera (v35.0.2066.68)
1. _[0].concat(arr);_ // 4 102 128 ops/sec
2. _arr.unshift(0);_ 97.44 % slower
#### Safari (v9.0.3)
1. _arr.unshift(0);_ // 12 356 477 ops/sec
2. _[0].concat(arr);_ 15.17 % slower
```javascript
Final victor
1. [0].concat(arr); // with an average of 6 032 573 ops/sec
2. arr.unshift(0); // 78.65 % slower
```
## Add an element in the middle
Adding items in the middle of an array is easy with splice, and it's the most performant way to do it.
```javascript
var items = ['one', 'two', 'three', 'four'];
items.splice(items.length / 2, 0, 'hello');
```
I tried to run these tests in various Browsers and OS and the results were similar. I hope these tips will be useful for you and encourage to perform your own tests!
================================================
FILE: _posts/en/javascript/2016-01-03-improve-nested-conditionals.md
================================================
---
layout: post
title: Improve Nested Conditionals
tip-number: 03
tip-username: AlbertoFuente
tip-username-profile: https://github.com/AlbertoFuente
tip-tldr: How can we improve and make a more efficient nested `if` statement in javascript?
redirect_from:
- /en/improve-nested-conditionals/
categories:
- en
- javascript
---
How can we improve and make a more efficient nested `if` statement in javascript?
```javascript
if (color) {
if (color === 'black') {
printBlackBackground();
} else if (color === 'red') {
printRedBackground();
} else if (color === 'blue') {
printBlueBackground();
} else if (color === 'green') {
printGreenBackground();
} else {
printYellowBackground();
}
}
```
One way to improve the nested `if` statement would be using the `switch` statement. Although it is less verbose and is more ordered, it's not recommended to use it because it's so difficult to debug errors. Here's [why](https://toddmotto.com/deprecating-the-switch-statement-for-object-literals).
```javascript
switch(color) {
case 'black':
printBlackBackground();
break;
case 'red':
printRedBackground();
break;
case 'blue':
printBlueBackground();
break;
case 'green':
printGreenBackground();
break;
default:
printYellowBackground();
}
```
But what if we have a conditional with several checks in each statement? In this case, if we want it less verbose and more ordered, we can use the conditional `switch`.
If we pass `true` as a parameter to the `switch` statement, it allows us to put a conditional in each case.
```javascript
switch(true) {
case (typeof color === 'string' && color === 'black'):
printBlackBackground();
break;
case (typeof color === 'string' && color === 'red'):
printRedBackground();
break;
case (typeof color === 'string' && color === 'blue'):
printBlueBackground();
break;
case (typeof color === 'string' && color === 'green'):
printGreenBackground();
break;
case (typeof color === 'string' && color === 'yellow'):
printYellowBackground();
break;
}
```
If refactoring is an option, we can try to simplify the functions themselves. For example instead of having a function for each background color we could have an function that takes the color as an argument.
```javascript
function printBackground(color) {
if (!color || typeof color !== 'string') {
return; // Invalid color, return immediately
}
}
```
But if refactoring is not an option, we must always avoid having several checks in every condition and avoid using `switch` as much as possible. We also must take into account that the most efficient way to do this is through an `object`.
```javascript
var colorObj = {
'black': printBlackBackground,
'red': printRedBackground,
'blue': printBlueBackground,
'green': printGreenBackground,
'yellow': printYellowBackground
};
if (color in colorObj) {
colorObj[color]();
}
```
Here you can find more information about [this](http://www.nicoespeon.com/en/2015/01/oop-revisited-switch-in-js/).
================================================
FILE: _posts/en/javascript/2016-01-04-sorting-strings-with-accented-characters.md
================================================
---
layout: post
title: Sorting strings with accented characters
tip-number: 04
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: Javascript has a native method **sort** that allows sorting arrays. Doing a simple `array.sort()` will treat each array entry as a string and sort it alphabetically. But when you try order an array of non ASCII characters you will obtain a strange result.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /en/sorting-strings-with-accented-characters/
categories:
- en
- javascript
---
Javascript has a native method **[sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)** that allows sorting arrays. Doing a simple `array.sort()` will treat each array entry as a string and sort it alphabetically. Also you can provide your [own custom sorting](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Parameters) function.
```javascript
['Shanghai', 'New York', 'Mumbai', 'Buenos Aires'].sort();
// ["Buenos Aires", "Mumbai", "New York", "Shanghai"]
```
But when you try order an array of non ASCII characters like this `['é', 'a', 'ú', 'c']`, you will obtain a strange result `['c', 'e', 'á', 'ú']`. That happens because sort works only with the English language.
See the next example:
```javascript
// Spanish
['único','árbol', 'cosas', 'fútbol'].sort();
// ["cosas", "fútbol", "árbol", "único"] // bad order
// German
['Woche', 'wöchentlich', 'wäre', 'Wann'].sort();
// ["Wann", "Woche", "wäre", "wöchentlich"] // bad order
```
Fortunately, there are two ways to overcome this behavior [localeCompare](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare) and [Intl.Collator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Collator) provided by ECMAScript Internationalization API.
> Both methods have their own custom parameters in order to configure it to work adequately.
### Using `localeCompare()`
```javascript
['único','árbol', 'cosas', 'fútbol'].sort(function (a, b) {
return a.localeCompare(b);
});
// ["árbol", "cosas", "fútbol", "único"]
['Woche', 'wöchentlich', 'wäre', 'Wann'].sort(function (a, b) {
return a.localeCompare(b);
});
// ["Wann", "wäre", "Woche", "wöchentlich"]
```
### Using `Intl.Collator()`
```javascript
['único','árbol', 'cosas', 'fútbol'].sort(Intl.Collator().compare);
// ["árbol", "cosas", "fútbol", "único"]
['Woche', 'wöchentlich', 'wäre', 'Wann'].sort(Intl.Collator().compare);
// ["Wann", "wäre", "Woche", "wöchentlich"]
```
- For each method you can customize the location.
- According to [Firefox](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare#Performance) Intl.Collator is faster when comparing large numbers of strings.
So when you are working with arrays of strings in a language other than English, remember to use this method to avoid unexpected sorting.
================================================
FILE: _posts/en/javascript/2016-01-05-differences-between-undefined-and-null.md
================================================
---
layout: post
title: Differences between `undefined` and `null`
tip-number: 05
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: Understanding the differences between `undefined` and `null`.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /en/differences-between-undefined-and-null/
categories:
- en
- javascript
---
- `undefined` means a variable has not been declared, or has been declared but has not yet been assigned a value
- `null` is an assignment value that means "no value"
- Javascript sets unassigned variables with a default value of `undefined`
- Javascript never sets a value to `null`. It is used by programmers to indicate that a `var` has no value.
- `undefined` is not valid in JSON while `null` is
- `undefined` typeof is `undefined`
- `null` typeof is an `object`. [Why?](http://www.2ality.com/2013/10/typeof-null.html)
- Both are primitives
- Both are [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy)
(`Boolean(undefined) // false`, `Boolean(null) // false`)
- You can know if a variable is [undefined](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined)
```javascript
typeof variable === "undefined"
```
- You can check if a variable is [null](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null)
```javascript
variable === null
```
- The **equality** operator considers them equal, but the **identity** doesn't
```javascript
null == undefined // true
null === undefined // false
```
================================================
FILE: _posts/en/javascript/2016-01-06-writing-a-single-method-for-arrays-and-a-single-element.md
================================================
---
layout: post
title: Writing a single method for arrays and a single element
tip-number: 06
tip-username: mattfxyz
tip-username-profile: https://twitter.com/mattfxyz
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).
redirect_from:
- /en/writing-a-single-method-for-arrays-and-a-single-element/
categories:
- en
- javascript
---
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).
You just have to concat everything into an array first. `Array.concat` will accept an array or a single element.
```javascript
function printUpperCase(words) {
var elements = [].concat(words || []);
for (var i = 0; i < elements.length; i++) {
console.log(elements[i].toUpperCase());
}
}
```
`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.
```javascript
printUpperCase("cactus");
// => CACTUS
printUpperCase(["cactus", "bear", "potato"]);
// => CACTUS
// BEAR
// POTATO
```
================================================
FILE: _posts/en/javascript/2016-01-07-use-strict-and-get-lazy.md
================================================
---
layout: post
title: use strict and get lazy
tip-number: 07
tip-username: nainslie
tip-username-profile: https://twitter.com/nat5an
tip-tldr: Strict-mode JavaScript makes it easier for the developer to write "secure" JavaScript.
redirect_from:
- /en/use-strict-and-get-lazy/
categories:
- en
- javascript
---
Strict-mode JavaScript makes it easier for the developer to write "secure" JavaScript.
By default, JavaScript allows the programmer to be pretty careless, for example, by not requiring us to declare our variables with "var" when we first introduce them. While this may seem like a convenience to the unseasoned developer, it's also the source of many errors when a variable name is misspelled or accidentally referred to out of its scope.
Programmers like to make the computer do the boring stuff for us, and automatically check our work for mistakes. That's what the JavaScript "use strict" directive allows us to do, by turning our mistakes into JavaScript errors.
We add this directive either by adding it at the top of a js file:
```javascript
// Whole-script strict mode syntax
"use strict";
var v = "Hi! I'm a strict mode script!";
```
or inside a function:
```javascript
function f()
{
// Function-level strict mode syntax
'use strict';
function nested() { return "And so am I!"; }
return "Hi! I'm a strict mode function! " + nested();
}
function f2() { return "I'm not strict."; }
```
By including this directive in a JavaScript file or function, we will direct the JavaScript engine to execute in strict mode which disables a bunch of behaviors that are usually undesirable in larger JavaScript projects. Among other things, strict mode changes the following behaviors:
* Variables can only be introduced when they are preceded with "var"
* Attempting to write to read-only properties generates a noisy error
* You have to call constructors with the "new" keyword
* "this" is not implicitly bound to the global object
* Very limited use of eval() allowed
* Protects you from using reserved words or future reserved words as variable names
Strict mode is great for new projects, but can be challenging to introduce into older projects that don't already use it in most places. It also can be problematic if your build chain concatenates all your js files into one big file, as this may cause all files to execute in strict mode.
It is not a statement, but a literal expression, ignored by earlier versions of JavaScript.
Strict mode is supported in:
* Internet Explorer from version 10.
* Firefox from version 4.
* Chrome from version 13.
* Safari from version 5.1.
* Opera from version 12.
[See MDN for a fuller description of strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode).
================================================
FILE: _posts/en/javascript/2016-01-08-converting-a-node-list-to-an-array.md
================================================
---
layout: post
title: Converting a Node List to an Array
tip-number: 08
tip-username: Tevko
tip-username-profile: https://twitter.com/tevko
tip-tldr: Here's a quick, safe, and reusable way to convert a node list into an array of DOM elements.
redirect_from:
- /en/converting-a-node-list-to-an-array/
categories:
- en
- javascript
---
The `querySelectorAll` method returns an array-like object called a node list. These data structures are referred to as "Array-like", because they appear as an array, but can not be used with array methods like `map` and `forEach`. Here's a quick, safe, and reusable way to convert a node list into an array of DOM elements:
```javascript
const nodelist = document.querySelectorAll('div');
const nodelistToArray = Array.apply(null, nodelist);
//later on ..
nodelistToArray.forEach(...);
nodelistToArray.map(...);
nodelistToArray.slice(...);
//etc...
```
The `apply` method is used to pass an array of arguments to a function with a given `this` value. [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) states that `apply` will take an array-like object, which is exactly what `querySelectorAll` returns. Since we don't need to specify a value for `this` in the context of the function, we pass in `null` or `0`. The result is an actual array of DOM elements which contains all of the available array methods.
Alternatively you can use `Array.prototype.slice` combined with `Function.prototype.call` or `Function.prototype.apply` passing the array-like object as the value of `this`:
```javascript
const nodelist = document.querySelectorAll('div');
const nodelistToArray = Array.prototype.slice.call(nodelist); // or equivalently Array.prototype.slice.apply(nodelist);
//later on ..
nodelistToArray.forEach(...);
nodelistToArray.map(...);
nodelistToArray.slice(...);
//etc...
```
Or if you are using ES2015 you can use the [spread operator `...`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator)
```js
const nodelist = [...document.querySelectorAll('div')]; // returns a real array
//later on ..
nodelist.forEach(...);
nodelist.map(...);
nodelist.slice(...);
//etc...
```
================================================
FILE: _posts/en/javascript/2016-01-09-template-strings.md
================================================
---
layout: post
title: Template Strings
tip-number: 09
tip-username: JakeRawr
tip-username-profile: https://github.com/JakeRawr
tip-tldr: As of ES6, JS now has template strings as an alternative to the classic end quotes strings.
redirect_from:
- /en/template-strings/
categories:
- en
- javascript
---
As of ES6, JS now has template strings as an alternative to the classic end quotes strings.
Ex:
Normal string
```javascript
var firstName = 'Jake';
var lastName = 'Rawr';
console.log('My name is ' + firstName + ' ' + lastName);
// My name is Jake Rawr
```
Template String
```javascript
var firstName = 'Jake';
var lastName = 'Rawr';
console.log(`My name is ${firstName} ${lastName}`);
// My name is Jake Rawr
```
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.
```javascript
var val1 = 1, val2 = 2;
console.log(`${val1} is ${val1 < val2 ? 'less than': 'greater than'} ${val2}`)
// 1 is less than 2
```
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.
You may also want to [read](https://hacks.mozilla.org/2015/05/es6-in-depth-template-strings-2) to understand template strings more.
================================================
FILE: _posts/en/javascript/2016-01-10-check-if-a-property-is-in-a-object.md
================================================
---
layout: post
title: Check if a property is in a Object
tip-number: 10
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: These are ways to check if a property is present in an object.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /en/check-if-a-property-is-in-a-object/
categories:
- en
- javascript
---
When you have to check if a property is present in an [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects), you probably are doing something like this:
```javascript
var myObject = {
name: '@tips_js'
};
if (myObject.name) { ... }
```
That's ok, but you have to know that there are two native ways for this kind of thing, the [`in` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in) and [`Object.hasOwnProperty`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty). Every object descended from `Object`, has both ways available.
### See the big Difference
```javascript
var myObject = {
name: '@tips_js'
};
myObject.hasOwnProperty('name'); // true
'name' in myObject; // true
myObject.hasOwnProperty('valueOf'); // false, valueOf is inherited from the prototype chain
'valueOf' in myObject; // true
```
Both differ in the depth at which they check the properties. In other words, `hasOwnProperty` will only return true if key is available on that object directly. However, the `in` operator doesn't discriminate between properties created on an object and properties inherited from the prototype chain.
Here's another example:
```javascript
var myFunc = function() {
this.name = '@tips_js';
};
myFunc.prototype.age = '10 days';
var user = new myFunc();
user.hasOwnProperty('name'); // true
user.hasOwnProperty('age'); // false, because age is from the prototype chain
```
Check the [live examples here](https://jsbin.com/tecoqa/edit?js,console)!
I also recommend reading [this discussion](https://github.com/loverajoel/jstips/issues/62) about common mistakes made when checking a property's existence in objects.
================================================
FILE: _posts/en/javascript/2016-01-11-hoisting.md
================================================
---
layout: post
title: Hoisting
tip-number: 11
tip-username: squizzleflip
tip-username-profile: https://twitter.com/squizzleflip
tip-tldr: Understanding hoisting will help you organize your function scope.
redirect_from:
- /en/hoisting/
categories:
- en
- javascript
---
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.
```javascript
function doTheThing() {
// ReferenceError: notDeclared is not defined
console.log(notDeclared);
// Outputs: undefined
console.log(definedLater);
var definedLater;
definedLater = 'I am defined!'
// Outputs: 'I am defined!'
console.log(definedLater)
// Outputs: undefined
console.log(definedSimulateneously);
var definedSimulateneously = 'I am defined!'
// Outputs: 'I am defined!'
console.log(definedSimulateneously)
// Outputs: 'I did it!'
doSomethingElse();
function doSomethingElse(){
console.log('I did it!');
}
// TypeError: undefined is not a function
functionVar();
var functionVar = function(){
console.log('I did it!');
}
}
```
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.
================================================
FILE: _posts/en/javascript/2016-01-12-pseudomandatory-parameters-in-es6-functions.md
================================================
---
layout: post
title: Pseudomandatory parameters in ES6 functions
tip-number: 12
tip-username: Avraam Mavridis
tip-username-profile: https://github.com/AvraamMavridis
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.
redirect_from:
- /en/pseudomandatory-parameters-in-es6-functions/
categories:
- en
- javascript
---
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.
```javascript
const _err = function( message ){
throw new Error( message );
}
const getSum = (a = _err('a is not defined'), b = _err('b is not defined')) => a + b
getSum( 10 ) // throws Error, b is not defined
getSum( undefined, 10 ) // throws Error, a is not defined
```
`_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)
================================================
FILE: _posts/en/javascript/2016-01-13-tip-to-measure-performance-of-a-javascript-block.md
================================================
---
layout: post
title: Tip to measure performance of a javascript block
tip-number: 13
tip-username: manmadareddy
tip-username-profile: https://twitter.com/manmadareddy
tip-tldr: For quickly measuring performance of a javascript block, we can use the console functions like `console.time(label)` and `console.timeEnd(label)`
redirect_from:
- /en/tip-to-measure-performance-of-a-javascript-block/
categories:
- en
- javascript
---
For quickly measuring performance of a javascript block, we can use the console functions like
[`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)
```javascript
console.time("Array initialize");
var arr = new Array(100),
len = arr.length,
i;
for (i = 0; i < len; i++) {
arr[i] = new Object();
};
console.timeEnd("Array initialize"); // Outputs: Array initialize: 0.711ms
```
More info:
[Console object](https://github.com/DeveloperToolsWG/console-object),
[Javascript benchmarking](https://mathiasbynens.be/notes/javascript-benchmarking)
Demo: [jsfiddle](https://jsfiddle.net/meottb62/) - [codepen](http://codepen.io/anon/pen/JGJPoa) (outputs in browser console)
> 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.
================================================
FILE: _posts/en/javascript/2016-01-14-fat-arrow-functions.md
================================================
---
layout: post
title: Fat Arrow Functions
tip-number: 14
tip-username: pklinger
tip-username-profile: https://github.com/pklinger/
tip-tldr: Introduced as a new feature in ES6, fat arrow functions may come as a handy tool to write more code in fewer lines
redirect_from:
- /en/fat-arrow-functions/
categories:
- en
- javascript
---
Introduced as a new feature in ES6, fat arrow functions may come as a handy tool to write more code in fewer lines. The name comes from its syntax, `=>`, which is a 'fat arrow', as compared to a thin arrow `->`. Some programmers might already know this type of function from different languages such as Haskell, as 'lambda expressions', or as 'anonymous functions'. It is called anonymous, as these arrow functions do not have a descriptive function name.
### What are the benefits?
* Syntax: fewer LOC; no more typing `function` keyword over and over again
* Semantics: capturing the keyword `this` from the surrounding context
### Simple syntax example
Have a look at these two code snippets, which do the exact same job, and you will quickly understand what fat arrow functions do:
```javascript
// general syntax for fat arrow functions
param => expression
// may also be written with parentheses
// parentheses are required on multiple params
(param1 [, param2]) => expression
// using functions
var arr = [5,3,2,9,1];
var arrFunc = arr.map(function(x) {
return x * x;
});
console.log(arr)
// using fat arrow
var arr = [5,3,2,9,1];
var arrFunc = arr.map((x) => x*x);
console.log(arr)
```
As you can see, the fat arrow function in this case can save you time typing out the parentheses as well as the function and return keywords. I would advise you to always write parentheses around the parameter inputs, as the parentheses will be needed for multiple input parameters, such as in `(x,y) => x+y`. It is just a way to cope with forgetting them in different use cases. But the code above would also work like this: `x => x*x`. So far, these are only syntactical improvements, which lead to fewer LOC and better readability.
### Lexically binding `this`
There is another good reason to use fat arrow functions. There is the issue with the context of `this`. With arrow functions, you don't need to worry about `.bind(this)` or setting `that = this` anymore, as fat arrow functions pick the context of `this` from the lexical surrounding. Have a look at the next [example] (https://jsfiddle.net/pklinger/rw94oc11/):
```javascript
// globally defined this.i
this.i = 100;
var counterA = new CounterA();
var counterB = new CounterB();
var counterC = new CounterC();
var counterD = new CounterD();
// bad example
function CounterA() {
// CounterA's `this` instance (!! gets ignored here)
this.i = 0;
setInterval(function () {
// `this` refers to global object, not to CounterA's `this`
// therefore starts counting with 100, not with 0 (local this.i)
this.i++;
document.getElementById("counterA").innerHTML = this.i;
}, 500);
}
// manually binding that = this
function CounterB() {
this.i = 0;
var that = this;
setInterval(function() {
that.i++;
document.getElementById("counterB").innerHTML = that.i;
}, 500);
}
// using .bind(this)
function CounterC() {
this.i = 0;
setInterval(function() {
this.i++;
document.getElementById("counterC").innerHTML = this.i;
}.bind(this), 500);
}
// fat arrow function
function CounterD() {
this.i = 0;
setInterval(() => {
this.i++;
document.getElementById("counterD").innerHTML = this.i;
}, 500);
}
```
Further information about fat arrow functions may be found at [MDN] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions). To see different syntax options visit [this site] (http://jsrocks.org/2014/10/arrow-functions-and-their-scope/).
================================================
FILE: _posts/en/javascript/2016-01-15-even-simpler-way-of-using-indexof-as-a-contains-clause.md
================================================
---
layout: post
title: Even simpler way of using `indexOf` as a contains clause
tip-number: 15
tip-username: jhogoforbroke
tip-username-profile: https://twitter.com/jhogoforbroke
tip-tldr: JavaScript by default does not have a contains method. And for checking existence of a substring in a string or an item in an array you may do this.
redirect_from:
- /en/even-simpler-way-of-using-indexof-as-a-contains-clause/
categories:
- en
- javascript
---
JavaScript by default does not have a contains method. And for checking existence of a substring in a string or an item in an array you may do this:
```javascript
var someText = 'javascript rules';
if (someText.indexOf('javascript') !== -1) {
}
// or
if (someText.indexOf('javascript') >= 0) {
}
```
But let's look at these [Expressjs](https://github.com/strongloop/express) code snippets.
[examples/mvc/lib/boot.js](https://github.com/strongloop/express/blob/2f8ac6726fa20ab5b4a05c112c886752868ac8ce/examples/mvc/lib/boot.js#L26)
```javascript
for (var key in obj) {
// "reserved" exports
if (~['name', 'prefix', 'engine', 'before'].indexOf(key)) continue;
```
[lib/utils.js](https://github.com/strongloop/express/blob/2f8ac6726fa20ab5b4a05c112c886752868ac8ce/lib/utils.js#L93)
```javascript
exports.normalizeType = function(type){
return ~type.indexOf('/')
? acceptParams(type)
: { value: mime.lookup(type), params: {} };
};
```
[examples/web-service/index.js](https://github.com/strongloop/express/blob/2f8ac6726fa20ab5b4a05c112c886752868ac8ce/examples/web-service/index.js#L35)
```javascript
// key is invalid
if (!~apiKeys.indexOf(key)) return next(error(401, 'invalid api key'));
```
The gotcha is the [bitwise operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) **~**, "Bitwise operators perform their operations on binary representations, but they return standard JavaScript numerical values."
It transforms `-1` into `0`, and `0` evaluates to `false` in JavaScript:
```javascript
var someText = 'text';
!!~someText.indexOf('tex'); // someText contains "tex" - true
!~someText.indexOf('tex'); // someText NOT contains "tex" - false
~someText.indexOf('asd'); // someText doesn't contain "asd" - false
~someText.indexOf('ext'); // someText contains "ext" - true
```
### String.prototype.includes()
ES6 introduced the [includes() method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes) and you can use it to determine whether or not a string includes another string:
```javascript
'something'.includes('thing'); // true
```
With ECMAScript 2016 (ES7) it is even possible to use these techniques with Arrays:
```javascript
!!~[1, 2, 3].indexOf(1); // true
[1, 2, 3].includes(1); // true
```
**Unfortunately, it is only supported in Chrome, Firefox, Safari 9 or above and Edge; not IE11 or lower.**
**It's better used in controlled environments.**
================================================
FILE: _posts/en/javascript/2016-01-16-passing-arguments-to-callback-functions.md
================================================
---
layout: post
title: Passing arguments to callback functions
tip-number: 16
tip-username: minhazav
tip-username-profile: https://twitter.com/minhazav
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.
redirect_from:
- /en/passing-arguments-to-callback-functions/
categories:
- en
- javascript
---
By default you cannot pass arguments to a callback function. For example:
```js
function callback() {
console.log('Hi human');
}
document.getElementById('someelem').addEventListener('click', callback);
```
You can take advantage of the closure scope in Javascript to pass arguments to callback functions. Check this example:
```js
function callback(a, b) {
return function() {
console.log('sum = ', (a+b));
}
}
var x = 1, y = 2;
document.getElementById('someelem').addEventListener('click', callback(x, y));
```
### What are closures?
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.
So this way the arguments `x` and `y` are in scope of the callback function when it is called.
Another method to do this is using the `bind` method. For example:
```js
var alertText = function(text) {
alert(text);
};
document.getElementById('someelem').addEventListener('click', alertText.bind(this, 'hello'));
```
There is a very slight difference in performance of both methods, checkout [jsperf](http://jsperf.com/bind-vs-closure-23).
================================================
FILE: _posts/en/javascript/2016-01-17-nodejs-run-a-module-if-it-is-not-required.md
================================================
---
layout: post
title: Node.js - Run a module if it is not `required`
tip-number: 17
tip-username: odsdq
tip-username-profile: https://twitter.com/odsdq
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.
redirect_from:
- /en/nodejs-run-a-module-if-it-is-not-required/
categories:
- en
- javascript
---
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.
```js
if (!module.parent) {
// ran with `node something.js`
app.listen(8088, function() {
console.log('app listening on port 8088');
})
} else {
// used with `require('/.something.js')`
module.exports = app;
}
```
See [the documentation for modules](https://nodejs.org/api/modules.html#modules_module_parent) for more info.
================================================
FILE: _posts/en/javascript/2016-01-18-rounding-the-fast-way.md
================================================
---
layout: post
title: Truncating the fast (but risky) way
tip-number: 18
tip-username: pklinger
tip-username-profile: https://github.com/pklinger
tip-tldr: .`~~X` is usually a faster `Math.trunc(X)`, but can also make your code do nasty things.
redirect_from:
- /en/rounding-the-fast-way/
categories:
- en
- javascript
---
This tip is about performance...with a hidden price tag.
Have you ever come across the [double tilde `~~` operator](http://stackoverflow.com/questions/5971645/what-is-the-double-tilde-operator-in-javascript)? It's also often called the "double bitwise NOT" operator. You can often use it as a faster substitute for `Math.trunc()`. Why is that?
One bitwise shift `~` first truncates `input` to 32 bits, then transforms it into `-(input+1)`. The double bitwise shift therefore transforms the input into `-(-(input + 1)+1)` making it a great tool to round towards zero. For numeric input, it therefore mimics `Math.trunc()`. On failure, `0` is returned, which might come in handy sometimes instead of `Math.trunc()`, which returns `NaN` on failure.
```js
// single ~
console.log(~1337) // -1338
// numeric input
console.log(~~47.11) // -> 47
console.log(~~1.9999) // -> 1
console.log(~~3) // -> 3
```
However, while `~~` is probably a better performer, experienced programmers often stick with `Math.trunc()` instead. To understand why, here's a clinical view on this operator.
### INDICATIONS
##### When every CPU cycle counts
`~~` is probably faster than `Math.trunc()` across the board, though you should [test that assumption](https://jsperf.com/jsfvsbitnot/10) on whichever platforms matter to you. Also, you'd generally have to perform millions of such operations to have any visible impact at run time.
##### When code clarity is not a concern
If you're trying to confuse others, or get maximum utility from your minifier/uglifier, this is a relatively cheap way to do it.
### CONTRAINDICATIONS
##### When your code needs to be maintained
Code clarity is of great importance in the long term, whether you work in a team, contribute to public code repos, or fly solo. As [the oft-quoted saying](http://c2.com/cgi/wiki?CodeForTheMaintainer) goes:
> Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live.
For a solo programmer, that psychopath is inevitably "you in six months".
##### When you forget that `~~` always rounds to zero
Newbie programmers may fixate on the cleverness of `~~`, forgetting the significance of "just drop the fractional portion of this number". This can easily lead to **fencepost errors** (a.k.a. "off-by-one") when transforming floats to array indices or related ordinal values, where a different kind of fractional rounding may actually be called for. (Lack of code clarity usually contributes to this problem.)
For instance, if you're counting numbers on a "nearest integer" basis, you should use `Math.round()` instead of `~~`, but programmer laziness and the impact of **_10 whole characters saved per use_** on human fingers often triumph over cold logic, leading to incorrect results.
In contrast, the very names of the `Math.xyz()` functions clearly communicate their effect, reducing the probability of accidental errors.
##### When dealing with large-magnitude numbers
Because `~` first does a 32-bit conversion, `~~` results in bogus values around ±2.15 billion. If you don't properly range-check your input, a user could trigger unexpected behavior when the transformed value ends up being a great distance from the original:
```js
a = 2147483647.123 // maximum positive 32-bit integer, plus a bit more
console.log(~~a) // -> 2147483647 (ok)
a += 10000 // -> 2147493647.123 (ok)
console.log(~~a) // -> -2147483648 (huh?)
```
One particularly vulnerable area involves dealing with Unix epoch timestamps (measured in seconds from 1 Jan 1970 00:00:00 UTC). A quick way to get such values is:
```js
epoch_int = ~~(+new Date() / 1000) // Date() epochs in milliseconds, so we scale accordingly
```
However, when dealing with timestamps after 19 Jan 2038 03:14:07 UTC (sometimes called the **Y2038 limit**), this breaks horribly:
```js
// epoch timestamp for 1 Jan 2040 00:00:00.123 UTC
epoch = +new Date('2040-01-01') / 1000 + 0.123 // -> 2208988800.123
// back to the future!
epoch_int = ~~epoch // -> -2085978496
console.log(new Date(epoch_int * 1000)) // -> Wed Nov 25 1903 17:31:44 UTC
// that was fun, now let's get real
epoch_flr = Math.floor(epoch) // -> 2208988800
console.log(new Date(epoch_flr * 1000)) // -> Sun Jan 01 2040 00:00:00 UTC
```
##### When the original input wasn't sanitized
Because `~~` transforms every non-number into `0`:
```js
console.log(~~[]) // -> 0
console.log(~~NaN) // -> 0
console.log(~~null) // -> 0
```
some programmers treat it as alternative to proper input validation. However, this can lead to strange logic bugs down the line, since you're no longer distinguishing between invalid inputs and actual `0` values. This is therefore _not_ a recommended practice.
##### When so many people think `~~X == Math.floor(X)`
Most people who write about "double bitwise NOT" incorrectly equate it with `Math.floor()` for some reason. If you can't write about it accurately, odds are good you'll eventually misuse it.
Others are more careful to mention `Math.floor()` for positive inputs and `Math.ceil()` for negative ones, but that forces you to stop and think about the values you're dealing with. This defeats the purpose of `~~` as a handy no-gotchas shortcut.
### DOSAGE
Avoid where possible. Use sparingly otherwise.
### ADMINISTRATION
1. Apply cautiously.
2. Sanitize values before applying.
3. Carefully document relevant assumptions about the values being transformed.
4. Review code to deal with, at minimum:
* logic bugs where invalid inputs are instead passed to other code modules as valid `0` values
* range errors on transformed inputs
* fencepost errors due to incorrect rounding direction
================================================
FILE: _posts/en/javascript/2016-01-19-safe-string-concatenation.md
================================================
---
layout: post
title: Safe string concatenation
tip-number: 19
tip-username: gogainda
tip-username-profile: https://twitter.com/gogainda
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
redirect_from:
- /en/safe-string-concatenation/
categories:
- en
- javascript
---
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`:
```javascript
var one = 1;
var two = 2;
var three = '3';
var result = ''.concat(one, two, three); //"123"
```
This way of concatenting does exactly what you'd expect. In contrast, concatenation with pluses might lead to unexpected results:
```javascript
var one = 1;
var two = 2;
var three = '3';
var result = one + two + three; //"33" instead of "123"
```
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.
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).
================================================
FILE: _posts/en/javascript/2016-01-20-return-objects-to-enable-chaining-of-functions.md
================================================
---
layout: post
title: Return objects to enable chaining of functions
tip-number: 20
tip-username: WakeskaterX
tip-username-profile: https://twitter.com/WakeStudio
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.
redirect_from:
- /en/return-objects-to-enable-chaining-of-functions/
categories:
- en
- javascript
---
When creating functions on an object in Object Oriented Javascript, returning the object in the function will enable you to chain functions together.
```js
function Person(name) {
this.name = name;
this.sayName = function() {
console.log("Hello my name is: ", this.name);
return this;
};
this.changeName = function(name) {
this.name = name;
return this;
};
}
var person = new Person("John");
person.sayName().changeName("Timmy").sayName();
```
================================================
FILE: _posts/en/javascript/2016-01-21-shuffle-an-array.md
================================================
---
layout: post
title: Shuffle an Array
tip-number: 21
tip-username: 0xmtn
tip-username-profile: https://github.com/0xmtn/
tip-tldr: Fisher-Yates Shuffling it's an algorithm to shuffle an array.
redirect_from:
- /en/shuffle-an-array/
categories:
- en
- javascript
---
This snippet here uses [Fisher-Yates Shuffling](https://www.wikiwand.com/en/Fisher%E2%80%93Yates_shuffle) Algorithm to shuffle a given array.
```javascript
function shuffle(arr) {
var i,
j,
temp;
for (i = arr.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return arr;
};
```
An example:
```javascript
var a = [1, 2, 3, 4, 5, 6, 7, 8];
var b = shuffle(a);
console.log(b);
// [2, 7, 8, 6, 5, 3, 1, 4]
```
================================================
FILE: _posts/en/javascript/2016-01-22-two-ways-to-empty-an-array.md
================================================
---
layout: post
title: Two ways to empty an array
tip-number: 22
tip-username: microlv
tip-username-profile: https://github.com/microlv
tip-tldr: In JavaScript when you want to empty an array, there are a lot ways, but this is the most performant.
redirect_from:
- /en/two-ways-to-empty-an-array/
categories:
- en
- javascript
---
You define an array and want to empty its contents.
Usually, you would do it like this:
```javascript
// define Array
var list = [1, 2, 3, 4];
function empty() {
//empty your array
list = [];
}
empty();
```
But there is another way to empty an array that is more performant.
You should use code like this:
```javascript
var list = [1, 2, 3, 4];
function empty() {
//empty your array
list.length = 0;
}
empty();
```
* `list = []` assigns a reference to a new array to a variable, while any other references are unaffected.
which means that references to the contents of the previous array are still kept in memory, leading to memory leaks.
* `list.length = 0` deletes everything in the array, which does hit other references.
In other words, if you have two references to the same array (`a = [1,2,3]; a2 = a;`), and you delete the array's contents using `list.length = 0`, both references (a and a2) will now point to the same empty array. (So don't use this technique if you don't want a2 to hold an empty array!)
Think about what this will output:
```js
var foo = [1,2,3];
var bar = [1,2,3];
var foo2 = foo;
var bar2 = bar;
foo = [];
bar.length = 0;
console.log(foo, bar, foo2, bar2);
// [] [] [1, 2, 3] []
```
Stackoverflow more detail:
[difference-between-array-length-0-and-array](http://stackoverflow.com/questions/4804235/difference-between-array-length-0-and-array)
================================================
FILE: _posts/en/javascript/2016-01-23-converting-to-number-fast-way.md
================================================
---
layout: post
title: Converting to number fast way
tip-number: 23
tip-username: sonnyt
tip-username-profile: http://twitter.com/sonnyt
tip-tldr: Converting strings to numbers is extremely common. The easiest and fastest way to achieve that would be using the + operator.
redirect_from:
- /en/converting-to-number-fast-way/
categories:
- en
- javascript
---
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.
```javascript
var one = '1';
var numberOne = +one; // Number 1
```
You can also use the `-` (minus) operator which type-converts the value into number but also negates it.
```javascript
var one = '1';
var negativeNumberOne = -one; // Number -1
```
================================================
FILE: _posts/en/javascript/2016-01-24-use_===_instead_of_==.md
================================================
---
layout: post
title: Use === instead of ==
tip-number: 24
tip-username: bhaskarmelkani
tip-username-profile: https://www.twitter.com/bhaskarmelkani
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 `==`.
redirect_from:
- /en/use_===_instead_of_==/
categories:
- en
- javascript
---
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 `==`.
```js
[10] == 10 // is true
[10] === 10 // is false
'10' == 10 // is true
'10' === 10 // is false
[] == 0 // is true
[] === 0 // is false
'' == false // is true but true == "a" is false
'' === false // is false
```
================================================
FILE: _posts/en/javascript/2016-01-25-Using-immediately-invoked-function-expression.md
================================================
---
layout: post
title: Using immediately invoked function expression
tip-number: 25
tip-username: rishantagarwal
tip-username-profile: https://github.com/rishantagarwal
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.
redirect_from:
- /en/Using-immediately-invoked-function-expression/
categories:
- en
- javascript
---
Called as "Iffy" ( IIFE - immediately invoked function expression) is an anonymous function expression that is immediately invoked and has some important uses in Javascript.
```javascript
(function() {
// Do something
}
)()
```
It is an anonymous function expression that is immediately invoked, and it has some particularly important uses in JavaScript.
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.
Similarly, we can even create a named, immediately invoked function expression:
```javascript
(someNamedFunction = function(msg) {
console.log(msg || "Nothing for today !!")
}) (); // Output --> Nothing for today !!
someNamedFunction("Javascript rocks !!"); // Output --> Javascript rocks !!
someNamedFunction(); // Output --> Nothing for today !!
```
For more details, check the following URL's -
1. [Link 1](https://blog.mariusschulz.com/2016/01/13/disassembling-javascripts-iife-syntax)
2. [Link 2](http://javascriptissexy.com/12-simple-yet-powerful-javascript-tips/)
Performance:
[jsPerf](http://jsperf.com/iife-with-call)
================================================
FILE: _posts/en/javascript/2016-01-26-filtering-and-sorting-a-list-of-strings.md
================================================
---
layout: post
title: Filtering and Sorting a List of Strings
tip-number: 26
tip-username: davegomez
tip-username-profile: https://github.com/davegomez
tip-tldr: You may have a big list of names you need to filter in order to remove duplicates and sort them alphabetically.
credirect_from:
- /en/filtering-and-sorting-a-list-of-strings/
categories:
- en
- javascript
---
You may have a big list of names you need to filter in order to remove duplicates and sort them alphabetically.
In our example we are going to use the list of **JavaScript reserved keywords** we can find across the different versions of the language, but as you can notice, there is a lot of duplicated keywords and they are not alphabetically organized. So this is a perfect list ([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)) of strings to test out this JavaScript tip.
```js
var keywords = ['do', 'if', 'in', 'for', 'new', 'try', 'var', 'case', 'else', 'enum', 'null', 'this', 'true', 'void', 'with', 'break', 'catch', 'class', 'const', 'false', 'super', 'throw', 'while', 'delete', 'export', 'import', 'return', 'switch', 'typeof', 'default', 'extends', 'finally', 'continue', 'debugger', 'function', 'do', 'if', 'in', 'for', 'int', 'new', 'try', 'var', 'byte', 'case', 'char', 'else', 'enum', 'goto', 'long', 'null', 'this', 'true', 'void', 'with', 'break', 'catch', 'class', 'const', 'false', 'final', 'float', 'short', 'super', 'throw', 'while', 'delete', 'double', 'export', 'import', 'native', 'public', 'return', 'static', 'switch', 'throws', 'typeof', 'boolean', 'default', 'extends', 'finally', 'package', 'private', 'abstract', 'continue', 'debugger', 'function', 'volatile', 'interface', 'protected', 'transient', 'implements', 'instanceof', 'synchronized', 'do', 'if', 'in', 'for', 'let', 'new', 'try', 'var', 'case', 'else', 'enum', 'eval', 'null', 'this', 'true', 'void', 'with', 'break', 'catch', 'class', 'const', 'false', 'super', 'throw', 'while', 'yield', 'delete', 'export', 'import', 'public', 'return', 'static', 'switch', 'typeof', 'default', 'extends', 'finally', 'package', 'private', 'continue', 'debugger', 'function', 'arguments', 'interface', 'protected', 'implements', 'instanceof', 'do', 'if', 'in', 'for', 'let', 'new', 'try', 'var', 'case', 'else', 'enum', 'eval', 'null', 'this', 'true', 'void', 'with', 'await', 'break', 'catch', 'class', 'const', 'false', 'super', 'throw', 'while', 'yield', 'delete', 'export', 'import', 'public', 'return', 'static', 'switch', 'typeof', 'default', 'extends', 'finally', 'package', 'private', 'continue', 'debugger', 'function', 'arguments', 'interface', 'protected', 'implements', 'instanceof'];
```
Since we don't want to change our original list, we are going to use a high order function named [`filter`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), which will return a new filter array based in a predicate (*function*) we pass to it. The predicate will compare the index of the current keyword in the original list with its `index` in the new list and will push it to the new array only if the indexes match.
Finally we are going to sort the filtered list using the [`sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) function which takes a comparison function as the only argument, returning a alphabetically sorted list.
```js
var filteredAndSortedKeywords = keywords
.filter(function (keyword, index) {
return keywords.lastIndexOf(keyword) === index;
})
.sort(function (a, b) {
return a < b ? -1 : 1;
});
```
The **ES6** (ECMAScript 2015) version using [arrow functions](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) looks a little simpler:
```js
const filteredAndSortedKeywords = keywords
.filter((keyword, index) => keywords.lastIndexOf(keyword) === index)
.sort((a, b) => a < b ? -1 : 1);
```
And this is the final filtered and sorted list of JavaScript reserved keywords:
```js
console.log(filteredAndSortedKeywords);
// ['abstract', 'arguments', 'await', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'double', 'else', 'enum', 'eval', 'export', 'extends', 'false', 'final', 'finally', 'float', 'for', 'function', 'goto', 'if', 'implements', 'import', 'in', 'instanceof', 'int', 'interface', 'let', 'long', 'native', 'new', 'null', 'package', 'private', 'protected', 'public', 'return', 'short', 'static', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient', 'true', 'try', 'typeof', 'var', 'void', 'volatile', 'while', 'with', 'yield']
```
*Thanks to [@nikshulipa](https://github.com/nikshulipa), [@kirilloid](https://twitter.com/kirilloid), [@lesterzone](https://twitter.com/lesterzone), [@tracker1](https://twitter.com/tracker1), [@manuel_del_pozo](https://twitter.com/manuel_del_pozo) for all the comments and suggestions!*
================================================
FILE: _posts/en/javascript/2016-01-27-short-circuit-evaluation-in-js.md
================================================
---
layout: post
title: Short circuit evaluation in JS.
tip-number: 27
tip-username: bhaskarmelkani
tip-username-profile: https://www.twitter.com/bhaskarmelkani
tip-tldr: Short-circuit evaluation says, the second argument is executed or evaluated only if the first argument does not suffice to determine the value of the expression, when the first argument of the AND `&&` function evaluates to false, the overall value must be false, and when the first argument of the OR `||` function evaluates to true, the overall value must be true.
redirect_from:
- /en/short-circuit-evaluation-in-js/
categories:
- en
- javascript
---
[Short-circuit evaluation](https://en.wikipedia.org/wiki/Short-circuit_evaluation) says, the second argument is executed or evaluated only if the first argument does not suffice to determine the value of the expression: when the first argument of the AND (`&&`) function evaluates to false, the overall value must be false; and when the first argument of the OR (`||`) function evaluates to true, the overall value must be true.
For the following `test` condition and `isTrue` and `isFalse` function.
```js
var test = true;
var isTrue = function(){
console.log('Test is true.');
};
var isFalse = function(){
console.log('Test is false.');
};
```
Using logical AND - `&&`.
```js
// A normal if statement.
if(test){
isTrue(); // Test is true
}
// Above can be done using '&&' as -
( test && isTrue() ); // Test is true
```
Using logical OR - `||`.
```js
test = false;
if(!test){
isFalse(); // Test is false.
}
( test || isFalse()); // Test is false.
```
The logical OR could also be used to set a default value for function argument.
```js
function theSameOldFoo(name){
name = name || 'Bar' ;
console.log("My best friend's name is " + name);
}
theSameOldFoo(); // My best friend's name is Bar
theSameOldFoo('Bhaskar'); // My best friend's name is Bhaskar
```
The logical AND could be used to avoid exceptions when using properties of undefined.
Example:
```js
var dog = {
bark: function(){
console.log('Woof Woof');
}
};
// Calling dog.bark();
dog.bark(); // Woof Woof.
// But if dog is not defined, dog.bark() will raise an error "Cannot read property 'bark' of undefined."
// To prevent this, we can use &&.
dog&&dog.bark(); // This will only call dog.bark(), if dog is defined.
```
================================================
FILE: _posts/en/javascript/2016-01-28-curry-vs-partial-application.md
================================================
---
layout: post
title: Currying vs partial application
tip-number: 28
tip-username: bhaskarmelkani
tip-username-profile: https://www.twitter.com/bhaskarmelkani
tip-tldr: Currying and partial application are two ways of transforming a function into another function with a generally smaller arity.
redirect_from:
- /en/curry-vs-partial-application/
categories:
- en
- javascript
---
**Currying**
Currying takes a function
f: X * Y -> R
and turns it into a function
f': X -> (Y -> R)
Instead of calling f with two arguments, we invoke f' with the first argument. The result is a function that we then call with the second argument to produce the result.
Thus, if the uncurried f is invoked as
f(3,5)
then the curried f' is invoked as
f(3)(5)
For example:
Uncurried add()
```javascript
function add(x, y) {
return x + y;
}
add(3, 5); // returns 8
```
Curried add()
```javascript
function addC(x) {
return function (y) {
return x + y;
}
}
addC(3)(5); // returns 8
```
**The algorithm for currying.**
Curry takes a binary function and returns a unary function that returns a unary function.
curry: (X × Y → R) → (X → (Y → R))
Javascript Code:
```javascript
function curry(f) {
return function(x) {
return function(y) {
return f(x, y);
}
}
}
```
**Partial application**
Partial application takes a function
f: X * Y -> R
and a fixed value for the first argument to produce a new function
f`: Y -> R
f' does the same as f, but only has to fill in the second parameter which is why its arity is one less than the arity of f.
For example: Binding the first argument of function add to 5 produces the function plus5.
```javascript
function plus5(y) {
return 5 + y;
}
plus5(3); // returns 8
```
**The algorithm of partial application.***
partApply takes a binary function and a value and produces a unary function.
partApply : ((X × Y → R) × X) → (Y → R)
Javascript Code:
```javascript
function partApply(f, x) {
return function(y) {
return f(x, y);
}
}
```
================================================
FILE: _posts/en/javascript/2016-01-29-speed-up-recursive-functions-with-memoization.md
================================================
---
layout: post
title: Speed up recursive functions with memoization
tip-number: 29
tip-username: hingsir
tip-username-profile: https://github.com/hingsir
tip-tldr: Fibonacci sequence is very familiar to everybody. we can write the following function in 20 seconds.it works, but not efficient. it did lots of duplicate computing works, we can cache its previously computed results to speed it up.
redirect_from:
- /en/speed-up-recursive-functions-with-memoization/
categories:
- en
- javascript
---
Fibonacci sequence is very familiar to everybody. We can write the following function in 20 seconds.
```js
var fibonacci = function(n) {
return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}
```
It works, but is not efficient. It did lots of duplicate computing works, we can cache its previously computed results to speed it up.
```js
var fibonacci = (function() {
var cache = [0, 1]; // cache the value at the n index
return function(n) {
if (cache[n] === undefined) {
for (var i = cache.length; i <= n; ++i) {
cache[i] = cache[i - 1] + cache[i - 2];
}
}
return cache[n];
}
})();
```
Also, we can define a higher-order function that accepts a function as its argument and returns a memoized version of the function.
```js
var memoize = function(func) {
var cache = {};
return function() {
var key = JSON.stringify(Array.prototype.slice.call(arguments));
return key in cache ? cache[key] : (cache[key] = func.apply(this, arguments));
}
}
fibonacci = memoize(fibonacci);
```
And this is an ES6 version of the memoize function.
```js
var memoize = function(func) {
const cache = {};
return (...args) => {
const key = JSON.stringify(args);
return key in cache ? cache[key] : (cache[key] = func(...args));
}
}
fibonacci = memoize(fibonacci);
```
we can use `memoize()` in many other situations
* GCD(Greatest Common Divisor)
```js
var gcd = memoize(function(a, b) {
var t;
if (a < b) t = b, b = a, a = t;
while (b != 0) t = b, b = a % b, a = t;
return a;
});
gcd(27, 183); //=> 3
```
* Factorial calculation
```js
var factorial = memoize(function(n) {
return (n <= 1) ? 1 : n * factorial(n - 1);
})
factorial(5); //=> 120
```
Learn more about memoization:
- [Memoization - Wikipedia](https://en.wikipedia.org/wiki/Memoization)
- [Implementing Memoization in JavaScript](https://www.sitepoint.com/implementing-memoization-in-javascript/)
================================================
FILE: _posts/en/javascript/2016-01-30-converting-truthy-falsy-values-to-boolean.md
================================================
---
layout: post
title: Converting truthy/falsy values to boolean
tip-number: 30
tip-username: hakhag
tip-username-profile: https://github.com/hakhag
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.
redirect_from:
- /en/converting-truthy-falsy-values-to-boolean/
categories:
- en
- javascript
---
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.
```js
!!"" // false
!!0 // false
!!null // false
!!undefined // false
!!NaN // false
!!"hello" // true
!!1 // true
!!{} // true
!![] // true
```
================================================
FILE: _posts/en/javascript/2016-01-31-avoid-modifying-or-passing-arguments-into-other-functions—it-kills-optimization.md
================================================
---
layout: post
title: Avoid modifying or passing `arguments` into other functions — it kills optimization
tip-number: 31
tip-username: berkana
tip-username-profile: https://github.com/berkana
tip-tldr: Within JavaScript functions, the variable name `arguments` lets you access all of the arguments passed to the function. `arguments` is an *array-like object*; `arguments` can be accessed using array notation, and it has the *length* property, but it doesn't have many of the built-in methods that arrays have such as `filter` and `map` and `forEach`. Because of this, it is a fairly common practice to convert `arguments` into an array using the following snipet
redirect_from:
- /en/avoid-modifying-or-passing-arguments-into-other-functions-it-kills-optimization/
categories:
- en
- javascript
---
###Background
Within JavaScript functions, the variable name [`arguments`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments) lets you access all of the arguments passed to the function. `arguments` is an *array-like object*; `arguments` can be accessed using array notation, and it has the *length* property, but it doesn't have many of the built-in methods that arrays have such as `filter` and `map` and `forEach`. Because of this, it is a fairly common practice to convert `arguments` into an array using the following:
```js
var args = Array.prototype.slice.call(arguments);
```
This calls the `slice` method from the `Array` prototype, passing it `arguments`; the `slice` method returns a shallow copy of `arguments` as a new array object. A common shorthand for this is :
```js
var args = [].slice.call(arguments);
```
In this case, instead of calling `slice` from the `Array` prototype, it is simply being called from an empty array literal.
###Optimization
Unfortunately, passing `arguments` into any function call will cause the V8 JavaScript engine used in Chrome and Node to skip optimization on the function that does this, which can result in considerably slower performance. See this article on [optimization killers](https://github.com/petkaantonov/bluebird/wiki/Optimization-killers). Passing `arguments` to any other function is known as *leaking `arguments`*.
Instead, if you want an array of the arguments that lets you use you need to resort to this:
```js
var args = new Array(arguments.length);
for(var i = 0; i < args.length; ++i) {
args[i] = arguments[i];
}
```
Yes it is more verbose, but in production code, it is worth it for the performance optimization.
================================================
FILE: _posts/en/javascript/2016-02-01-map-to-the-rescue-adding-order-to-object-properties.md
================================================
---
layout: post
title: Map() to the rescue; adding order to Object properties
tip-number: 32
tip-username: loverajoel
tip-username-profile: https://twitter.com/loverajoel
tip-tldr: An Object it is an unordered collection of properties... that means that if you are trying to save ordered data inside an Object, you have to review it because properties order in objects are not guaranteed.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /en/map-to-the-rescue-adding-order-to-object-properties/
categories:
- en
- javascript
---
## Object properties order
> An object is a member of the type Object. It is an unordered collection of properties each of which contains a primitive value, object, or function. A function stored in a property of an object is called a method. [ECMAScript](http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf)
Take a look in action
```js
var myObject = {
z: 1,
'@': 2,
b: 3,
1: 4,
5: 5
};
console.log(myObject) // Object {1: 4, 5: 5, z: 1, @: 2, b: 3}
for (item in myObject) {...
// 1
// 5
// z
// @
// b
```
Each browser have his own rules about the order in objects bebause technically, order is unspecified.
## How to solve this?
### Map
Using a new ES6 feature called Map. A [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) object iterates its elements in insertion order — a `for...of` loop returns an array of [key, value] for each iteration.
```js
var myObject = new Map();
myObject.set('z', 1);
myObject.set('@', 2);
myObject.set('b', 3);
for (var [key, value] of myObject) {
console.log(key, value);
...
// z 1
// @ 2
// b 3
```
### Hack for old browsers
Mozilla suggest:
> So, if you want to simulate an ordered associative array in a cross-browser environment, you are forced to either use two separate arrays (one for the keys and the other for the values), or build an array of single-property objects, etc.
```js
// Using two separate arrays
var objectKeys = [z, @, b, 1, 5];
for (item in objectKeys) {
myObject[item]
...
// Build an array of single-property objects
var myData = [{z: 1}, {'@': 2}, {b: 3}, {1: 4}, {5: 5}];
```
================================================
FILE: _posts/en/javascript/2016-02-02-create-range-0-n-easily-using-one-line.md
================================================
---
layout: post
title: Create array sequence `[0, 1, ..., N-1]` in one line
tip-number: 33
tip-username: SarjuHansaliya
tip-username-profile: https://github.com/SarjuHansaliya
tip-tldr: Compact one-liners that generate ordinal sequence arrays
redirect_from:
- /en/create-range-0-n-easily-using-one-line/
categories:
- en
- javascript
---
Here are two compact code sequences to generate the `N`-element array `[0, 1, ..., N-1]`:
### Solution 1 (requires ES5)
```js
Array.apply(null, {length: N}).map(Function.call, Number);
```
#### Brief explanation
1. `Array.apply(null, {length: N})` returns an `N`-element array filled with `undefined` (i.e. `A = [undefined, undefined, ...]`).
2. `A.map(Function.call, Number)` returns an `N`-element array, whose index `I` gets the result of `Function.call.call(Number, undefined, I, A)`
3. `Function.call.call(Number, undefined, I, A)` collapses into `Number(I)`, which is naturally `I`.
4. Result: `[0, 1, ..., N-1]`.
For a more thorough explanation, go [here](https://github.com/gromgit/jstips-xe/blob/master/tips/33.md).
### Solution 2 (requires ES6)
It uses `Array.from` [https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
```js
Array.from(new Array(N),(val,index)=>index);
```
### Solution 3 (requires ES6)
```js
Array.from(Array(N).keys());
```
#### Brief explanation
1. `A = new Array(N)` returns an array with `N` _holes_ (i.e. `A = [,,,...]`, but `A[x] = undefined` for `x` in `0...N-1`).
2. `F = (val,index)=>index` is simply `function F (val, index) { return index; }`
3. `Array.from(A, F)` returns an `N`-element array, whose index `I` gets the results of `F(A[I], I)`, which is simply `I`.
4. Result: `[0, 1, ..., N-1]`.
### One More Thing
If you actually want the sequence [1, 2, ..., N], **Solution 1** becomes:
```js
Array.apply(null, {length: N}).map(function(value, index){
return index + 1;
});
```
and **Solution 2**:
```js
Array.from(new Array(N),(val,index)=>index+1);
```
================================================
FILE: _posts/en/javascript/2016-02-03-implementing-asynchronous-loops.md
================================================
---
layout: post
title: Implementing asynchronous loop
tip-number: 34
tip-username: madmantalking
tip-username-profile: https://github.com/madmantalking
tip-tldr: You may run into problems while implementing asynchronous loops.
redirect_from:
- /en/implementing-asynchronous-loops/
categories:
- en
- javascript
---
Let's try out writing an asynchronous function which prints the value of the loop index every second.
```js
for (var i=0; i<5; i++) {
setTimeout(function(){
console.log(i);
}, 1000 * (i+1));
}
```
The output of the above programs turns out to be
```js
> 5
> 5
> 5
> 5
> 5
```
So this definitely doesn't work.
**Reason**
Each timeout refers to the original `i`, not a copy. So the for loop increments `i` until it gets to 5, then the timeouts run and use the current value of `i` (which is 5).
Well , this problem seems easy. An immediate solution that strikes is to cache the loop index in a temporary variable.
```js
for (var i=0; i<5; i++) {
var temp = i;
setTimeout(function(){
console.log(temp);
}, 1000 * (i+1));
}
```
But again the output of the above programs turns out to be
```js
> 4
> 4
> 4
> 4
> 4
```
So , that doesn't work either , because blocks don't create a scope and variables initializers are hoisted to the top of the scope. In fact, the previous block is the same as:
```js
var temp;
for (var i=0; i<5; i++) {
temp = i;
setTimeout(function(){
console.log(temp);
}, 1000 * (i+1));
}
```
**Solution**
There are a few different ways to copy `i`. The most common way is creating a closure by declaring a function and passing `i` as an argument. Here we do this as a self-calling function.
```js
for (var i=0; i<5; i++) {
(function(num){
setTimeout(function(){
console.log(num);
}, 1000 * (i+1));
})(i);
}
```
In JavaScript, arguments are passed by value to a function. So primitive types like numbers, dates, and strings are basically copied. If you change them inside the function, it does not affect the outside scope. Objects are special: if the inside function changes a property, the change is reflected in all scopes.
Another approach for this would be with using `let`. With ES6 the `let` keyword is useful since it's block scoped unlike `var`
```js
for (let i=0; i<5; i++) {
setTimeout(function(){
console.log(i);
}, 1000 * (i+1));
}
```
================================================
FILE: _posts/en/javascript/2016-02-04-assignment-shorthands.md
================================================
---
layout: post
title: Assignment Operators
tip-number: 35
tip-username: hsleonis
tip-username-profile: https://github.com/hsleonis
tip-tldr: Assigning is very common. Sometimes typing becomes time consuming for us 'Lazy programmers'. So, we can use some tricks to help us and make our code cleaner and simpler.
redirect_from:
- /en/assignment-shorthands/
categories:
- en
- javascript
---
Assigning is very common. Sometimes typing becomes time consuming for us 'Lazy programmers'.
So, we can use some tricks to help us and make our code cleaner and simpler.
This is the similar use of
````javascript
x += 23; // x = x + 23;
y -= 15; // y = y - 15;
z *= 10; // z = z * 10;
k /= 7; // k = k / 7;
p %= 3; // p = p % 3;
d **= 2; // d = d ** 2;
m >>= 2; // m = m >> 2;
n <<= 2; // n = n << 2;
n ++; // n = n + 1;
n --; n = n - 1;
````
### `++` and `--` operators
There is a special `++` operator. It's best to explain it with an example:
````javascript
var a = 2;
var b = a++;
// Now a is 3 and b is 2
````
The `a++` statement does this:
1. return the value of `a`
2. increment `a` by 1
But what if we wanted to increment the value first? It's simple:
````javascript
var a = 2;
var b = ++a;
// Now both a and b are 3
````
See? I put the operator _before_ the variable.
The `--` operator is similar, except it decrements the value.
### If-else (Using ternary operator)
This is what we write on regular basis.
````javascript
var newValue;
if(value > 10)
newValue = 5;
else
newValue = 2;
````
We can user ternary operator to make it awesome:
````javascript
var newValue = (value > 10) ? 5 : 2;
````
### Null, Undefined, Empty Checks
````javascript
if (variable1 !== null || variable1 !== undefined || variable1 !== '') {
var variable2 = variable1;
}
````
Shorthand here:
````javascript
var variable2 = variable1 || '';
````
P.S.: If variable1 is a number, then first check if it is 0.
### Object Array Notation
Instead of using:
````javascript
var a = new Array();
a[0] = "myString1";
a[1] = "myString2";
````
Use this:
````javascript
var a = ["myString1", "myString2"];
````
### Associative array
Instead of using:
````javascript
var skillSet = new Array();
skillSet['Document language'] = 'HTML5';
skillSet['Styling language'] = 'CSS3';
````
Use this:
````javascript
var skillSet = {
'Document language' : 'HTML5',
'Styling language' : 'CSS3'
};
````
================================================
FILE: _posts/en/javascript/2016-02-05-observe-dom-changes.md
================================================
---
layout: post
title: Observe DOM changes in extensions
tip-number: 36
tip-username: beyondns
tip-username-profile: https://github.com/beyondns
tip-tldr: When you develop extensions to existent sites it's not so easy to play with DOM 'cause of modern dynamic javascript.
redirect_from:
- /en/observe-dom-changes/
categories:
- en
- javascript
---
[MutationObserver](https://developer.mozilla.org/en/docs/Web/API/MutationObserver) is a solution to listen DOM changes and do what you want to do with elements when they changed. In following example there is some emulation of dynamic content loading with help of timers, after first "target" element creation goes "subTarget".
In extension code firstly rootObserver works till targetElement appearance then elementObserver starts. This cascading observing helps finally get moment when subTargetElement found.
This useful to develop extensions to complex sites with dynamic content loading.
```js
const observeConfig = {
attributes: true,
childList: true,
characterData: true,
subtree: true
};
function initExtension(rootElement, targetSelector, subTargetSelector) {
var rootObserver = new MutationObserver(function(mutations) {
console.log("Inside root observer");
targetElement = rootElement.querySelector(targetSelector);
if (targetElement) {
rootObserver.disconnect();
var elementObserver = new MutationObserver(function(mutations) {
console.log("Inside element observer");
subTargetElement = targetElement.querySelector(subTargetSelector);
if (subTargetElement) {
elementObserver.disconnect();
console.log("subTargetElement found!");
}
});
elementObserver.observe(targetElement, observeConfig);
}
});
rootObserver.observe(rootElement, observeConfig);
}
(function() {
initExtension(document.body, "div.target", "div.subtarget");
setTimeout(function() {
del = document.createElement("div");
del.innerHTML = "
target
";
document.body.appendChild(del);
}, 3000);
setTimeout(function() {
var el = document.body.querySelector('div.target');
if (el) {
del = document.createElement("div");
del.innerHTML = "
subtarget
";
el.appendChild(del);
}
}, 5000);
})();
```
================================================
FILE: _posts/en/javascript/2016-02-06-deduplicate-an-array.md
================================================
---
layout: post
title: Deduplicate an Array
tip-number: 37
tip-username: danillouz
tip-username-profile: https://www.twitter.com/danillouz
tip-tldr: How to remove duplicate elements, of different data types, from an Array.
redirect_from:
- /en/deduplicate-an-array/
categories:
- en
- javascript
---
# Primitives
If an Array only contains primitive values, we can deduplicate it by
only using the [`filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) and [`indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) methods.
```javascript
var deduped = [ 1, 1, 'a', 'a' ].filter(function (el, i, arr) {
return arr.indexOf(el) === i;
});
console.log(deduped); // [ 1, 'a' ]
```
## ES2015
We can write this in a more compact way using an [arrow function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions).
```javascript
var deduped = [ 1, 1, 'a', 'a' ].filter( (el, i, arr) => arr.indexOf(el) === i);
console.log(deduped); // [ 1, 'a' ]
```
But with the introduction of [Sets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) and the [`from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from) method, we can achieve the same
result in a more concise way.
```javascript
var deduped = Array.from( new Set([ 1, 1, 'a', 'a' ]) );
console.log(deduped); // [ 1, 'a' ]
```
# Objects
We can't use the same approach when the elements are Objects,
because Objects are stored by reference and primitives are stored
by value.
```javascript
1 === 1 // true
'a' === 'a' // true
{ a: 1 } === { a: 1 } // false
```
Therefore we need to change our approach and use a hash table.
```javascript
function dedup(arr) {
var hashTable = {};
return arr.filter(function (el) {
var key = JSON.stringify(el);
var match = Boolean(hashTable[key]);
return (match ? false : hashTable[key] = true);
});
}
var deduped = dedup([
{ a: 1 },
{ a: 1 },
[ 1, 2 ],
[ 1, 2 ]
]);
console.log(deduped); // [ {a: 1}, [1, 2] ]
```
Because a hash table in javascript is simply an `Object`, the keys
will always be of the type `String`. This means that normally we can't
distinguish between strings and numbers of the same value, i.e. `1` and
`'1'`.
```javascript
var hashTable = {};
hashTable[1] = true;
hashTable['1'] = true;
console.log(hashTable); // { '1': true }
```
However, because we're using [`JSON.stringify`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify), keys that are of the
type `String`, will be stored as an escaped string value, giving us unique
keys in our `hashTable`.
```javascript
var hashTable = {};
hashTable[JSON.stringify(1)] = true;
hashTable[JSON.stringify('1')] = true;
console.log(hashTable); // { '1': true, '\'1\'': true }
```
This means duplicate elements of the same value, but of a different type,
will still be deduplicated using the same implementation.
```javascript
var deduped = dedup([
{ a: 1 },
{ a: 1 },
[ 1, 2 ],
[ 1, 2 ],
1,
1,
'1',
'1'
]);
console.log(deduped); // [ {a: 1}, [1, 2], 1, '1' ]
```
# Resources
## Methods
* [`filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)
* [`indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)
* [`from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
* [`JSON.stringify`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify)
## ES2015
* [arrow functions](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
* [Sets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)
## Stack overflow
* [remove duplicates from array](http://stackoverflow.com/questions/9229645/remove-duplicates-from-javascript-array/9229821#9229821)
================================================
FILE: _posts/en/javascript/2016-02-07-flattening-multidimensional-arrays-in-javascript.md
================================================
---
layout: post
title: Flattening multidimensional Arrays in JavaScript
tip-number: 38
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: Three different solutions to merge multidimensional array into a single array.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /en/flattening-multidimensional-arrays-in-javascript/
categories:
- en
- javascript
---
These are the three known ways to merge multidimensional array into a single array.
Given this array:
```js
var myArray = [[1, 2],[3, 4, 5], [6, 7, 8, 9]];
```
We wanna have this result:
```js
[1, 2, 3, 4, 5, 6, 7, 8, 9]
```
### Solution 1: Using [`concat()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) and [`apply()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)
```js
var myNewArray = [].concat.apply([], myArray);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
```
### Solution 2: Using [`reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Flatten_an_array_of_arrays)
```js
var myNewArray = myArray.reduce(function(prev, curr) {
return prev.concat(curr);
});
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
```
### Solution 3:
```js
var myNewArray3 = [];
for (var i = 0; i < myArray.length; ++i) {
for (var j = 0; j < myArray[i].length; ++j)
myNewArray3.push(myArray[i][j]);
}
console.log(myNewArray3);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
```
### Solution 4: Using [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator) in ES6
```js
var myNewArray4 = [].concat(...myArray);
console.log(myNewArray4);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
```
### Solution 5: Using [`flat()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) in ES10
```js
var myNewArray5 = myArray.flat();
console.log(myNewArray5);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
```
Take a look [here](https://jsbin.com/janana/edit?js,console) these 4 algorithms in action.
For infinitely nested array try Lodash [flattenDeep()](https://lodash.com/docs#flattenDeep).
If you are curious about performance, [here](http://jsperf.com/flatten-an-array-loop-vs-reduce/6) a test for check how it works.
================================================
FILE: _posts/en/javascript/2016-02-08-advanced-properties.md
================================================
---
layout: post
title: Advanced Javascript Properties
tip-number: 39
tip-username: mallowigi
tip-username-profile: https://github.com/mallowigi
tip-tldr: How to add private properties, getters and setters to objects.
redirect_from:
- /en/advanced-properties/
categories:
- en
- javascript
---
It is possible to configure object properties in Javascript for example to set properties to be pseudo-private or readonly. This feature is available since ECMAScript 5.1, therefore supported by all recent browsers.
To do so, you need to use the method `defineProperty` of the `Object` prototype like so:
```js
var a = {};
Object.defineProperty(a, 'readonly', {
value: 15,
writable: false
});
a.readonly = 20;
console.log(a.readonly); // 15
```
The syntax is as follows:
```js
Object.defineProperty(dest, propName, options)
```
or for multiple definitions:
```js
Object.defineProperties(dest, {
propA: optionsA,
propB: optionsB, //...
})
```
where options include the following attributes:
- *value*: if the property is not a getter (see below), value is a mandatory attribute. `{a: 12}` === `Object.defineProperty(obj, 'a', {value: 12})`
- *writable*: set the property as readonly. Note that if the property is a nested objects, its properties are still editable.
- *enumerable*: set the property as hidden. That means that `for ... of` loops and `stringify` will not include the property in their result, but the property is still there. Note: That doesn't mean that the property is private! It can still be accessible from the outside, it just means that it won't be printed.
- *configurable*: set the property as non modifiable, e.g. protected from deletion or redefinition. Again, if the property is a nested object, its properties are still configurable.
So in order to create a private constant property, you can define it like so:
```js
Object.defineProperty(obj, 'myPrivateProp', {value: val, enumerable: false, writable: false, configurable: false});
```
Besides configuring properties, `defineProperty` allows us to define *dynamic properties*, thanks to the second parameter being a string. For instance, let's say that I want to create properties according to some external configuration:
```js
var obj = {
getTypeFromExternal(): true // illegal in ES5.1
}
Object.defineProperty(obj, getTypeFromExternal(), {value: true}); // ok
// For the example sake, ES6 introduced a new syntax:
var obj = {
[getTypeFromExternal()]: true
}
```
But that's not all! Advanced properties allows us to create **getters** and **setters**, just like other OOP languages! In that case, one cannot use the `writable`, `enumerable` and `configurable` properties, but instead:
```js
function Foobar () {
var _foo; // true private property
Object.defineProperty(obj, 'foo', {
get: function () { return _foo; }
set: function (value) { _foo = value }
});
}
var foobar = new Foobar();
foobar.foo; // 15
foobar.foo = 20; // _foo = 20
```
Aside for the obvious advantage of encapsulation and advanced accessors, you will notice that we didn't "call" the getter, instead we just "get" the property without parentheses! This is awesome! For instance, let's imagine that we have an object with long nested properties, like so:
```js
var obj = {a: {b: {c: [{d: 10}, {d: 20}] } } };
```
Now instead of doing `a.b.c[0].d` (where one of the properties can resolve to `undefined` and throw an error), we can instead create an alias:
```js
Object.defineProperty(obj, 'firstD', {
get: function () { return a && a.b && a.b.c && a.b.c[0] && a.b.c[0].d }
})
console.log(obj.firstD) // 10
```
### Note
If you define a getter without a setter and still try to set a value, you will get an error! This is particularly important when using helper functions such as `$.extend` or `_.merge`. Be careful!
### Links
- [defineProperty](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
- [Defining properties in JavaScript](http://bdadam.com/blog/defining-properties-in-javascript.html)
================================================
FILE: _posts/en/javascript/2016-02-09-using-json-stringify.md
================================================
---
layout: post
title: Using JSON.Stringify
tip-number: 40
tip-username: vamshisuram
tip-username-profile: https://github.com/vamshisuram
tip-tldr: Create string from selected properties of JSON object.
redirect_from:
- /en/using-json-stringify/
categories:
- en
- javascript
---
Let's say there is an object with properties "prop1", "prop2", "prop3".
We can pass __additional params__ to __JSON.stringify__ to selectively write properties of the object to string like:
```javascript
var obj = {
'prop1': 'value1',
'prop2': 'value2',
'prop3': 'value3'
};
var selectedProperties = ['prop1', 'prop2'];
var str = JSON.stringify(obj, selectedProperties);
// str
// {"prop1":"value1","prop2":"value2"}
```
The __"str"__ will contain only info on selected properties only.
Instead of array we can pass a function also.
```javascript
function selectedProperties(key, val) {
// the first val will be the entire object, key is empty string
if (!key) {
return val;
}
if (key === 'prop1' || key === 'prop2') {
return val;
}
return;
}
```
The last optional param it takes is to modify the way it writes the object to string.
```javascript
var str = JSON.stringify(obj, selectedProperties, '\t\t');
/* str output with double tabs in every line.
{
"prop1": "value1",
"prop2": "value2"
}
*/
```
================================================
FILE: _posts/en/javascript/2016-02-10-array-average-and-median.md
================================================
---
layout: post
title: Array average and median
tip-number: 41
tip-username: soyuka
tip-username-profile: https://github.com/soyuka
tip-tldr: Calculate the average and median from array values
redirect_from:
- /en/array-average-and-median/
categories:
- en
- javascript
---
The following examples will be based on the following array:
```javascript
let values = [2, 56, 3, 41, 0, 4, 100, 23];
```
To get the average, we have to sum up numbers and then divide by the number of values. Steps are:
- get the array length
- sum up values
- get the average (`sum/length`)
```javascript
let values = [2, 56, 3, 41, 0, 4, 100, 23];
let sum = values.reduce((previous, current) => current += previous);
let avg = sum / values.length;
// avg = 28
```
Or:
```javascript
let values = [2, 56, 3, 41, 0, 4, 100, 23];
let count = values.length;
values = values.reduce((previous, current) => current += previous);
values /= count;
// avg = 28
```
Now, to get the median steps are:
- sort the array
- get the arethmic mean of the middle values
```javascript
let values = [2, 56, 3, 41, 0, 4, 100, 23];
values.sort((a, b) => a - b);
let lowMiddle = Math.floor((values.length - 1) / 2);
let highMiddle = Math.ceil((values.length - 1) / 2);
let median = (values[lowMiddle] + values[highMiddle]) / 2;
// median = 13,5
```
With a bitwise operator:
```javascript
let values = [2, 56, 3, 41, 0, 4, 100, 23];
values.sort((a, b) => a - b);
let median = (values[(values.length - 1) >> 1] + values[values.length >> 1]) / 2
// median = 13,5
```
================================================
FILE: _posts/en/javascript/2016-02-11-preventing-unapply-attacks.md
================================================
---
layout: post
title: Preventing Unapply Attacks
tip-number: 42
tip-username: emars
tip-username-profile: https://twitter.com/marseltov
tip-tldr: Freeze the builtin prototypes.
redirect_from:
- /en/preventing-unapply-attacks/
categories:
- en
- javascript
---
By overriding the builtin prototypes, external code can cause code to break by rewriting code to expose and change bound arguments. This can be an issue that seriously breaks applications that works by using polyfill es5 methods.
```js
// example bind polyfill
function bind(fn) {
var prev = Array.prototype.slice.call(arguments, 1);
return function bound() {
var curr = Array.prototype.slice.call(arguments, 0);
var args = Array.prototype.concat.apply(prev, curr);
return fn.apply(null, args);
};
}
// unapply-attack
function unapplyAttack() {
var concat = Array.prototype.concat;
Array.prototype.concat = function replaceAll() {
Array.prototype.concat = concat; // restore the correct version
var curr = Array.prototype.slice.call(arguments, 0);
var result = concat.apply([], curr);
return result;
};
}
```
The above function discards the `prev` array from the bind meaning that any `.concat` the first concat call following using the unapply attack will throw an error.
By using [Object.freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze), making an object immutable, you prevent any overriding of the builtin object prototypes.
```js
(function freezePrototypes() {
if (typeof Object.freeze !== 'function') {
throw new Error('Missing Object.freeze');
}
Object.freeze(Object.prototype);
Object.freeze(Array.prototype);
Object.freeze(Function.prototype);
}());
```
You can read more about unapply attacks [here](https://glebbahmutov.com/blog/unapply-attack/).
Although this concept is called an 'unapply attack' due to some code being able to access closures that normally wouldn't be in scope, it is mostly wrong to consider this a security feature due to it not preventing an attacker with code execution from extending prototypes before the freezing happens and also still having the potential to read all scopes using various language features. ECMA modules would give realm based isolation which is much stronger than this solution however still doesn't fix the issues of third party scripts.
================================================
FILE: _posts/en/javascript/2016-02-12-use-destructuring-in-function-parameters.md
================================================
---
layout: post
title: Use destructuring in function parameters
tip-number: 43
tip-username: dislick
tip-username-profile: https://github.com/dislick
tip-tldr: Did you know that you can use destructuring in function parameters?
redirect_from:
- /en/use-destructuring-in-function-parameters/
categories:
- en
- javascript
---
I am sure many of you are already familiar with the [ES6 Destructuring Assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment). Did you know that you can also use it in function parameters?
```js
var sayHello = function({ name, surname }) {
console.log(`Hello ${name} ${surname}! How are you?`);
};
sayHello({ name: 'John', surname: 'Smith' })
// -> Hello John Smith! How are you?
```
This is great for functions which accept an options object. For this use case, you can also add [default parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters) to fill in whatever values the caller leaves out, or if the caller forgets to pass one at all:
```js
var sayHello2 = function({ name = "Anony", surname = "Moose" } = {}) {
console.log(`Hello ${name} ${surname}! How are you?`);
};
```
The `= {}` says that the default object to be destructured for this parameter is `{}`, in case the caller forgets to pass the parameter, or passes one of the wrong type (more on this below).
```js
sayHello2()
// -> Hello Anony Moose! How are you?
sayHello2({ name: "Bull" })
// -> Hello Bull Moose! How are you?
```
##### Argument Handling
With plain destructuring assignment, if the the input parameter can't be matched with the function's specified object arguments, all the unmatched arguments are `undefined`, so you need to add code that handles this properly:
```js
var sayHelloTimes = function({ name, surname }, times) {
console.log(`Hello ${name} ${surname}! I've seen you ${times} times before.`);
}
sayHelloTimes({ name: "Pam" }, 5678)
// -> Hello Pam undefined! I've seen you 5678 times before.
sayHelloTimes(5678)
// -> Hello undefined undefined! I've seen you undefined times before.
```
Worse, if the parameter to be destructured is missing, an exception is thrown, probably bringing your app to a screeching halt:
```js
sayHelloTimes()
// -> Uncaught TypeError: Cannot match against 'undefined' or 'null'...
```
It's conceptually similar to accessing a property of an undefined object, just with a different exception type.
Destructuring assignment with default parameters hides all the above to a certain extent:
```js
var sayHelloTimes2 = function({ name = "Anony", surname = "Moose" } = {}, times) {
console.log(`Hello ${name} ${surname}! I've seen you ${times} times before.`);
};
sayHelloTimes2({ name: "Pam" }, 5678)
// -> Hello Pam Moose! I've seen you 5678 times before.
sayHelloTimes2(5678)
// -> Hello Anony Moose! I've seen you undefined times before.
sayHelloTimes2()
// -> Hello Anony Moose! I've seen you undefined times before.
```
As for `= {}`, it covers the case of a missing _object_, for which individual property defaults won't help at all:
```js
var sayHelloTimes2a = function({ name = "Anony", surname = "Moose" }, times) {
console.log(`Hello ${name} ${surname}! I've seen you ${times} times before.`);
};
sayHelloTimes2a({ name: "Pam" }, 5678)
// -> Hello Pam Moose! I've seen you 5678 times before.
sayHelloTimes2a(5678)
// -> Hello Anony Moose! I've seen you undefined times before.
sayHelloTimes2a()
// -> Uncaught TypeError: Cannot match against 'undefined' or 'null'.
```
##### Availability
Note that destructuring assignment may not yet be available by default, in the version of Node.js or browser that you're using. For Node.js, you can try using the `--harmony-destructuring` flag on startup to activate this feature.
================================================
FILE: _posts/en/javascript/2016-02-13-know-the-passing-mechanism.md
================================================
---
layout: post
title: Know the passing mechanism
tip-number: 44
tip-username: bmkmanoj
tip-username-profile: https://github.com/bmkmanoj
tip-tldr: JavaScript technically only passes by value for both primitives and object (or reference) types. In case of reference types the reference value itself is passed by value.
redirect_from:
- /en/know-the-passing-mechanism/
categories:
- en
- javascript
---
JavaScript is pass-by-value, technically. It is neither pass-by-value nor pass-by-reference, going by the truest sense of these terms. To understand this passing mechanism, take a look at the following two example code snippets and the explanations.
### Example 1
```js
var me = { // 1
'partOf' : 'A Team'
};
function myTeam(me) { // 2
me = { // 3
'belongsTo' : 'A Group'
};
}
myTeam(me);
console.log(me); // 4 : {'partOf' : 'A Team'}
```
In above example, when the `myTeam` gets invoked, JavaScript is *passing the reference to* `me` *object as value, as it is an object* and invocation itself creates two independent references to the same object, (though the name being same here i.e. `me`, is misleading and gives us an impression that it is the single reference) and hence, the reference variable themselves are independent.
When we assigned a new object at #`3`, we are changing this reference value entirely within the `myTeam` function, and it will not have any impact on the original object outside this function scope, from where it was passed and the reference in the outside scope is going to retain the original object and hence the output from #`4`.
### Example 2
```js
var me = { // 1
'partOf' : 'A Team'
};
function myGroup(me) { // 2
me.partOf = 'A Group'; // 3
}
myGroup(me);
console.log(me); // 4 : {'partOf' : 'A Group'}
```
In the case of `myGroup` invocation, we are passing the object `me`. But unlike the example 1 scenario, we are not assigning this `me` variable to any new object, effectively meaning the object reference value within the `myGroup` function scope still is the original object's reference value and when we are modifying the property within this scope, it is effectively modifying the original object's property. Hence, you get the output from #`4`.
So does this later case not prove that javascript is pass-by-reference? No, it does not. Remember, *JavaScript passes the reference as value, in case of objects*. The confusion arises as we tend not to understand fully what pass by reference is. This is the exact reason, some prefer to call this as *call-by-sharing*.
*Initially posted by the author on [js-by-examples](https://github.com/bmkmanoj/js-by-examples/blob/master/examples/js_pass_by_value_or_reference.md)*
================================================
FILE: _posts/en/javascript/2016-02-14-calculate-the-max-min-value-from-an-array.md
================================================
---
layout: post
title: Calculate the Max/Min value from an array
tip-number: 45
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: Ways to use the built-in functions Math.max() and Math.min() with arrays of numbers
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /en/calculate-the-max-min-value-from-an-array/
categories:
- en
- javascript
---
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.
```js
Math.max(1, 2, 3, 4); // 4
Math.min(1, 2, 3, 4); // 1
```
These functions will not work as-is with arrays of numbers. However, there are some ways around this.
[`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.
```js
var numbers = [1, 2, 3, 4];
Math.max.apply(null, numbers) // 4
Math.min.apply(null, numbers) // 1
```
Passing the `numbers` array as the second argument of `apply()` results in the function being called with all values in the array as parameters.
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).
```js
var numbers = [1, 2, 3, 4];
Math.max(...numbers) // 4
Math.min(...numbers) // 1
```
This operator causes the values in the array to be expanded, or "spread", into the function's arguments.
================================================
FILE: _posts/en/javascript/2016-02-15-detect-document-ready-in-pure-js.md
================================================
---
layout: post
title: Detect document ready in pure JS
tip-number: 46
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: The cross-browser way to check if the document has loaded in pure JavaScript
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /en/detect-document-ready-in-pure-js/
categories:
- en
- javascript
---
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).
```js
if (document.readyState === 'complete') {
// The page is fully loaded
}
```
You can detect when the document is ready...
```js
let stateCheck = setInterval(() => {
if (document.readyState === 'complete') {
clearInterval(stateCheck);
// document ready
}
}, 100);
```
or with [onreadystatechange](https://developer.mozilla.org/en-US/docs/Web/Events/readystatechange)...
```js
document.onreadystatechange = () => {
if (document.readyState === 'complete') {
// document ready
}
};
```
Use `document.readyState === 'interactive'` to detect when the DOM is ready.
================================================
FILE: _posts/en/javascript/2016-02-16-basics-declarations.md
================================================
---
layout: post
title: Basics declarations
tip-number: 47
tip-username: adaniloff
tip-username-profile: https://github.com/adaniloff
tip-tldr: Understand and work with declarations.
redirect_from:
- /en/basics-declarations/
categories:
- en
- javascript
---
Below, different ways to declare variables in JavaScript.
Comments and console.log should be enough to explain what's happening here:
```js
var y, x = y = 1 //== var x; var y; x = y = 1
console.log('--> 1:', `x = ${x}, y = ${y}`)
// Will print
//--> 1: x = 1, y = 1
```
First, we just set two variables. Nothing much here.
```js
;(() => {
var x = y = 2 // == var x; x = y = 2;
console.log('2.0:', `x = ${x}, y = ${y}`)
})()
console.log('--> 2.1:', `x = ${x}, y = ${y}`)
// Will print
//2.0: x = 2, y = 2
//--> 2.1: x = 1, y = 2
```
As you can see, the code has only changed the global y, as we haven't declared the variable in the closure.
```js
;(() => {
var x, y = 3 // == var x; var y = 3;
console.log('3.0:', `x = ${x}, y = ${y}`)
})()
console.log('--> 3.1:', `x = ${x}, y = ${y}`)
// Will print
//3.0: x = undefined, y = 3
//--> 3.1: x = 1, y = 2
```
Now we declare both variables through var. Meaning they only live in the context of the closure.
```js
;(() => {
var y, x = y = 4 // == var x; var y; x = y = 4
console.log('4.0:', `x = ${x}, y = ${y}`)
})()
console.log('--> 4.1:', `x = ${x}, y = ${y}`)
// Will print
//4.0: x = 4, y = 4
//--> 4.1: x = 1, y = 2
```
Both variables have been declared using var and only after that we've set their values. As local > global, x and y are local in the closure, meaning the global x and y are untouched.
```js
x = 5 // == x = 5
console.log('--> 5:', `x = ${x}, y = ${y}`)
// Will print
//--> 5: x = 5, y = 2
```
This last line is explicit by itself.
You can test this and see the result [thanks to babel](https://babeljs.io/repl/#?experimental=false&evaluate=true&loose=false&spec=false&code=var%20y%2C%20x%20%3D%20y%20%3D%201%20%2F%2F%3D%3D%20var%20x%3B%20var%20y%3B%20x%20%3D%20y%20%3D%201%0Aconsole.log('--%3E%201%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%0A%2F%2F%20Will%20print%0A%2F%2F--%3E%201%3A%20x%20%3D%201%2C%20y%20%3D%201%0A%0A%3B(()%20%3D%3E%20%7B%20%0A%20%20var%20x%20%3D%20y%20%3D%202%20%2F%2F%20%3D%3D%20var%20x%3B%20y%20%3D%202%3B%0A%20%20console.log('2.0%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%7D)()%0Aconsole.log('--%3E%202.1%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%0A%2F%2F%20Will%20print%0A%2F%2F2.0%3A%20x%20%3D%202%2C%20y%20%3D%202%0A%2F%2F--%3E%202.1%3A%20x%20%3D%201%2C%20y%20%3D%202%0A%0A%3B(()%20%3D%3E%20%7B%20%0A%20%20var%20x%2C%20y%20%3D%203%20%2F%2F%20%3D%3D%20var%20x%3B%20var%20y%20%3D%203%3B%0A%20%20console.log('3.0%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%7D)()%0Aconsole.log('--%3E%203.1%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%0A%2F%2F%20Will%20print%0A%2F%2F3.0%3A%20x%20%3D%20undefined%2C%20y%20%3D%203%0A%2F%2F--%3E%203.1%3A%20x%20%3D%201%2C%20y%20%3D%202%0A%0A%3B(()%20%3D%3E%20%7B%20%0A%20%20var%20y%2C%20x%20%3D%20y%20%3D%204%20%2F%2F%20%3D%3D%20var%20x%3B%20var%20y%3B%20x%20%3D%20y%20%3D%203%0A%20%20console.log('4.0%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%7D)()%0Aconsole.log('--%3E%204.1%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%0A%2F%2F%20Will%20print%0A%2F%2F4.0%3A%20x%20%3D%204%2C%20y%20%3D%204%0A%2F%2F--%3E%204.1%3A%20x%20%3D%201%2C%20y%20%3D%202%0A%0Ax%20%3D%205%20%2F%2F%20%3D%3D%20x%20%3D%205%0Aconsole.log('--%3E%205%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%0A%2F%2F%20Will%20print%0A%2F%2F--%3E%205%3A%20x%20%3D%205%2C%20y%20%3D%202).
More informations available on the [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var).
Special thanks to @kurtextrem for his collaboration :)!
================================================
FILE: _posts/en/javascript/2016-02-17-reminders-about-reduce-function-usage.md
================================================
---
layout: post
title: How to `reduce()` arrays
tip-number: 48
tip-username: darul75
tip-username-profile: https://twitter.com/darul75
tip-tldr: Some reminders about using `reduce()`
redirect_from:
- /en/reminders-about-reduce-function-usage/
categories:
- en
- javascript
---
As written in documentation the `reduce()` method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.
### Signature
[reduce()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) function accepts 2 parameters (M: mandatory, O: optional):
- (M) a callback **reducer function** to be applied that deals with a pair of previous (result of previous computation) and next element until end of the list.
- (O) an **initial value** to be used as the first argument to the first call of the callback.
So let's see a common usage and later a more sophisticated one.
### Common usage (accumulation, concatenation)
We are on Amazon website (prices in $) and our caddy is quite full, let's compute total.
```javascript
// my current amazon caddy purchases
var items = [{price: 10}, {price: 120}, {price: 1000}];
// our reducer function
var reducer = function add(sumSoFar, item) { return sumSoFar + item.price; };
// do the job
var total = items.reduce(reducer, 0);
console.log(total); // 1130
```
Optional reduce function parameter was primitive integer type 0 in that first case, but it could have been an Object, an Array...instead of a primitive type,
but we will see that later.
Now, cool I received a discount coupon of 20$.
```javascript
var total = items.reduce(reducer,-20);
console.log(total); // 1110
```
### Advanced usage (combination)
This second usage example is inspired by Redux [combineReducers](http://redux.js.org/docs/api/combineReducers.html) function [source](https://github.com/reactjs/redux/blob/master/src/combineReducers.js#L93).
Idea behind is to separate reducer function into separate individual functions and at the end compute a new *single big reducer function*.
To illustrate this, let's create a single object literal with some reducers function able to compute total prices in different currency $, €...
```javascript
var reducers = {
totalInDollar: function(state, item) {
// specific statements...
return state.dollars += item.price;
},
totalInEuros : function(state, item) {
return state.euros += item.price * 0.897424392;
},
totalInPounds : function(state, item) {
return state.pounds += item.price * 0.692688671;
},
totalInYen : function(state, item) {
return state.yens += item.price * 113.852;
}
// more...
};
```
Then, we create a new swiss knife function
- responsible for applying each partial reduce functions.
- that will return a new callback reducer function
```javascript
var combineTotalPriceReducers = function(reducers) {
return function(state, item) {
return Object.keys(reducers).reduce(
function(nextState, key) {
reducers[key](state, item);
return state;
},
{}
);
}
};
```
Now let's see how using it.
```javascript
var bigTotalPriceReducer = combineTotalPriceReducers(reducers);
var initialState = {dollars: 0, euros:0, yens: 0, pounds: 0};
var totals = items.reduce(bigTotalPriceReducer, initialState);
console.log(totals);
/*
Object {dollars: 1130, euros: 1015.11531904, yens: 127524.24, pounds: 785.81131152}
*/
```
I hope this approach can give you another idea of using reduce() function for your own needs.
Your reduce function could handle an history of each computation by instance as it is done in Ramdajs with [scan](http://ramdajs.com/docs/#scan) function
[JSFiddle to play with](https://jsfiddle.net/darul75/81tgt0cd/)
================================================
FILE: _posts/en/javascript/2016-02-26-extract-unix-timestamp-easily.md
================================================
---
layout: post
title: Easiest way to extract unix timestamp in JS
tip-number: 49
tip-username: nmrony
tip-username-profile: https://github.com/nmrony
tip-tldr: In Javascript you can easily get the unix timestamp
redirect_from:
- /en/extract-unix-timestamp-easily/
categories:
- en
- javascript
---
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
```js
const dateTime = Date.now();
const timestamp = Math.floor(dateTime / 1000);
```
or
```js
const dateTime = new Date().getTime();
const timestamp = Math.floor(dateTime / 1000);
```
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
```js
const dateTime = new Date('2012-06-08').getTime();
const timestamp = Math.floor(dateTime / 1000);
```
You can just add a `+` sign also when declaring a `Date` object like below
```js
const dateTime = +new Date();
const timestamp = Math.floor(dateTime / 1000);
```
or for specific date
```js
const dateTime = +new Date('2012-06-08');
const timestamp = Math.floor(dateTime / 1000);
```
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
* [Date.prototype.valueOf](http://es5.github.io/#x15.9.5.8)
* [Unary + operator](http://es5.github.io/#x11.4.6)
* [toNumber()](http://es5.github.io/#x9.3)
* [Date Javascript MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)
* [Date.parse()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse)
================================================
FILE: _posts/en/javascript/2016-03-03-helpful-console-log-hacks.md
================================================
---
layout: post
title: Helpful Console Logging Tricks
tip-number: 50
tip-username: zackhall
tip-username-profile: https://twitter.com/zthall
tip-tldr: Helpful logging techniques using coercion and conditonal breakpoints.
redirect_from:
- /en/helpful-console-log-hacks/
categories:
- en
- javascript
---
## Using conditional breakpoints to log data
If you wanted to log to the console a value each time a function is called, you can use conditional break points to do this. Open up your dev tools, find the function where you'd like to log data to the console and set a breakpoint with the following condition:
```js
console.log(data.value) && false
```
A conditional breakpoint pauses the page thread only if the condition for the breakpoint evaluates to true. So by using a condition like console.log('foo') && false it's guaranteed to evaluate to false since you're putting the literal false in the AND condition. So this will not pause the page thread when it's hit, but it will log data to the console. This can also be used to count how many times a function or callback is called.
Here's how you can set a conditional breakpoint in [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") and [Safari](https://developer.apple.com/library/mac/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/Debugger/Debugger.html "Managing Breakpoints in Safari").
## Printing a function variable to console
Have you ever logged a function variable to the console and weren't able to just view the function's code? The quickest way to see the function's code is to coerce it to a string using concatenation with an empty string.
```js
console.log(funcVariable + '');
```
================================================
FILE: _posts/en/javascript/2016-03-16-DOM-event-listening-made-easy.md
================================================
---
layout: post
title: DOM event listening made easy
tip-number: 51
tip-username: octopitus
tip-username-profile: https://github.com/octopitus
tip-tldr: An elegant and easy way to handle DOM events
redirect_from:
- /en/DOM-event-listening-made-easy/
categories:
- en
- javascript
---
Many of us are still doing these things:
- `element.addEventListener('type', obj.method.bind(obj))`
- `element.addEventListener('type', function (event) {})`
- `element.addEventListener('type', (event) => {})`
The above examples all create new anonymous event handlers that can't be removed when no longer needed. This may cause performance problems or unexpected logic bugs, when handlers that you no longer need still get accidentally triggered through unexpected user interactions or [event bubbling](http://www.javascripter.net/faq/eventbubbling.htm).
Safer event-handling patterns include the following:
Use a reference:
```js
const handler = function () {
console.log("Tada!")
}
element.addEventListener("click", handler)
// Later on
element.removeEventListener("click", handler)
```
Named function that removes itself:
```js
element.addEventListener('click', function click(e) {
if (someCondition) {
return e.currentTarget.removeEventListener('click', click);
}
});
```
A better approach:
```js
function handleEvent (eventName, {onElement, withCallback, useCapture = false} = {}, thisArg) {
const element = onElement || document.documentElement
function handler (event) {
if (typeof withCallback === 'function') {
withCallback.call(thisArg, event)
}
}
handler.destroy = function () {
return element.removeEventListener(eventName, handler, useCapture)
}
element.addEventListener(eventName, handler, useCapture)
return handler
}
// Anytime you need
const handleClick = handleEvent('click', {
onElement: element,
withCallback: (event) => {
console.log('Tada!')
}
})
// And anytime you want to remove it
handleClick.destroy()
```
================================================
FILE: _posts/en/javascript/2016-04-05-return-values-with-the-new-operator.md
================================================
---
layout: post
title: Return Values with the 'new' Operator
tip-number: 52
tip-username: Morklympious
tip-username-profile: https://github.com/morklympious
tip-tldr: Understand what gets returned when using new vs. not using new.
redirect_from:
- /en/return-values-with-the-new-operator/
categories:
- en
- javascript
---
You're going to run into some instances where you'll be using `new` to allocate new objects in JavaScript. It's going to blow your mind unless you read this tip to understand what's happening behind the scenes.
The `new` operator in JavaScript is an operator that, under reasonable circumstances, returns a new instance of an object. Let's say we have a constructor function:
````js
function Thing() {
this.one = 1;
this.two = 2;
}
var myThing = new Thing();
myThing.one // 1
myThing.two // 2
````
__Note__: `this` refers to the new object created by `new`. Otherwise if `Thing()` is called without `new`, __no object is created__, and `this` is going to point to the global object, which is `window`. This means that:
1. You'll suddenly have two new global variables named `one` and `two`.
2. `myThing` is now undefined, since nothing is returned in `Thing()`.
Now that you get that example, here's where things get a little bit wonky. Let's say I add something to the constructor function, a little SPICE:
````js
function Thing() {
this.one = 1;
this.two = 2;
return 5;
}
var myThing = new Thing();
````
Now, what does myThing equal? Is it 5? is it an object? Is it my crippled sense of self-worth? The world may never know!
Except the world does know:
````js
myThing.one // 1
myThing.two // 2
````
Interestingly enough, we never actually see the five that we supposedly 'returned' from our constructor. That's weird, isn't it? What are you doing function? WHERE'S THE FIVE? Let's try it with something else.
Let's return a non-primitive type instead, something like an object.
````js
function Thing() {
this.one = 1;
this.two = 2;
return {
three: 3,
four: 4
};
}
var myThing = new Thing();
````
Let's check it out. A quick console.log reveals all:
````js
console.log(myThing);
/*
Object {three: 3, four: 4}
What happened to this.one and this.two!?
They've been stomped, my friend.
*/
````
__Here's where we learn:__ When you invoke a function with the `new` keyword, you can set properties on it using the keyword `this` (but you probably already knew that). Returning a primitive value from a function you called with the `new` keyword will not return the value you specified, but instead will return the `this` instance of the function (the one you put properties on, like `this.one = 1;`).
However, returning a non-primitive, like an `object`, `array`, or `function` will stomp on the `this` instance, and return that non-primitive instead, effectively ruining all the hard work you did assigning everything to `this`.
================================================
FILE: _posts/en/javascript/2016-04-21-get-file-extension.md
================================================
---
layout: post
title: Get File Extension
tip-number: 53
tip-username: richzw
tip-username-profile: https://github.com/richzw
tip-tldr: How to get the file extension more efficiently?
redirect_from:
- /en/get-file-extension/
categories:
- en
- javascript
---
### Question: How to get the file extension?
```javascript
var file1 = "50.xsl";
var file2 = "30.doc";
getFileExtension(file1); //returs xsl
getFileExtension(file2); //returs doc
function getFileExtension(filename) {
/*TODO*/
}
```
### Solution 1: Regular Expression
```js
function getFileExtension1(filename) {
return (/[.]/.exec(filename)) ? /[^.]+$/.exec(filename)[0] : undefined;
}
```
### Solution 2: String `split` method
```js
function getFileExtension2(filename) {
return filename.split('.').pop();
}
```
Those two solutions couldnot handle some edge cases, here is another more robust solution.
### Solution3: String `slice`, `lastIndexOf` methods
```js
function getFileExtension3(filename) {
return filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2);
}
console.log(getFileExtension3('')); // ''
console.log(getFileExtension3('filename')); // ''
console.log(getFileExtension3('filename.txt')); // 'txt'
console.log(getFileExtension3('.hiddenfile')); // ''
console.log(getFileExtension3('filename.with.many.dots.ext')); // 'ext'
```
_How does it works?_
- [String.lastIndexOf()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf) method returns the last occurrence of the specified value (`'.'` in this case). Returns `-1` if the value is not found.
- The return values of `lastIndexOf` for parameter `'filename'` and `'.hiddenfile'` are `-1` and `0` respectively. [Zero-fill right shift operator (>>>)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#%3E%3E%3E_%28Zero-fill_right_shift%29) will transform `-1` to `4294967295` and `-2` to `4294967294`, here is one trick to insure the filename unchanged in those edge cases.
- [String.prototype.slice()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice) extracts file extension from the index that was calculated above. If the index is more than the length of the filename, the result is `""`.
### Comparison
| Solution | Paramters | Results |
| ----------------------------------------- |:-------------------:|:--------:|
| Solution 1: Regular Expression | '' 'filename' 'filename.txt' '.hiddenfile' 'filename.with.many.dots.ext' | undefined undefined 'txt' 'hiddenfile' 'ext' |
| Solution 2: String `split` | '' 'filename' 'filename.txt' '.hiddenfile' 'filename.with.many.dots.ext' | '' 'filename' 'txt' 'hiddenfile' 'ext' |
| Solution 3: String `slice`, `lastIndexOf` | '' 'filename' 'filename.txt' '.hiddenfile' 'filename.with.many.dots.ext' | '' '' 'txt' '' 'ext' |
### Live Demo and Performance
[Here](https://jsbin.com/tipofu/edit?js,console) is the live demo of the above codes.
[Here](http://jsperf.com/extract-file-extension) is the performance test of those 3 solutions.
### Source
[How can I get file extensions with JavaScript](http://stackoverflow.com/questions/190852/how-can-i-get-file-extensions-with-javascript)
================================================
FILE: _posts/en/javascript/2016-05-06-use-optional-arguments.md
================================================
---
layout: post
title: How to use optional arguments in functions (with optional callback)
tip-number: 54
tip-username: alphashuro
tip-username-profile: https://github.com/alphashuro
tip-tldr: You can make function arguments and callback optional
redirect_from:
- /en/use-optional-arguments/
categories:
- en
- javascript
---
Example function where arguments 2 and 3 are optional
```javascript
function example( err, optionalA, optionalB, callback ) {
// retrieve arguments as array
var args = new Array(arguments.length);
for(var i = 0; i < args.length; ++i) {
args[i] = arguments[i];
};
// first argument is the error object
// shift() removes the first item from the
// array and returns it
err = args.shift();
// if last argument is a function then its the callback function.
// pop() removes the last item in the array
// and returns it
if (typeof args[args.length-1] === 'function') {
callback = args.pop();
}
// if args still holds items, these are
// your optional items which you could
// retrieve one by one like this:
if (args.length > 0) optionalA = args.shift(); else optionalA = null;
if (args.length > 0) optionalB = args.shift(); else optionalB = null;
// continue as usual: check for errors
if (err) {
return callback && callback(err);
}
// for tutorial purposes, log the optional parameters
console.log('optionalA:', optionalA);
console.log('optionalB:', optionalB);
console.log('callback:', callback);
/* do your thing */
}
// ES6 with shorter, more terse code
function example(...args) {
// first argument is the error object
const err = args.shift();
// if last argument is a function then its the callback function
const callback = (typeof args[args.length-1] === 'function') ? args.pop() : null;
// if args still holds items, these are your optional items which you could retrieve one by one like this:
const optionalA = (args.length > 0) ? args.shift() : null;
const optionalB = (args.length > 0) ? args.shift() : null;
// ... repeat for more items
if (err && callback) return callback(err);
/* do your thing */
}
// invoke example function with and without optional arguments
example(null, 'AA');
example(null, function (err) { /* do something */ });
example(null, 'AA', function (err) {});
example(null, 'AAAA', 'BBBB', function (err) {});
```
### How do you determine if optionalA or optionalB is intended?
Design your function to require optionalA in order to accept optionalB
================================================
FILE: _posts/en/javascript/2016-05-12-make-easy-loop-on-array.md
================================================
---
layout: post
title: Create an easy loop using an array
tip-number: 55
tip-username: jamet-julien
tip-username-profile: https://github.com/jamet-julien
tip-tldr: Sometimes, we need to loop endlessly over an array of items, like a carousel of images or an audio playlist. Here’s how to take an array and give it “looping powers”
redirect_from:
- /en/make-easy-loop-on-array/
categories:
- en
- javascript
---
Sometimes, we need to loop endlessly over an array of items, like a carousel of images or an audio playlist. Here's how to take an array and give it "looping powers":
```js
var aList = ['A','B','C','D','E'];
function make_looper( arr ){
arr.loop_idx = 0;
// return current item
arr.current = function(){
if( this.loop_idx < 0 ){// First verification
this.loop_idx = this.length - 1;// update loop_idx
}
if( this.loop_idx >= this.length ){// second verification
this.loop_idx = 0;// update loop_idx
}
return arr[ this.loop_idx ];//return item
};
// increment loop_idx AND return new current
arr.next = function(){
this.loop_idx++;
return this.current();
};
// decrement loop_idx AND return new current
arr.prev = function(){
this.loop_idx--;
return this.current();
};
}
make_looper( aList);
aList.current();// -> A
aList.next();// -> B
aList.next();// -> C
aList.next();// -> D
aList.next();// -> E
aList.next();// -> A
aList.pop() ;// -> E
aList.prev();// -> D
aList.prev();// -> C
aList.prev();// -> B
aList.prev();// -> A
aList.prev();// -> D
```
Using the ```%``` ( Modulus ) operator is prettier.The modulus return division's rest ( ``` 2 % 5 = 1``` and ``` 5 % 5 = 0```):
```js
var aList = ['A','B','C','D','E'];
function make_looper( arr ){
arr.loop_idx = 0;
// return current item
arr.current = function(){
this.loop_idx = ( this.loop_idx ) % this.length;// no verification !!
return arr[ this.loop_idx ];
};
// increment loop_idx AND return new current
arr.next = function(){
this.loop_idx++;
return this.current();
};
// decrement loop_idx AND return new current
arr.prev = function(){
this.loop_idx += this.length - 1;
return this.current();
};
}
make_looper( aList);
aList.current();// -> A
aList.next();// -> B
aList.next();// -> C
aList.next();// -> D
aList.next();// -> E
aList.next();// -> A
aList.pop() ;// -> E
aList.prev();// -> D
aList.prev();// -> C
aList.prev();// -> B
aList.prev();// -> A
aList.prev();// -> D
```
================================================
FILE: _posts/en/javascript/2016-08-02-copy-to-clipboard.md
================================================
---
layout: post
title: Copy to Clipboard
tip-number: 56
tip-username: loverajoel
tip-username-profile: https://twitter.com/loverajoel
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.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /en/copy-to-clipboard/
categories:
- en
- javascript
---
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.
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).
`execCommand('copy')` will copy the actual selected content.
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.
```js
document.querySelector('#input').select();
document.execCommand('copy');
```
##### Playground
================================================
FILE: _posts/en/javascript/2016-08-10-comma-operaton-in-js.md
================================================
---
layout: post
title: Comma operator in JS
tip-number: 57
tip-username: bhaskarmelkani
tip-username-profile: https://www.twitter.com/bhaskarmelkani
tip-tldr: When placed in an expression, it evaluates every expression from left to right and returns the last one.
redirect_from:
- /en/comma-operaton-in-js/
categories:
- en
- javascript
---
Apart from being just a delimiter, the comma operator allows you to put multiple statements in a place where one statement is expected.
Eg:-
```js
for(var i=0, j=0; i<5; i++, j++, j++){
console.log("i:"+i+", j:"+j);
}
```
Output:-
```js
i:0, j:0
i:1, j:2
i:2, j:4
i:3, j:6
i:4, j:8
```
When placed in an expression, it evaluates every expression from left to right and returns the right most expression.
Eg:-
```js
function a(){console.log('a'); return 'a';}
function b(){console.log('b'); return 'b';}
function c(){console.log('c'); return 'c';}
var x = (a(), b(), c());
console.log(x); // Outputs "c"
```
Output:-
```js
"a"
"b"
"c"
"c"
```
* Note: The comma(`,`) operator has the lowest priority of all javascript operators, so without the parenthesis the expression would become: `(x = a()), b(), c();`.
##### Playground
================================================
FILE: _posts/en/javascript/2016-08-17-break-continue-loop-functional.md
================================================
---
layout: post
title: Breaking or continuing loop in functional programming
tip-number: 58
tip-username: vamshisuram
tip-username-profile: https://github.com/vamshisuram
tip-tldr: A common task for us is iterate over a list looking for a value or values, but we can't return from inside a loop so we will have to iterate the whole array, even if the item we search is the first in the list, in this tip we will see how to short circuit with `.some` and `.every`.
redirect_from:
- /en/break-continue-loop-functional/
categories:
- en
- javascript
---
A common requirement of iteration is cancelation. Using `for` loops we can `break` to end iteration early.
```javascript
const a = [0, 1, 2, 3, 4];
for (var i = 0; i < a.length; i++) {
if (a[i] === 2) {
break; // stop the loop
}
console.log(a[i]);
}
//> 0, 1
```
Another common requirement is to close over our variables.
A quick approach is to use `.forEach` but
then we lack the ability to `break`. In this situation the closest we get is `continue` functionality through `return`.
```javascript
[0, 1, 2, 3, 4].forEach(function(val, i) {
if (val === 2) {
// how do we stop?
return true;
}
console.log(val); // your code
});
//> 0, 1, 3, 4
```
The `.some` is a method on Array prototype. It tests whether some element in the array passes the test implemented by the provided function. If any value is returning true, then it stops executing. Here is a [MDN link](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/some) for more details.
An example quoted from that link
```javascript
const isBiggerThan10 = numb => numb > 10;
[2, 5, 8, 1, 4].some(isBiggerThan10); // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true
```
Using `.some` we get iteration functionally similar to `.forEach` but with the ability to `break` through `return` instead.
```javascript
[0, 1, 2, 3, 4].some(function(val, i) {
if (val === 2) {
return true;
}
console.log(val); // your code
});
//> 0, 1
```
You keep returning `false` to make it `continue` to next item. When you return `true`, the loop will `break` and `a.some(..)` will `return` `true`.
```javascript
// Array contains 2
const isTwoPresent = [0, 1, 2, 3, 4].some(function(val, i) {
if (val === 2) {
return true; // break
}
});
console.log(isTwoPresent);
//> true
```
Also there is `.every`, which can be used. We have to return the opposite boolean compared to `.some`.
##### Playground
================================================
FILE: _posts/en/javascript/2016-08-25-keyword-var-vs-let.md
================================================
---
layout: post
title: ES6, var vs let
tip-number: 59
tip-username: richzw
tip-username-profile: https://github.com/richzw
tip-tldr: In this tip, I will introduce the block-scope difference between keyword var and let. Should I replace var by let? let's take a look
redirect_from:
- /en/keyword-var-vs-let/
categories:
- en
- javascript
---
### Overview
- The scope of a variable defined with `var` is function scope or declared outside any function, global.
- The scope of a variable defined with `let` is block scope.
```js
function varvslet() {
console.log(i); // i is undefined due to hoisting
// console.log(j); // ReferenceError: j is not defined
for( var i = 0; i < 3; i++ ) {
console.log(i); // 0, 1, 2
};
console.log(i); // 3
// console.log(j); // ReferenceError: j is not defined
for( let j = 0; j < 3; j++ ) {
console.log(j);
};
console.log(i); // 3
// console.log(j); // ReferenceError: j is not defined
}
```
### Difference Details
- Variable Hoisting
`let` will not hoist to the entire scope of the block they appear in. By contrast, `var` could hoist as below.
```js
{
console.log(c); // undefined. Due to hoisting
var c = 2;
}
{
console.log(b); // ReferenceError: b is not defined
let b = 3;
}
```
- Closure in Loop
`let` in the loop can re-binds it to each iteration of the loop, making sure to re-assign it the value from the end of the previous loop iteration, so it can be used to avoid issue with closures.
```js
for (var i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i); // output '5' 5 times
}, 100);
}
```
After replacing `var` with `let`
```js
// print 1, 2, 3, 4, 5
for (let i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i); // output 0, 1, 2, 3, 4
}, 100);
}
```
### Should I replace `var` with `let`?
> NO, `let` is the new block scoping `var`. That statement emphasizes that `let` should replace `var` only when `var` was already signaling
block scoping stylistically. Otherwise, leave `var` alone. `let` improves scoping options in JS, not replaces. `var` is still a useful signal for variables that are used throughout the function.
### `let` compatibility
- In server side, such as Node.js, you can safely use the `let` statement now.
- In client side, through a transpiler (like [Traceur](https://github.com/google/traceur-compiler)), you can safely use the `let` statement. Otherwise, please consider the browser support [here](http://caniuse.com/#search=let)
### Playground
### More info
- [Let keyword vs var keyword](http://stackoverflow.com/questions/762011/let-keyword-vs-var-keyword)
- [For and against let](https://davidwalsh.name/for-and-against-let)
- [Explanation of `let` and block scoping with for loops](http://stackoverflow.com/questions/30899612/explanation-of-let-and-block-scoping-with-for-loops/30900289#30900289).
================================================
FILE: _posts/en/javascript/2016-10-28-three-useful-hacks.md
================================================
---
layout: post
title: Three useful hacks
tip-number: 60
tip-username: leandrosimoes
tip-username-profile: https://github.com/leandrosimoes
tip-tldr: Three very useful and syntax sugar hacks to speed up your development.
redirect_from:
- /en/three-useful-hacks/
categories:
- en
- javascript
---
#### Getting array items from behind to front
If you want to get the array items from behind to front, just do this:
```javascript
var newArray = [1, 2, 3, 4];
console.log(newArray.slice(-1)); // [4]
console.log(newArray.slice(-2)); // [3, 4]
console.log(newArray.slice(-3)); // [2, 3, 4]
console.log(newArray.slice(-4)); // [1, 2, 3, 4]
```
#### Short-circuits conditionals
If you have to execute a function just if a condition is `true`, like this:
```javascript
if(condition){
dosomething();
}
```
You can use a short-circuit just like this:
```javascript
condition && dosomething();
```
#### Set variable default values using "||"
If you have to set a default value to variables, you can simple do this:
```javascript
var a;
console.log(a); //undefined
a = a || 'default value';
console.log(a); //default value
a = a || 'new value';
console.log(a); //default value
```
================================================
FILE: _posts/en/javascript/2017-01-19-binding-objects-to-functions.md
================================================
---
layout: post
title: Binding objects to functions
tip-number: 61
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: Understanding how to use `Bind` method with objects and functions in JavaScript
redirect_from:
- /en/binding-objects-to-functions/
categories:
- en
- javascript
---
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.
### Bind syntax
```js
fun.bind(thisArg[, arg1[, arg2[, ...]]])
```
## Parameters
**thisArg**
`this` parameter value to be passed to target function while calling the `bound` function.
**arg1, arg2, ...**
Prepended arguments to be passed to the `bound` function while invoking the target function.
**Return value**
A copy of the given function along with the specified `this` value and initial arguments.
### Bind method in action in JS
```js
const myCar = {
brand: 'Ford',
type: 'Sedan',
color: 'Red'
};
const getBrand = function () {
console.log(this.brand);
};
const getType = function () {
console.log(this.type);
};
const getColor = function () {
console.log(this.color);
};
getBrand(); // object not bind,undefined
getBrand(myCar); // object not bind,undefined
getType.bind(myCar)(); // Sedan
let boundGetColor = getColor.bind(myCar);
boundGetColor(); // Red
```
================================================
FILE: _posts/en/javascript/2017-03-09-working-with-websocket-timeout.md
================================================
---
layout: post
title: Working With Websocket Timeout
tip-number: 63
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: A trick to control the timeout
categories:
- en
- javascript
---
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.
Let’s have a look on implementation-
```js
var timerID = 0;
function keepAlive() {
var timeout = 20000;
if (webSocket.readyState == webSocket.OPEN) {
webSocket.send('');
}
timerId = setTimeout(keepAlive, timeout);
}
function cancelKeepAlive() {
if (timerId) {
clearTimeout(timerId);
}
}
```
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.
Yes! We have perfectly implemented hack for websocket timeout problem.
================================================
FILE: _posts/en/javascript/2017-03-12-3-array-hacks.md
================================================
---
layout: post
title: 3 Array Hacks
tip-number: 64
tip-username: hassanhelfi
tip-username-profile: https://twitter.com/hassanhelfi
tip-tldr: Arrays are everywhere and with the new spread operators introduced in ECMAScript 6, you can do awesome things with them. In this post I will show you 3 useful tricks you can use when programming.
categories:
- en
- javascript
---
Arrays are everywhere in JavaScript and with the new [spread operators](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Spread_operator) introduced in ECMAScript 6, you can do awesome things with them. In this post I will show you 3 useful tricks you can use when programming.
### 1. Iterating through an empty array
JavaScript arrays are sparse in nature in that there are a lot of holes in them. Try creating an array using the Array’s constructor and you will see what I mean.
```javascript
> const arr = new Array(4);
[undefined, undefined, undefined, undefined]
```
You may find that iterating over a sparse array to apply a certain transformation is hard.
```javascript
> const arr = new Array(4);
> arr.map((elem, index) => index);
[undefined, undefined, undefined, undefined]
```
To solve this, you can use `Array.apply` when creating the array.
```javascript
> const arr = Array.apply(null, new Array(4));
> arr.map((elem, index) => index);
[0, 1, 2, 3]
```
### 2. Passing an empty parameter to a method
If you want to call a method and ignore one of its parameters, then JavaScript will complain if you keep it empty.
```javascript
> method('parameter1', , 'parameter3');
Uncaught SyntaxError: Unexpected token ,
```
A workaround that people usually resort to is to pass either `null` or `undefined`.
```javascript
> method('parameter1', null, 'parameter3') // or
> method('parameter1', undefined, 'parameter3');
```
I personally don’t like using `null` since JavaScript treats it as an object and that’s just weird. With the introduction of spread operators in ES6, there is a neater way of passing empty parameters to a method. As previously mentioned, arrays are sparse in nature and so passing empty values to it is totally okay. We'll use this to our advantage.
```javascript
> method(...['parameter1', , 'parameter3']); // works!
```
### 3. Unique array values
I always wonder why the Array constructor does not have a designated method to facilitate the use of unique array values. Spread operators are here for the rescue. Use spread operators with the `Set` constructor to generate unique array values.
```javascript
> const arr = [...new Set([1, 2, 3, 3])];
[1, 2, 3]
```
================================================
FILE: _posts/en/javascript/2017-03-16-tapping-for-quick-debugging.md
================================================
---
layout: post
title: Tapping for quick debugging
tip-number: 65
tip-username: loverajoel
tip-username-profile: https://twitter.com/loverajoel
tip-tldr: This little beastie here is tap. A really useful function for quick-debugging chains of function calls, anonymous functions and, actually, whatever you just want to print.
tip-md-link: https://github.com/loverajoel/jstips/blob/master/_posts/en/javascript/2017-03-16-tapping-for-quick-debugging.md
categories:
- en
- javascript
---
This little beastie here is tap. A really useful function for quick-debugging
chains of function calls, anonymous functions and, actually, whatever you just
want to print.
``` javascript
function tap(x) {
console.log(x);
return x;
}
```
Why would you use instead of good old `console.log`? Let me show you an example:
``` javascript
bank_totals_by_client(bank_info(1, banks), table)
.filter(c => c.balance > 25000)
.sort((c1, c2) => c1.balance <= c2.balance ? 1 : -1 )
.map(c =>
console.log(`${c.id} | ${c.tax_number} (${c.name}) => ${c.balance}`));
```
Now, suppose you're getting nothing from this chain (possibly an error).
Where is it failing? Maybe `bank_info` isn't returning anything, so we'll tap it:
``` javascript
bank_totals_by_client(tap(bank_info(1, banks)), table)
```
Depending on our particular implementation, it might print something or not.
I'll assume the information that we got from our tapping was correct and
therefore, bank_info isn't causing anything.
We must then move on to the next chain, filter.
``` javascript
.filter(c => tap(c).balance > 25000)
```
Are we receiving any c's (clients actually)? If so, then bank_totals_by_client
works alright. Maybe it's the condition within the filter?
``` javascript
.filter(c => tap(c.balance > 25000))
```
Ah! Sweet, we see nothing but `false` printed, so there's no client with >25000,
that's why the function was returning nothing.
## (Bonus) A more advanced tap.
``` javascript
function tap(x, fn = x => x) {
console.log(fn(x));
return x;
}
```
Now we're talking about a more advanced beast, what if we wanted to perform a
certain operation *prior* to tapping? i.e, we want to access a certain object
property, perform a logical operation, etc. with our tapped object? Then we
call old good tap with an extra argument, a function to be applied at the moment
of tapping.
``` javascript
tap(3, x => x + 2) === 3; // prints 5, but expression evaluates to true, why :-)?
```
================================================
FILE: _posts/en/javascript/2017-03-29-recursion-iteration-and-tail-calls-in-js.md
================================================
---
layout: post
title: Recursion, iteration and tail calls in JS
tip-number: 67
tip-username: loverajoel
tip-username-profile: https://twitter.com/loverajoel
tip-tldr: If you've been on the business for some time, you have, most likely, come across the definition of recursion, for which the factorial of a given number `n! = n * n - 1 * ... * 1` is a standard example...
tip-md-link: https://github.com/loverajoel/jstips/blob/master/_posts/en/javascript/2017-03-29-recursion-iteration-and-tail-calls-in-js.md
categories:
- en
- javascript
---
If you've been on the business for some time, you have, most likely,
come across the definition of recursion, for which the factorial of
a given number `n! = n * (n - 1) * ... * 1` is a standard example.
``` javascript
function factorial(n) {
if (n === 0) {
return 1;
}
return n * factorial(n - 1);
}
```
The example shown above is but the most naive implementation of the
factorial function.
For the sake of completeness, let's look at how this executes for
`n = 6`:
- factorial(6)
- 6 * factorial(5)
- 5 * factorial (4)
- 4 * factorial(3)
- 3 * factorial(2)
- 2 * factorial(1)
- 1 * factorial(0)
- 1
- (resuming previous execution) 1 * 1 = 1
- (resuming...) 2 * 1 = 2
- (...) 3 * 2 = 6
- ... 4 * 6 = 24
- 5 * 24 = 120
- 6 * 120 = 720
- factorial(6) = 720
Now, we must be very cautious as to what's happening so we can understand
what is to come next.
When we invoke a function, several things happen at once. The location to
which we must return to after calling the function is saved, along with
the information of the current frame (i.e, the value of n). Then space is
allocated for the new function and a new frame is born.
This goes on and on, we keep stacking these frames and then we unwind that
stack, replacing function calls with values returned by them.
Another thing to notice is the shape of the process generated by our function.
You might not be surprised if I call this shape *recursive*. We have, thus, a
*recursive process*.
Let's take a look at a second implementation of this function.
``` javascript
function factorial(n, res) {
if (n === 0) {
return res;
}
return factorial(n - 1, res * n);
}
```
We can encapsulate functionality a bit further by defining an inner function.
``` javascript
function factorial(n) {
function inner_factorial(n, res) {
if (n === 0) {
return res;
}
return inner_factorial(n - 1, res * n);
}
return inner_factorial(n, 1);
}
```
Let's take a look at how this gets executed:
- factorial(6)
- inner anonymous function (iaf) gets called with (n = 6, res = 1)
- iaf(5, 1 * 6)
- iaf(4, 6 * 5)
- iaf(3, 30 * 4)
- iaf(2, 120 * 3)
- iaf(1, 360 * 2)
- iaf(0, 720)
- 720
- 720
- 720
- 720
- 720
- 720
- 720
- iaf (6, 1) = 720
- factorial(6) = 720
You might notice that we didn't need to perform any calculation after unwinding
the stack. We just returned a value. But, according to our rules, we had to save
the state as a stack frame, even if it weren't of any use later in the chain.
Our rules, however, are not applied to every language out there. In fact, in
Scheme it's mandatory for such chains to be optimized with tail call
optimization. This ensures that our stack is not filled with unnecessary frames.
Our previous calculation would look, thus, this way:
- factorial(6)
- iaf(6, 1)
- iaf(5, 6)
- iaf(4, 30)
- iaf(3, 120)
- iaf(2, 360)
- iaf(1, 720)
- iaf(0, 720)
- 720
Which in turns, looks an awfully lot like
``` javascript
res = 1;
n = 6;
while(n > 1) {
res = res * n;
n--;
}
```
This means, we actually have an *iterative process*, even if we're using
recursion. How cool is that?
The good news is, this is a feature in ES6. As long as your recursive call
is in tail position and your function has strict mode, tail call optimization
will kick in and save you from having a `maximum stack size exceeded` error.
UPDATE Dec 1, 2017:
The only major browser with tail call optimization is Safari.1 V8 has an implentation2 but has not shipped it yet3 for the reasons listed.
1: https://kangax.github.io/compat-table/es6/#test-proper_tail_calls_(tail_call_optimisation)
2: https://bugs.chromium.org/p/v8/issues/detail?id=4698
3: https://v8project.blogspot.com/2016/04/es6-es7-and-beyond.html
================================================
FILE: _posts/en/javascript/2017-04-03-why-you-should-use-Object.is()-in-equality-comparison.md
================================================
---
layout: post
title: Why you should use Object.is() in equality comparison
tip-number: 68
tip-username: TarekAlQaddy
tip-username-profile: https://github.com/TarekAlQaddy
tip-tldr: A good solution for the looseness of equality comparisons in javascript
categories:
- en
- javascript
---
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".
``` javascript
0 == ' ' //true
null == undefined //true
[1] == true //true
```
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:
``` javascript
NaN === NaN //false
```
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:
``` javascript
Object.is(0 , ' '); //false
Object.is(null, undefined); //false
Object.is([1], true); //false
Object.is(NaN, NaN); //true
```
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.
Now this table illustrates..

## References:
[Equality comparisons and sameness](http://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness)
================================================
FILE: _posts/en/javascript/2017-04-05-picking-and-rejecting-object-properties.md
================================================
---
layout: post
title: Picking and rejecting object properties
tip-number: 70
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: Sometimes we need to whitelist certain attributes from an object, say we've got an array representation of a database table and we need to `select` just a few fields for some function.
categories:
- en
- javascript
---
Sometimes we need to whitelist certain attributes from an object, say we've
got an array representation of a database table and we need to `select` just
a few fields for some function:
``` javascript
function pick(obj, keys) {
return keys.map(k => k in obj ? {[k]: obj[k]} : {})
.reduce((res, o) => Object.assign(res, o), {});
}
const row = {
'accounts.id': 1,
'client.name': 'John Doe',
'bank.code': 'MDAKW213'
};
const table = [
row,
{'accounts.id': 3, 'client.name': 'Steve Doe', 'bank.code': 'STV12JB'}
];
pick(row, ['client.name']); // Get client name
table.map(row => pick(row, ['client.name'])); // Get a list of client names
```
There's a bit of skulduggery going on in pick. First, we `map` a function over
the keys that will return, each time, an object with only the attribute pointed
by the current key (or an empty object if there's no such attribute in the
object). Then, we `reduce` this collection of single-attribute objects by
merging the objects.
But what if we want to `reject` the attributes? Well, the function changes a bit
``` javascript
function reject(obj, keys) {
return Object.keys(obj)
.filter(k => !keys.includes(k))
.map(k => Object.assign({}, {[k]: obj[k]}))
.reduce((res, o) => Object.assign(res, o), {});
}
// or, reusing pick
function reject(obj, keys) {
const vkeys = Object.keys(obj)
.filter(k => !keys.includes(k));
return pick(obj, vkeys);
}
reject({a: 2, b: 3, c: 4}, ['a', 'b']); // => {c: 4}
```
================================================
FILE: _posts/en/javascript/2017-04-11-protocols-for-the-brave.md
================================================
---
layout: post
title: Protocols for the Brave
tip-number: 73
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: You might have heard about the old ways gaining hype recently, and we don't mean praying to the gods of the north. Today we're introducing a feature found in Clojure which allows you to define interfaces for your classes.
categories:
- en
- javascript
---
You might have heard about the old ways gaining hype recently, and we don't
mean praying to the gods of the north.
Functional programming is the rediscovered toy which is bringing some sanity
to the world of mutable state and global bindings.
Today we're introducing a feature found in Clojure which allows you to define
interfaces for your classes. Let's look at one-off implementation:
``` javascript
const protocols = (...ps) => ps.reduce((c, p) => p(c), Object);
const Mappable = (klass) => {
return class extends klass {
map() {
throw 'Not implemented';
}
};
};
const Foldable = (klass) => {
return class extends klass {
fold() {
throw 'Not implemented';
}
};
};
class NaturalNumbers extends protocols(Mappable, Foldable) {
constructor() {
super();
this.elements = [1,2,3,4,5,6,7,8,9];
}
map (f) {
return this.elements.map(f);
}
fold (f) {
return this.elements.reduce(f, this.elements, 0);
}
}
```
Yes, we're building a chain of class inheritance up there with that reduce boy.
It's pretty cool. We're doing it dynamically! You see, each protocol receives
a base class (Object) and extends it somehow returning the new class. The idea
is similar to that of interfaces.
We supply method signatures for the protocol and make sure we provide
implementations for it on our base classes.
What's so cool about it? We get to write things like these:
``` javascript
const map = f => o => o.map(f);
const fold = f => o => o.fold(f);
const compose = (... fns) => fns.reduce((acc, f) => (x) => acc(f(x)), id);
```
Ok, maybe we could have written those two functions without the above fuzz but,
now that we know `NaturalNumbers` are `Mappable`, we can call `map` on them
and trust it will return the right result. Furthermore, with our third function,
we can *compose* any number of operations defined in protocols cleanly:
``` javascript
const plus1 = x => x + 1;
const div5 = x => x / 5;
const plus_then_div = compose(map(div5), map(plus1));
console.log(plus_then_div(new NaturalNumbers));
// => [ 0.4, 0.6, 0.8, 1, 1.2, 1.4, 1.6, 1.8, 2 ]
```
More important, if we know that an object of ours is `Mappable`, we know `map`
will work on it. Protocols gives us an idea of what we can do with an object and
help us abstract common operations between data types, thus reducing the
overhead of dealing with a hundred functions.
What is easier? To have a hundred functions for every different object or ten
functions that work on a hundred objects?
================================================
FILE: _posts/en/javascript/2017-04-24-improving-your-async-functions-with-webworkers.md
================================================
---
layout: post
title: Improving your Async functions with WebWorkers
tip-number: 74
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: JS runs in a single thread in the browser, this is the truth. In this tip I'll show you how to unleash the full power of asynchronous processing with Web Workers.
categories:
- en
- javascript
---
> JS shall have but one Thread (in the browser at least)
>
> -- Thus spoke the master programmer.
JS runs in a single thread in the browser, this is the truth.
Somewhere in its own universe, there exists a Queue which holds messages
and functions associated with them.
Every time an event (i.e, a user clicks a button) is registered, there's
a runtime check to see whether there's any listener attached to that event.
If there's one, it will enqueue the message. Otherwise, it will be lost
forever.
Now, our event loop processes one message at a time, meaning that if you
do some CPU intensive operation (i.e, number crunching) this will indeed
'block' the one Thread, rendering our application useless.
This is true even for `async` functions, which will be queued as soon as
invoked and executed as soon as possible (immediately given the queue is
empty).
I/O such as requests to external resources are non-blocking though, so you
can request a file as large as you want without fear. The associated
callback, however, will show the same characteristics of an `async` function.
Strategies for processing lots of data vary a lot. You could partition data
and set timeouts for processing bits of it a time for example. But to unleash
the full power of asynchronous processing, you should use Web Workers.
To do so, you separate the processing part in a different file (possibly
'my_worker.js'), create a worker with `newWorker = new Worker('my_worker.js');`
and offload the processing to it.
``` javascript
// my_worker.js
const do_a_lot_of_processing = (data) => {
....
}
onmessage = (e) => {
postMessage(do_a_lot_of_processing(e.data));
}
// main.js
const myWorker = new Worker('my_worker.js');
async function get_useful_data() {
const raw_data = await request(some_url);
myWorker.postmessage(raw_data);
}
const show_data => (e) {
const data = e.data;
...
}
myWorker.onmessage(show_data);
get_useful_data();
```
Your mileage may vary of course, and there are many abstractions that can be
built upon this model.
================================================
FILE: _posts/en/javascript/2017-06-14-closures-inside-loops.md
================================================
---
layout: post
title: Closures inside loops
tip-number: 76
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: Closure in a loop is an interesting topic and this is the tip to be a master of it
categories:
- en
- javascript
---
If you ever come across the likes of
```javascript
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs[i] = function() {
console.log("i value is " + i);
};
}
for (var k = 0; k < 3; k++) {
funcs[k]();
}
```
You will notice that the expected output of
```
i value is 0
i value is 1
i value is 2
```
Doesn't match the actual output which will resemble
```
i value is 3
i value is 3
i value is 3
```
This is because of how the capturing mechanism of closures work and how `i` is represented internally.
To solve this situation you can do as follows:
```javascript
for (var i = 0; i < 3; i++) {
funcs[i] = (function(value) {
console.log("i value is " + i);
})(i);
}
```
Which effectively copies i by value by handing it to our closure or
```javascript
for (let i = 0; i < 3; i++) {
funcs[i] = function() {
console.log("i value is " + i);
}
}
```
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.
================================================
FILE: _posts/en/javascript/2017-06-14-immutable-structures-and-cloning.md
================================================
---
layout: post
title: Immutable structures and cloning
tip-number: 78
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: Object cloning is a tricky, full of edge-cases, endeavor. The reason is simple enough. Objects maintain internal state, and that is much abused. There are countless techniques, or better phrased, countless derivations of the same technique.
categories:
- en
- javascript
---
Object cloning is a tricky, full of edge-cases, endeavor. The reason is simple
enough. Objects maintain internal state, and that is much abused. There are
countless techniques, or better phrased, countless derivations of the same
technique.
Cloning an object is an indicator that your application is growing, and that
you've got a complex object which you'd want to treat as an immutable value, i.e
operate on it while maintaining a previous state.
If the object is in your control, you're lucky. A bit of refactoring here and
there might lead you to a point where you avoid the problem entirely by
rethinking your object's structure and behavior.
With the rediscovering of functional programming techniques, a myriad of debates
have been held about immutable structures and how they offer exactly what you
seek for. Mutable state is the root of all evil, some might argue.
We encourage to reach **ImmutableJS** by Facebook which provides a nice set of
immutable structures free for use. By rethinking your object's inner workings
and separating state from behavior, making each function consume a state to
produce a new one - much like the Haskell's **State** monad - you will
reduce many nuisances.
If the object is outside your control, you're partly out of luck. This can be
circumvented by creating convoluted computations where you solve for yourself
circular references and reach enlightenment. However, as you're using external
objects anyways, and they must come, as their name says, from external sources,
then you might be more comfortable handling the matter to yet another external
library and focus on what matters the most, i.e, your application itself.
One such library is [pvorb/clone](https://github.com/pvorb/clone), which has a
very simple API. To clone an object you only have to
``` javascript
var clone = require('clone');
var a = {foo: {bar: 'baz'}};
var b = clone(a);
a.foo.bar = 'foo';
console.log(a); // {foo: {bar: 'foo'}}
console.log(b); // {foo: {bar: 'baz'}}
```
There are, of course, many more libraries that allow you to do the same such as
[Ramda](http://ramdajs.com/docs/#clone), [lodash.clonedeep](https://www.npmjs.com/package/lodash.clonedeep)
and [lodash.clone](https://www.npmjs.com/package/lodash.clone).
As an end note, if you are serious about dealing with immutable structures, you
might want to check **ClojureScript** or (for those that feel that Haskell's
worth a shot) **PureScript**.
We neither encourage, nor condemn, the use of self made cloning mechanisms. Only
noting that considerable work has been done on the area and that you'd probably
be better of reusing than reinventing the wheel.
================================================
FILE: _posts/en/javascript/2017-06-15-looping-over-arrays.md
================================================
---
layout: post
title: Looping over arrays
tip-number: 79
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: There's a few methods for looping over arrays in Javascript. We'll start with the classical ones and move towards additions made to the standard.
categories:
- en
- javascript
---
# Looping over arrays
There're few methods for looping over arrays in Javascript. We'll start
with the classical ones and move towards additions made to the standard.
## while
```javascript
let index = 0;
const array = [1,2,3,4,5,6];
while (index < array.length) {
console.log(array[index]);
index++;
}
```
## for (classical)
```javascript
const array = [1,2,3,4,5,6];
for (let index = 0; index < array.length; index++) {
console.log(array[index]);
}
```
## forEach
```javascript
const array = [1,2,3,4,5,6];
array.forEach(function(current_value, index, array) {
console.log(`At index ${index} in array ${array} the value is ${current_value}`);
});
// => undefined
```
## map
The last construct was useful, however, it doesn't return a new array which might
be undesirable for your specific case. `map` solves this by applying a function
over every element and then returning the new array.
```javascript
const array = [1,2,3,4,5,6];
const square = x => Math.pow(x, 2);
const squares = array.map(square);
console.log(`Original array: ${array}`);
console.log(`Squared array: ${squares}`);
```
The full signature for `map` is `.map(current_value, index, array)`.
## reduce
From MDN:
> The reduce() method applies a function against an accumulator and each element
> in the array (from left to right) to reduce it to a single value.
```javascript
const array = [1,2,3,4,5,6];
const sum = (x, y) => x + y;
const array_sum = array.reduce(sum, 0);
console.log(`The sum of array: ${array} is ${array_sum}`);
```
## filter
Filters elements on an array based on a boolean function.
```javascript
const array = [1,2,3,4,5,6];
const even = x => x % 2 === 0;
const even_array = array.filter(even);
console.log(`Even numbers in array ${array}: ${even_array}`);
```
## every
Got an array and want to test if a given condition is met in every element?
```javascript
const array = [1,2,3,4,5,6];
const under_seven = x => x < 7;
if (array.every(under_seven)) {
console.log('Every element in the array is less than 7');
} else {
console.log('At least one element in the array was bigger than 7');
}
```
## some
Test if at least one element matches our boolean function.
```javascript
const array = [1,2,3,9,5,6,4];
const over_seven = x => x > 7;
if (array.some(over_seven)) {
console.log('At least one element bigger than 7 was found');
} else {
console.log('No element bigger than 7 was found');
}
```
================================================
FILE: _posts/en/javascript/2017-09-01-hash-maps-without-side-effects.md
================================================
---
layout: post
title: Hash maps without side effects
tip-number: 73
tip-username: bhaskarmelkani
tip-username-profile: https://www.twitter.com/bhaskarmelkani
tip-tldr: Create hash maps(without side effects) using `Object.create(null)`.
categories:
- en
- javascript
---
# Hash maps without side effects
When you want to use javascript object as a hash map(purely for storing data), you might want to create it as follows.
```javascript
const map = Object.create(null);
```
When creating a map using object literal(`const map = {}`), the map inherits properties from Object by default. It is equivalent to `Object.create(Object.prototype)`.
But by doing `Object.create(null)`, we explicitly specify `null` as its prototype. So it have absolutely no properties, not even constructor, toString, hasOwnProperty, etc. so you're free to use those keys in your data structure if you need to.
## Rationale:
```javascript
const dirtyMap = {};
const cleanMap = Object.create(null);
dirtyMap.constructor // function Object() { [native code] }
cleanMap.constructor // undefined
// Iterating maps
const key;
for(key in dirtyMap){
if (dirtyMap.hasOwnProperty(key)) { // Check to avoid iterating over inherited properties.
console.log(key + " -> " + dirtyMap[key]);
}
}
for(key in cleanMap){
console.log(key + " -> " + cleanMap[key]); // No need to add extra checks, as the object will always be clean
}
```
## Notes:
* Object.create() was introduced in ES5: [Compatibility](http://kangax.github.io/compat-table/es5/)
* ES6 introduced some new structures: [Map](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map), [WeakMap](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap), [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) and [Weak Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet)
================================================
FILE: _posts/en/javascript/2018-11-25-creating-immutable-objects-in-native-javascript.md
================================================
---
layout: post
title: Creating immutable objects in native JavaScript
tip-number: 74
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: With the latest versions of JavaScript it’s possible to create immutable objects. I’ll walk you through how to do it in three different ways.
categories:
- en
- javascript
---
# Creating immutable objects in native JavaScript
Javascript it’s a flexible language, you can redefine anything. But when projects get complex we find problems with mutable data structures.
With the latest versions of JavaScript this situation changed. Now it’s possible to create immutable objects. I’ll walk you through how to do it in three different ways.
### Wait, what means immutable?
> Immutability in object means we don’t want our objects to change in any ways once we create them i.e make them read-only type.
Let’s suppose we need to define a car [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) and use its properties to perform operations throughout our entire project.
We can’t allow modifying by mistake any data.
```
const myTesla = {
maxSpeed: 250,
batteryLife: 300,
weight: 123
};
```
## [Object.preventExtensions()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/preventExtensions)
This method prevents the addition of new properties to our existing object.
`preventExtensions()` is a irreversible operation. We can never add extra properties to the object again.
```
Object.isExtensible(myTesla); // true
Object.preventExtensions(myTesla);
Object.isExtensible(myTesla); // false
myTesla.color = 'blue';
console.log(myTesla.color) // undefined
```
## [Object.seal()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal)
It prevents additions or deletion of properties. `seal()` also prevents the modification of property descriptors.
```
Object.isSealed(myTesla); // false
Object.seal(myTesla);
Object.isSealed(myTesla); // true
myTesla.color = 'blue';
console.log(myTesla.color); // undefined
delete myTesla.batteryLife; // false
console.log(myTesla.batteryLife); // 300
Object.defineProperty(myTesla, 'batteryLife'); // TypeError: Cannot redefine property: batteryLife
```
## [Object.freeze()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)
It does the same that `Object.seal()` plus it makes the properties non-writable.
```
Object.isFrozen(myTesla); // false
Object.freeze(myTesla);
Object.isFrozen(myTesla); // true
myTesla.color = 'blue';
console.log(myTesla.color); // undefined
delete myTesla.batteryLife;
console.log(myTesla.batteryLife); // 300
Object.defineProperty(myTesla, 'batteryLife'); // TypeError: Cannot redefine property: batteryLife
myTesla.batteryLife = 400;
console.log(myTesla.batteryLife); // 300
```
## Extra
Use `strict mode` if you want to throw an error when trying to modify an immutable object.
================================================
FILE: _posts/en/javascript/2020-10-13-what-is-a-functional-inheritance.md
================================================
---
layout: post
title: What is Functional Inheritance?
tip-number: 75
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: Functional inheritance is the process of inheriting features by applying an augmenting function to an object instance.
categories:
- en
- javascript
---
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.
Functional mixins are composable factory functions that add properties and behaviors to objects like stations in an assembly line.
```javascript
// Base object constructor function
function Animal(data) {
var that = {}; // Create an empty object
that.name = data.name; // Add it a "name" property
return that; // Return the object
};
// Create achild object, inheriting from the base Animal
function Cat(data) {
// Create the Animal object
var that = Animal(data);
// Extend base object
that.sayHello = function() {
return 'Hello, I\'m ' + that.name;
};
return that;
};
// Usage
var myCat = Cat({ name: 'Rufi' });
console.log(myCat.sayHello());
// Output: "Hello, I'm Rufi"
```
================================================
FILE: _posts/en/javascript/2020-10-15-what-is-a-currying-function.md
================================================
---
layout: post
title: What is a currying function?
tip-number: 75
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
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.
categories:
- en
- javascript
---
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.
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.
```javascript
// Normal definition
function multiply(a, b, c) {
return a * b * c;
};
console.log(multiply(1, 2, 3));
// Output: 6
// Simple curry function definition
function multiply(a) {
return (b) => {
return (c) => {
return a * b * c;
};
};
};
console.log(multiply(1)(2)(3));
// Output: 6
```
### Further readings:
- [Currying in JavaScript](https://dev.to/suprabhasupi/currying-in-javascript-1k3l)
- [Lodash curry](https://lodash.com/docs/#curry)
- [JavaScript currying](http://zetcode.com/javascript/currying/)
================================================
FILE: _posts/en/javascript/2020-10-20-what-is-the-temporal-dead-zone.md
================================================
---
layout: post
title: What is the Temporal Dead Zone?
tip-number: 76
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: Temporal Dead Zone is a JavaScript behavior while using variables declared using `let` and `const` keywords.
categories:
- en
- javascript
---
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`.
```javascript
function myFunc(){
console.log(greeting);
var greeting = 'Hello World!'
};
myFunc(); // Output: undefined
function myFunc() {
console.log(greeting);
let greeting = 'Hello World!';
};
myFunc(); // Output: ReferenceError: greeting is not defined
function myFunc() {
console.log(greeting);
const greeting = 'Hello World!';
}
myFunc(); // Output: ReferenceError: greeting is not defined
```
================================================
FILE: _posts/en/javascript/2020-10-22-difference-between-target-and-currentTarget.md
================================================
---
layout: post
title: What is the difference between Target and currentTarget in the event context?
tip-number: 77
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: target refers to the element that triggers an event. currentTarget to the element that the event listener is listening on.
categories:
- en
- javascript
---
`target` refers to the DOM element that triggers an event. Otherwise, `currentTarget` refers to the DOM element that the event listener is listening on.
```html
Walk your dog
```
```js
const list = document.querySelector(".todo-list");
list.addEventListener("click", e => {
console.log(e.target);
// Output:
Walk your dog
console.log(e.currentTarget);
// Output:
});
```
================================================
FILE: _posts/en/javascript/2020-10-27-what-is-a-spread-operator.md
================================================
---
layout: post
title: What is a spread operator?
tip-number: 78
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: The spread operator is a useful syntax for manipulating arrays and objects.
categories:
- en
- javascript
---
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.
```js
// Concatenating arrays and objects
let arr1 = [1,2,3];
let arr2 = [4,5];
let newArray = [...arr1,...arr2];
console.log(newArray);
// Output: [ 1, 2, 3, 4, 5 ]
// Copying array elements
let arr = ["a","b","c"];
let newArray = [...arr];
console.log(newArray);
// Output: ["a", "b", "c"]
// Expanding arrays
let arr = ["a","b"];
let newArray = [...arr,"c","d"];
console.log(newArray);
// Output: ["a", "b", "c", "d"]
// Merging objects
const userBasic = {
name: "Jen",
age: 22,
};
const userMoreInfo = {
country: "Argentina",
city: "Córdoba",
};
const user = {... userBasic, ... userMoreInfo};
// Output: { name: "Jen", age: 22, country: "Argentina", city: "Córdoba" }
```
================================================
FILE: _posts/en/javascript/2020-11-04-what-is-a-void-operator.md
================================================
---
layout: post
title: What is a void operator?
tip-number: 79
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: The void operator returns an undefined value from an evaluated expression
categories:
- en
- javascript
---
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.
```js
function getYear() {
return 2020;
};
console.log(getYear());
// Output: 2020
console.log(void getYear());
// Output: undefined
// Useful use case
button.onclick = () => void getYear();
```
================================================
FILE: _posts/en/javascript/2020-11-17-what-is-the-promise-executor.md
================================================
---
layout: post
title: What is the promise executor?
tip-number: 80
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: The method received as an argument for the promise.
categories:
- en
- javascript
---
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.
```js
const executor = (resolve, reject) => {
setTimeout(() => resolve("I'm done"), 1000);
};
new Promise(executor).then(result => {
console.log(result);
// Output after 1000ms: I'm done
});
```
================================================
FILE: _posts/en/javascript/2021-02-02-what-is-the-javascript-ternary-operator.md
================================================
---
layout: post
title: What is the JavaScript ternary operator?
tip-number: 81
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: The ternary operator is a shortcut for the if statement.
categories:
- en
- javascript
---
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.
```js
let age = 26;
// condition ? expression if true : expression if false
let drink = (age >= 21) ? "Beer" : "Juice";
console.log(drink); // "Beer"
// Equivalent to:
let drink;
if ((age >= 21)) {
drink = "Beer";
} else {
drink = "Juice";
}
console.log(drink); // "Beer"
```
================================================
FILE: _posts/en/more/2017-04-06-vuejs-how-vuejs-makes-a-copy-update-replace-inside-the-data-binding.md
================================================
---
layout: post
title: VueJS, How VueJS makes a copy-update-replace inside the data binding.
tip-number: 71
tip-username: pansila
tip-username-profile: https://github.com/pansil
tip-tldr: In this tip, I will introduce an example to show you how it might conflict with other software.
categories:
- en
- more
---
### Overview
Vuejs is a wonderful piece of software that keeps simple yet powerful compared to other prevalent frameworks, like Angularjs and Reactjs.
You can quickly master it before you give up by being in awe of the framework complexity unlike them above.
But it bites you sometimes if you don't know how it works. Here is an example of the conflict with another simple and popular UI framework, Framework7.
```html
```
```js
var myApp = new Framework7();
myApp.onPageInit('test', function (page) {
new Vue({
el: '#test',
data: {
content: 'hello world'
}
});
});
```
You may be surprised that it doesn't work, nothing changed after new page loaded. In fact, Vue internally makes a copy of the target html template element and replaces the original one with the new copied one after the date binding to it. While during the page loading, Framework7 invokes the `PageInit` callback and then Vue kicks in and makes the update on the `` element. Now the DOM tree has the new copied `` element while Framework7 stays unconcerned and continues to perform the remaining initialization job on the old `` element, like show it eventually, that's the root cause.
To work around it, don't let Vue selector targets on the `` element, on its child instead. Then the copy-update-replace won't blow away the whole page anymore.
```js
var myApp = new Framework7();
myApp.onPageInit('test', function (page) {
new Vue({
el: '#test1',
data: {
content: 'hello world'
}
});
});
```
### More info
- [Vue](https://github.com/Vuejs/Vue)
- [Framework7](https://framework7.io/)
================================================
FILE: _posts/en/react/2016-01-02-keys-in-children-components-are-important.md
================================================
---
layout: post
title: Keys in children components are important
tip-number: 02
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: The key is an attribute that you must pass to all components created dynamically from an array. It's a unique and constant id that React uses to identify each component in the DOM and to know whether it's a different component or the same one. Using keys ensures that the child component is preserved and not recreated and prevents weird things from happening.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /en/keys-in-children-components-are-important/
categories:
- en
- react
---
The [key](https://facebook.github.io/react/docs/multiple-components.html#dynamic-children) is an attribute that you must pass to all components created dynamically from an array. It's a unique and constant id that React uses to identify each component in the DOM and to know whether it's a different component or the same one. Using keys ensures that the child component is preserved and not recreated and prevents weird things from happening.
> Key is not really about performance, it's more about identity (which in turn leads to better performance). Randomly assigned and changing values do not form an identity [Paul O’Shannessy](https://github.com/facebook/react/issues/1342#issuecomment-39230939)
- Use an existing unique value of the object.
- Define the keys in the parent components, not in child components
```javascript
//bad
...
render() {
{% raw %}{{item.name}}{% endraw %}
}
...
//good
```
- [Using array index is a bad practice.](https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318#.76co046o9)
- `random()` will not work
```javascript
//bad
```
- You can create your own unique id. Be sure that the method is fast and attach it to your object.
- When the number of children is large or contains expensive components, use keys to improve performance.
- [You must provide the key attribute for all children of ReactCSSTransitionGroup.](http://docs.reactjs-china.com/react/docs/animation.html)
================================================
FILE: _posts/en/react/2017-03-27-state-to-props-maps-with-memory.md
================================================
---
layout: post
title: State to Props maps with memory
tip-number: 66
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: You've been building your React apps with a Redux store for quite a while, yet you feel awkward when your components update so often. You've crafted your state thoroughly, and your architecture is such that each component gets just what it needs from it, no more no less. Yet, they update behind your back. Always mapping, always calculating.
tip-writer-support: https://www.coinbase.com/loverajoel
categories:
- en
- react
---
You've been building your React apps with a Redux store for quite a while,
yet you feel awkward when your components update so often. You've crafted
your state thoroughly, and your architecture is such that each component
gets just what it needs from it, no more no less. Yet, they update behind
your back. Always mapping, always calculating.
## Reselector to the rescue
How could would it be if you could just calculate what you need? If this
part of the state tree changes, then yes, please, update this.
Let's take a look at the code for a simple TODOs list with a visibility filter,
specially the part in charge of getting the visible TODOs in our container
component:
```javascript
const getVisibleTodos = (todos, filter) => {
switch (filter) {
case 'SHOW_ALL':
return todos
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed)
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed)
}
}
const mapStateToProps = (state) => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
}
}
```
Each time our component is updated, this needs be recalculated again. Reselector
actually allows us to give our `getVisibleTodos` function memory. So it knows
whether the parts of the state we need have changed. If they have, it will
proceed, if they haven't, it will just return the last result.
Let's bring selectors!
```javascript
const getVisibilityFilter = (state) => state.visibilityFilter
const getTodos = (state) => state.todos
```
Now that we can *select* which parts of the state we want to keep track of,
we're ready to give memory to getVisibleTodos
```javascript
import {createSelector} from 'reselect'
const getVisibleTodos = createSelector(
[getVisibilityFilter, getTodos],
(visibilityFilter, todos) => {
switch (visibilityFilter) {
case 'SHOW_ALL':
return todos
case 'SHOW_COMPLETED':
return todos.filtler(t => t.completed)
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed)
}
}
)
```
And change our map to give the full state to it:
```javascript
const mapStateToProps = (state) => {
return {
todos: getVisibleTodos(state)
}
}
```
And that's it! We've given memory to our function. No extra calculations if
the involved parts of the state haven't changed!
================================================
FILE: _posts/en/react/2017-04-04-enhancing-react-components-composition.md
================================================
---
layout: post
title: Enhancing React components, Composition
tip-number: 69
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: React is extremely flexible in terms of how you can structure your components, but this pattern will make your apps more efficient.
tip-writer-support: https://www.coinbase.com/loverajoel
categories:
- en
- react
---
> At Facebook, we use React in thousands of components, and we haven't found any
> use cases where we would recommend creating component inheritance hierarchies.
*Long live to composition, inheritance is dead.*
So, how do you *extend* a component in React?
Well, it's pretty obvious that the guys @Facebook consider inappropriate to
inherit from parent components. Let's look at alternatives:
## Planning ahead of time
There might be some cases where you have a component which can't know what its
children will be ahead of time (like most of us). For them, React gifts
`props.children`:
``` javascript
function List(props) {
return (
{props.children}
);
}
function DownloadMenu() {
return (
Download SBCL
Download Racket
Download Haskell
);
}
```
As we can see, `props.children` receives everything that's in between the
component's open and closing tag.
Furthermore, we can exploit `props` to fill voids:
``` javascript
function ListWithHeader(props) {
return (
{props.header}
{props.children}
);
}
function DownloadMenuWithHeader() {
return (
}>
Download SBCL
...
);
}
```
## Generic components and specialization
So, we've got this great *FolderView* component
``` javascript
function FolderView(props) {
return (
{props.folderName}
{props.availableActions}
{props.files}
);
}
```
This could represent any folder in our filesystem, however, we only want to
*specialize* it so it shows only the Pictures and Desktop folders.
``` javascript
function DesktopFolder(props) {
return (
Create Folder
Create Document
}
files={props.files}
/>
);
}
function PicturesFolder(props) {
return (
New Picture
}
files={props.files}
/>
);
}
```
And just like so, we've *specialized* our component, without creating any
inheritance hierarchy!
================================================
FILE: _posts/en/react/2017-04-10-adventurers-guide-to-react.md
================================================
---
layout: post
title: Adventurers Guide to React (Part I)
tip-number: 72
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: So you've heard of this *React* thing, and you actually peeked at the docs, maybe even went through some of the pages. Then you suddenly came across mysterious runes that spelled somewhat along the lines of Webpack, Browserify, Yarn, Babel, NPM and yet much more.
categories:
- en
- react
---
> I used to be an adventurer like you, but then I took a RTFM in the knee...
>
> Guard outside of Castle Reducer in the Land of React
So you've heard of this *React* thing, and you actually peeked at the docs,
maybe even went through some of the pages. Then you suddenly came across
mysterious runes that spelled somewhat along the lines of Webpack, Browserify,
Yarn, Babel, NPM and yet much more.
Thus, you went to their official sites and went through the docs, just to find
yourself lost in the ever growing collection of modern tools (tm) to build
web applications with JS.
Afraid you must be not.
## Yarn, NPM
They are just dependency managers, nothing to be afraid of. In fact, they are
the less scary part. If you've ever used a GNU/Linux distro, FreeBSD, Homebrew
on MacOSX, Ruby and Bundler, Lisp and Quicklisp just to name a few, you'll be
familiar with the concept.
Should you not be, it's a very simple thing, so don't worry. The Land of React
is but a province in a much bigger world, which some call Javascript and others
Ecmascript (JS/ES for short).
Now suppose you are starting your own town, but you really want to use React's
tools for your buildings, because, let's face it, it is popular. The traditional
way would be to walk to the Land of React and ask the ruler to handle you some
of his tools. The problem is you waste time, and you must keep contact with him
so if any tools is faulty, you get a new one.
However, with the advent of drones and near-instant travel for them, some smart
guys started a registry of the different towns, cities and provinces. Furthermore,
they built especial drones that could deliver the tools right to you.
Nowadays, to require React in your project, you just have to go
```bash
$ npm init . # create town
$ npm install --save react # get react and put the materials in the store
```
Handy, isn't it? and free.
## Webpack, Browserify and friends
In the old times, you had to build your town all by yourself. If you wanted a
statue of John McCarthy you would have to fetch marble and some parentheses
on your own. This improved with the advent of *dependency managers*, which could
fetch the marble and the parentheses for you. Yet, you had to assemble them on
your own.
Then came some folks from Copy & Paste (inc) and developed some tools that allowed
you to copy and paste your materials on some specific order, so you could have
your parentheses over the statue or under it.
That was actually pretty cool, you just placed all the material and specified
how they were going to be built, and all was peaceful for a while.
But this approach had a problem, which I'm sure other folks tried to circumvent.
Namely, that if you wanted to replace the parentheses by cars you would have
to rebuild your entire town. This was no problem for small towns, but large cities
suffered by this approach.
Then inspiration was given by the mighty Lord and building and module bundlers
were born.
This module bundlers allowed you to draw blueprints, and specify exactly how
the town was to be constructed. Furthermore, they grew quickly and supported
only rebuilding parts of the town, leaving the rest be.
## Babel
Babel is a time traveler who can bring materials from the future for you. like
ES6/7/8 features.
## How they all mix together
Generally, you'll create a folder for your project, fetch dependencies, configure
your module bundler so it knows where to search for your code and where to output
the distributable. Furthermore, you may want to wire that to a development server
so you can get instant feedback on what you're building.
However, the documentation of module bundlers is a bit overwhelming. There are so
many choices and options for the novice adventurer that he might lose his
motivation.
## create-react-app and friends
Thus yet another tool was created.
```bash
$ npm install -g create-react-app # globally install create-react-app
$ create-react-app my-shiny-new-app
```
And that's all. It comes pre-configured so you don't have to go through all
of Webpack/Browserify docs just to test React. It also brings testing scripts,
a development web server and much more.
However, this is not yet the final word to our history. There exists a myriad
of different builders and tools for React, which can be seen here
https://github.com/facebook/react/wiki/Complementary-Tools
================================================
FILE: _posts/en/react/2017-05-29-upping-performance-by-appending-keying.md
================================================
---
layout: post
title: Upping Performance by Appending/Keying
tip-number: 75
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: React uses a mechanism called **reconciliation** for efficient rendering on update.
categories:
- en
- react
---
React uses a mechanism called **reconciliation** for efficient rendering on
update.
**Reconciliation** works by recursively comparing the tree of DOM elements,
the specifics of the algorithm might be found on the official documents or
the source, which is always the best source.
This mechanism is partly hidden, and as such, there are some conventions
that might be followed to ease its inner workings.
One such example is **appending** vs **inserting**.
**Reconciliation** compares the list of root's nodes children at the same
time, if two children differ, then React will mutate every one.
So, for example, if you've got the following:
``` html
Sherlock Holmes
John Hamish Watson
```
And you insert an element at the beginning
``` html
Mycroft Holmes
Sherlock Holmes
John Hamish Watson
```
React will start of by comparing the old tree, where `
Second
` is the
first child and the new tree where `
First
` is the new first child.
Because they are different, it will mutate the children.
If, instead of inserting good Mycroft you appended him, React would perform
better, not touching Sherlock nor John.
But you can't always append, sometimes you've just got to insert.
This is were **keys** come in. If you supply a **key** *attribute* then React
will figure out an efficient transformation from the old tree to the new one.
``` html
Mycroft Holmes
Sherlock Holmes
John Hamish Watson
```
================================================
FILE: _posts/en/react/2021-07-18-trace-the-reason-make-your-page-rerender.md
================================================
---
layout: post
title: Check the reason make your page re-render by changed props and state
tip-number: 74
tip-username: tranvanhuyhoang
tip-username-profile: https://github.com/tranvanhuyhoang
tip-tldr: The approach of the post is we will console.log at componentDidUpdate. Find out the reason make our component re-render (specifically is look for those states and props changed).
categories:
- en
- react
---
> Avoid your page re-render unnecessary is a thing very important in optimizing your app performance.
>
> I often trace it through the way watching console.log and determine which state and props changed unnecessarily. After that, I handle that problem.
The approach of the post is we will console.log at `componentDidUpdate`. Find out the reason make our component re-render (specifically is look for those **states** and **props** changed). This post will example of both styles are **Class** and **Hook**.
## With Class
We apply this block code to `componentDidUpdate`:
``` javascript
componentDidUpdate(prevProps, prevState) {
Object.entries(this.props).forEach(([key, val]) =>
prevProps[key] !== val && console.log(`Prop '${key}' changed `)
);
if (this.state) {
Object.entries(this.state).forEach(([key, val]) =>
prevState[key] !== val && console.log(`State '${key}' changed `)
);
}
}
```
## With Hook
We apply function `useTraceUpdate` to our main function need to trace:
``` javascript
function useTraceUpdate(props) {
const prev = useRef(props);
useEffect(() => {
const changedProps = Object.entries(props).reduce((ps, [k, v]) => {
if (prev.current[k] !== v) {
ps[k] = [prev.current[k], v];
}
return ps;
}, {});
if (Object.keys(changedProps).length > 0) {
console.log('Changed props:', changedProps);
}
prev.current = props;
});
}
// Usage
function MyComponent(props) {
useTraceUpdate(props);
return
{props.children}
;
}
```
## Conclusion
That is a way that can help us trace the reason why our component re-render unnecessarily. After look for the reason, we can solve it and improve the performance of the application.
================================================
FILE: _posts/es_ES/angular/2016-01-01-angularjs-digest-vs-apply.md
================================================
---
layout: post
title: AngularJs - `$digest` vs `$apply`
tip-number: 01
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: Los pasos para crear modulos en Javascript son cada vez más numerosos y complicados, pero ¿qué hay de los boilerplate en los nuevos frameworks?
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /es_es/angularjs-digest-vs-apply/
categories:
- es_ES
- angular
---
Una de las características más apreciadas de AngularJS es el de dos vías de enlace de datos. Con el fin de hacer de este trabajo AngularJS evalúa los cambios entre el modelo y la vista a través de ciclos (`$digest`). Es necesario comprender este concepto con el fin de entender cómo funciona el framework bajo el capó.
Angular evalúa cada observador cuando se dispara un evento. Este es el conocido ciclo de `$digest`.
A veces hay que obligarlo a realizar un nuevo ciclo de forma manual y debe elegir la opción correcta porque esta fase es uno de los más influyentes en términos de rendimiento.
### `$apply`
Este método del core le permite iniciar el ciclo de digestión de forma explícita. Eso significa que todos los observadores son comprobados; toda la aplicación se inicia el `$digest loop`. Internamente, después de ejecutar un parámetro de la función opcional, se llama `$rootScope.$digest();`.
### `$digest`
En este caso, el método `$digest` inicia el ciclo `$digest` para el scope actual y sus descendientes. Usted debe notar que los padres scopes, no serán revisadas, y no se verá afectada.
### Recomendaciones
- Use `$apply` o `$digest` sólo cuando eventos del DOM han disparado fuera del AngularJS.
- Pasar una expresión de función a `$apply`, esto tiene un mecanismo de control de errores y permite la integración de los cambios en el ciclo de digestión.
```javascript
$scope.$apply(() => {
$scope.tip = 'Javascript Tip';
});
```
- Si sólo necesita actualizar el scope actual o sus hijos, usar `$digest`, y evitar un nuevo ciclo de digest para toda la aplicación. La ventaja de rendimiento es evidente por sí mismo.
- `$apply()` es un proceso difícil para la máquina y puede conducir a problemas de rendimiento cuando hay una gran cantidad de unión.
- Si está utilizando >AngularJS 1.2.X, usar `$evalAsync`, que es un método básico que evaluará la expresión durante el ciclo actual o el siguiente. Esto puede mejorar el rendimiento de su aplicación.
================================================
FILE: _posts/es_ES/javascript/2015-12-29-insert-item-inside-an-array.md
================================================
---
layout: post
title: Insertar elemento dentro de un Array
tip-number: 00
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: La inserción de un elemento en un array existente, es una tarea común diaria. Se pueden añadir elementos al final de un array mediante push, al principio usando unshift, al medio que usa splice.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /es_es/insert-item-inside-an-array/
categories:
- es_ES
- javascript
---
La inserción de un elemento en un array existente, es una tarea común diaria. Se pueden añadir elementos al final de un array mediante push, al principio usando unshift, al medio que usa splice.
Esos son los métodos conocidos, pero no quiere decir que no hay una manera más performante. Aquí vamos:
Agragar un elemento al final de un array es fácil con push(), pero hay una manera más performante.
```javascript
var arr = [1,2,3,4,5];
arr.push(6);
arr[arr.length] = 6; // 43% faster in Chrome 47.0.2526.106 on Mac OS X 10.11.1
```
Ambos métodos modifican el array original. No lo cree? [jsperf](http://jsperf.com/push-item-inside-an-array)
Ahora bien, si estamos tratando de añadir un elemento al principio de un array:
```javascript
var arr = [1,2,3,4,5];
arr.unshift(0);
[0].concat(arr); // 98% faster in Chrome 47.0.2526.106 on Mac OS X 10.11.1
```
Aquí un poco más de detalle: unshift editó el array original; concat devuelve un nuevo array.[jsperf](http://jsperf.com/unshift-item-inside-an-array)
Para añadir elementos en el medio de un array es fácil con splice, y que es la forma mas potente para hacerlo.
```javascript
var items = ['one', 'two', 'three', 'four'];
items.splice(items.length / 2, 0, 'hello');
```
Traté de correr estas pruebas en distintos navegadores y sistemas operativos y los resultados fueron similares. Espero que estos consejos les sea de utilidad para usted y animar a llevar a cabo sus propias pruebas!
================================================
FILE: _posts/es_ES/javascript/2016-01-03-improve-nested-conditionals.md
================================================
---
layout: post
title: Mejorar anidaciones Condicionales
tip-number: 03
tip-username: AlbertoFuente
tip-username-profile: https://github.com/AlbertoFuente
tip-tldr: ¿Cómo podemos mejorar y hacer una declaración anidada `if` más eficiente en javascript?
redirect_from:
- /es_es/improve-nested-conditionals/
categories:
- es_ES
- javascript
---
¿Cómo podemos mejorar y hacer una declaración anidada `if` más eficiente en javascript?
```javascript
if (color) {
if (color === 'black') {
printBlackBackground();
} else if (color === 'red') {
printRedBackground();
} else if (color === 'blue') {
printBlueBackground();
} else if (color === 'green') {
printGreenBackground();
} else {
printYellowBackground();
}
}
```
Una forma de mejorar el `if` anidado sería usar `switch`. Aunque es menos verbosa y está más ordenado, no se recomienda su uso porque es muy difícil de depurar errores. Aquí [por eso] (https://toddmotto.com/deprecating-the-switch-statement-for-object-literals/).
```javascript
switch(color) {
case 'black':
printBlackBackground();
break;
case 'red':
printRedBackground();
break;
case 'blue':
printBlueBackground();
break;
case 'green':
printGreenBackground();
break;
default:
printYellowBackground();
}
```
Pero lo que si tenemos un condicional con varios controles en cada declaración? en este caso, si queremos que sean menos detalladas y más ordenada, podemos utilizar el condicional `switch`.
Si pasamos `true` como parámetro a la declaración `switch`, que nos permite colocar un condicional en cada caso.
```javascript
switch(true) {
case (typeof color === 'string' && color === 'black'):
printBlackBackground();
break;
case (typeof color === 'string' && color === 'red'):
printRedBackground();
break;
case (typeof color === 'string' && color === 'blue'):
printBlueBackground();
break;
case (typeof color === 'string' && color === 'green'):
printGreenBackground();
break;
case (typeof color === 'string' && color === 'yellow'):
printYellowBackground();
break;
}
```
Pero siempre hay que evitar tener varios controles en todas las condiciones y evitar el uso de `switch` tanto como sea posible. También hay que tener en cuenta que la forma más eficiente de hacer esto es a través de un `object`.
```javascript
var colorObj = {
'black': printBlackBackground,
'red': printRedBackground,
'blue': printBlueBackground,
'green': printGreenBackground,
'yellow': printYellowBackground
};
if (color in colorObj) {
colorObj[color]();
}
```
Aqui puede obtener mas informacion [this](http://www.nicoespeon.com/en/2015/01/oop-revisited-switch-in-js/).
================================================
FILE: _posts/es_ES/javascript/2016-01-04-sorting-strings-with-accented-characters.md
================================================
---
layout: post
title: Ordenando cadenas con caracteres acentuados
tip-number: 04
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: Javascript tiene un método nativo **sort** que permite ordenar matrices. Haciendo un simple `array.sort()` va a tratar a cada entrada del array como una cadena y va a tratar de ordenarla alfabéticamente. Pero cuando intenta ordenar un array de caracteres no ASCII obtendrá un resultado extraño.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /es_es/sorting-strings-with-accented-characters/
categories:
- es_ES
- javascript
---
Javascript tiene un método nativo **[sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)** que permite ordenar arrays. Haciendo una simple `array.sort()` va a tratar a cada entrada de la matriz como una cadena y va a tratar de ordenarla alfabéticamente. También puede proporcionar la funcion [own custom sorting](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Parameters).
```javascript
['Shanghai', 'New York', 'Mumbai', 'Buenos Aires'].sort();
// ["Buenos Aires", "Mumbai", "New York", "Shanghai"]
```
Pero cuando intenta para un array de caracteres no ASCII como esto `['E', 'a', 'U', 'c']`, se obtendrá un resultado extraño `[' c ',' e ',' A ',' U ']'. Eso sucede porque sort sólo funciona con el idioma Inglés.
Mire el siguiente ejemplo:
```javascript
// Spanish
['único','árbol', 'cosas', 'fútbol'].sort();
// ["cosas", "fútbol", "árbol", "único"] // bad order
// German
['Woche', 'wöchentlich', 'wäre', 'Wann'].sort();
// ["Wann", "Woche", "wäre", "wöchentlich"] // bad order
```
Afortunadamente, hay dos maneras de superar este comportamiento [localeCompare](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare) and [Intl.Collator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Collator).
> Ambos métodos tienen sus propios parámetros personalizados con el fin de configurarlo para que funcione adecuadamente.
### Usando `localeCompare()`
```javascript
['único','árbol', 'cosas', 'fútbol'].sort(function (a, b) {
return a.localeCompare(b);
});
// ["árbol", "cosas", "fútbol", "único"]
['Woche', 'wöchentlich', 'wäre', 'Wann'].sort(function (a, b) {
return a.localeCompare(b);
});
// ["Wann", "wäre", "Woche", "wöchentlich"]
```
### Usando `Intl.Collator()`
```javascript
['único','árbol', 'cosas', 'fútbol'].sort(Intl.Collator().compare);
// ["árbol", "cosas", "fútbol", "único"]
['Woche', 'wöchentlich', 'wäre', 'Wann'].sort(Intl.Collator().compare);
// ["Wann", "wäre", "Woche", "wöchentlich"]
```
- Para cada método se puede personalizar la ubicación.
- De acuerdo a [Firefox](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare#Performance) Intl.Collator es más rápida cuando se compara un gran número de cadenas.
Así que cuando se trabaja con arrays de cadenas en un idioma distinto del Inglés, recuerde utilizar este método para evitar la clasificación inesperado.
================================================
FILE: _posts/es_ES/javascript/2016-01-05-differences-between-undefined-and-null.md
================================================
---
layout: post
title: Diferencias entre `undefined` y `null`
tip-number: 05
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: Comprendiendo las diferencias entre `undefined` y `null`.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /es_es/differences-between-undefined-and-null/
categories:
- es_ES
- javascript
---
- `undefined` significa una variable no se ha declarado, o se ha declarado pero aún no se le ha asignado un valor
- `null` es un valor de asignación que significa "no value"
- Javascript establece variables no asignadas con un valor por defecto de `undefined`
- Javascript nunca se setea un valor de `null`. Es utilizado por los programadores para indicar que un `var` no tiene ningún valor.
- `undefined` no es válido en JSON, mientras que `null` si lo es
- `undefined` typeof es `undefined`
- `null` typeof es un `object`. [porque?](http://www.2ality.com/2013/10/typeof-null.html)
- Ambos son primitivos
- Ambos son [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy)
(`Boolean(undefined) // false`, `Boolean(null) // false`)
- Se puede saber si una variable es [undefined](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined)
```javascript
typeof variable === "undefined"
```
- Puede comprobar si una variable es [null](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null)
```javascript
variable === null
```
- The **equality** operator considers them equal, but the **identity** doesn't
El operador **igualdad** considera iguales, pero la **identidad** no lo hace
```javascript
null == undefined // true
null === undefined // false
```
================================================
FILE: _posts/es_ES/javascript/2016-01-06-writing-a-single-method-for-arrays-and-a-single-element.md
================================================
---
layout: post
title: Escribir un método único para los arrays y elemento unico
tip-number: 06
tip-username: mattfxyz
tip-username-profile: https://twitter.com/mattfxyz
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).
redirect_from:
- /es_es/writing-a-single-method-for-arrays-and-a-single-element/
categories:
- es_ES
- javascript
---
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).
Sólo tienes que concatenar todo en un array. `Array.concat` aceptará un array o un elemento único.
```javascript
function printUpperCase(words) {
var elements = [].concat(words);
for (var i = 0; i < elements.length; i++) {
console.log(elements[i].toUpperCase());
}
}
```
`printUpperCase` ya está listo para aceptar un único nodo o un conjunto de nodos como su parámetro.
```javascript
printUpperCase("cactus");
// => CACTUS
printUpperCase(["cactus", "bear", "potato"]);
// => CACTUS
// BEAR
// POTATO
```
================================================
FILE: _posts/es_ES/javascript/2016-01-07-use-strict-and-get-lazy.md
================================================
---
layout: post
title: Utilice strict y obtenga lazy
tip-number: 07
tip-username: nainslie
tip-username-profile: https://twitter.com/nat5an
tip-tldr: Modo estricto en JavaScript hace que sea más fácil para los desarrolladores para escribir "seguro".
redirect_from:
- /es_es/use-strict-and-get-lazy/
categories:
- es_ES
- javascript
---
Modo estricto en JavaScript hace que sea más fácil para los desarrolladores para escribir "seguro".
De forma predeterminada, JavaScript permite al programador ser bastante descuidado, por ejemplo, al no requerir que declaremos nuestras variables con "var". Si bien esto puede parecer como una conveniencia para el desarrollador experimentado, que es también la fuente de muchos errores cuando un nombre de variable está mal escrito o accidentalmente se refirió a salir de su scope de aplicación.
Los programadores como para hacer que el ordenador haga las cosas aburridas para nosotros, y automáticamente comprobar nuestro trabajo por los errores. Eso es lo que el código JavaScript "use strict" directiva nos permite hacer, haciendo nuestros errores en errores de JavaScript.
Añadimos esta directiva ya sea que en la parte superior de un archivo JS:
```javascript
// Whole-script strict mode syntax
"use strict";
var v = "Hi! I'm a strict mode script!";
```
o dentro de la funcion:
```javascript
function f()
{
// Function-level strict mode syntax
'use strict';
function nested() { return "And so am I!"; }
return "Hi! I'm a strict mode function! " + nested();
}
function f2() { return "I'm not strict."; }
```
Con la inclusión de esta directiva en un archivo o una función de JavaScript, vamos a dirigir el motor de JavaScript que se ejecutará en modo estricto que desactiva un grupo de comportamientos que son por lo general no deseable en proyectos de JavaScript más grandes. Entre otras cosas, el modo estricto cambia los siguientes comportamientos:
* Las variables sólo pueden ser introducidos cuando van precedidas con "var"
* El intento de escribir las propiedades de sólo lectura genera un error de ruido
* Tienes que llamar a los constructores con la palabra clave "new"
* "this" no está vinculado de manera implícita al objeto global
* Un uso permitido muy limitado de eval()
* Protege el uso de palabras reservadas o futuros palabras reservadas como nombres de variables
El modo estricto es ideal para nuevos proyectos, pero puede ser difícil de introducir en los proyectos más antiguos que aún no lo utilizan en la mayoría de lugares. También puede ser problemático si su cadena de acumulación concatena todos sus archivos js en un archivo grande, ya que esto puede causar todos los archivos que se ejecutan en modo estricto.
No es una declaración, sino una expresión literal, ignorada por las versiones anteriores de JavaScript.
El modo estricto se apoya en:
* Internet Explorer desde version 10.
* Firefox desde version 4.
* Chrome desde version 13.
* Safari desde version 5.1.
* Opera desde version 12.
[Ver MDN para una descripción más completa de modo estricto](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode).
================================================
FILE: _posts/es_ES/javascript/2016-01-08-converting-a-node-list-to-an-array.md
================================================
---
layout: post
title: Convitiendo una Node List a un Array.
tip-number: 08
tip-username: Tevko
tip-username-profile: https://twitter.com/tevko
tip-tldr: Aquí está una manera rápida, segura y reutilizable para convertir una lista de nodos en un Array de elementos del DOM.
redirect_from:
- /es_es/converting-a-node-list-to-an-array/
categories:
- es_ES
- javascript
---
El método `querySelectorAll` devuelve un array similar a un objeto, llamado una lista de nodos. Estas estructuras de datos se denominan como "Array-like", porque aparecen como un array, pero no se pueden utilizar con los métodos de matriz como `map` y `forEach`. Aquí está una manera rápida, segura y reutilizable para convertir una lista de nodos en un Array de elementos del DOM:
```javascript
const nodelist = document.querySelectorAll('div');
const nodelistToArray = Array.apply(null, nodelist);
//later on ..
nodelistToArray.forEach(...);
nodelistToArray.map(...);
nodelistToArray.slice(...);
//etc...
```
El método `apply` se utiliza para pasar una serie de argumentos a una función con un determinado valor de `this`.[MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) afirma que `apply` tendrá un objeto de tipo vector, que es exactamente lo que `querySelectorAll` retorna. Dado que no es necesario especificar un valor para `this` en el contexto de la función, se pasa en `null` o `0`. El resultado es una matriz real de los elementos DOM que contiene todos los métodos de arreglos disponibles.
O si esta utilizando ES2015 puede usar esto [spread operator `...`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator)
```js
const nodelist = [...document.querySelectorAll('div')]; // returns a real array
//later on ..
nodelist.forEach(...);
nodelist.map(...);
nodelist.slice(...);
//etc...
```
================================================
FILE: _posts/es_ES/javascript/2016-01-09-template-strings.md
================================================
---
layout: post
title: Template Strings
tip-number: 09
tip-username: JakeRawr
tip-username-profile: https://github.com/JakeRawr
tip-tldr: A partir de ES6, JS ahora tiene template strings.
redirect_from:
- /es_es/template-strings/
categories:
- es_ES
- javascript
---
A partir de ES6, JS ahora tiene template strings
Ejemplo:
String normal
```javascript
var firstName = 'Jake';
var lastName = 'Rawr';
console.log('My name is ' + firstName + ' ' + lastName);
// My name is Jake Rawr
```
Template String
```javascript
var firstName = 'Jake';
var lastName = 'Rawr';
console.log(`My name is ${firstName} ${lastName}`);
// My name is Jake Rawr
```
Usted puede hacer strings multilínea sin `\n' y lógica simple (ie 2+3) en el interior `$ {}` en template strings.
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.
Tambien puede leer mas sobre Template Strings [read](https://hacks.mozilla.org/2015/05/es6-in-depth-template-strings-2).
================================================
FILE: _posts/es_ES/javascript/2016-01-10-check-if-a-property-is-in-a-object.md
================================================
---
layout: post
title: Averiguar si una propiedad está en un Objeto
tip-number: 10
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: Estas son formas de comprobar si una propiedad está presente en un objeto.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /es_es/check-if-a-property-is-in-a-object/
categories:
- es_ES
- javascript
---
Cuando usted tiene que comprobar si una propiedad está presente en un [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects), es probable que esté haciendo algo como esto:
```javascript
var myObject = {
name: '@tips_js'
};
if (myObject.name) { ... }
```
Eso está bien, pero hay que saber que existen dos formas nativas para este tipo de cosas, el [`in` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in) y [`Object.hasOwnProperty`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty). Cada objeto descendiente de `Object`.
### Observe esta gran diferencia
```javascript
var myObject = {
name: '@tips_js'
};
myObject.hasOwnProperty('name'); // true
'name' in myObject; // true
myObject.hasOwnProperty('valueOf'); // false, valueOf is inherited from the prototype chain
'valueOf' in myObject; // true
```
Ambos difieren en la profundidad a la que se comprueban las propiedades. En otras palabras, `hasOwnProperty` sólo devolverá verdadero si la clave está disponible en ese objeto directamente. Sin embargo, el operador `in` no discrimina entre las propiedades creadas en un objeto y las propiedades heredadas de la cadena de prototipo.
Aqui otro ejemplo:
```javascript
var myFunc = function() {
this.name = '@tips_js';
};
myFunc.prototype.age = '10 days';
var user = new myFunc();
user.hasOwnProperty('name'); // true
user.hasOwnProperty('age'); // false, because age is from the prototype chain
```
Mire este link [live examples here](https://jsbin.com/tecoqa/edit?js,console)!
Recomiendo que lean [this discussion](https://github.com/loverajoel/jstips/issues/62) acerca de los errores comunes el momento del control de la existencia de una propiedad en objetos.
================================================
FILE: _posts/es_ES/javascript/2016-01-11-hoisting.md
================================================
---
layout: post
title: Hoisting
tip-number: 11
tip-username: squizzleflip
tip-username-profile: https://twitter.com/squizzleflip
tip-tldr: Los pasos para crear módulos en JavaScript y constructores son cada vez más numerosos y complicados, pero ¿qué pasa con los boilerplate en nuevos frameworks?
redirect_from:
- /es_es/hoisting/
categories:
- es_ES
- javascript
---
Comprendiendo [hoisting](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting) le ayudará a organizar su scope en una funcion. Sólo recuerde, las declaraciones de variables y definiciones de funciones se izan a la cima. Las definiciones de variables no lo son, incluso si se declara y define una variable en la misma línea. Además, una **declaración** de variable permite que el sistema sepa que existe la variable, mientras que **definición** asigne un valor.
```javascript
function doTheThing() {
// ReferenceError: notDeclared is not defined
console.log(notDeclared);
// Outputs: undefined
console.log(definedLater);
var definedLater;
definedLater = 'I am defined!'
// Outputs: 'I am defined!'
console.log(definedLater)
// Outputs: undefined
console.log(definedSimulateneously);
var definedSimulateneously = 'I am defined!'
// Outputs: 'I am defined!'
console.log(definedSimulateneously)
// Outputs: 'I did it!'
doSomethingElse();
function doSomethingElse(){
console.log('I did it!');
}
// TypeError: undefined is not a function
functionVar();
var functionVar = function(){
console.log('I did it!');
}
}
```
Para hacer las cosas más fáciles de leer, declarar todas las variables en la parte superior de su función para que quede claro, que variables que estan en el scope están viniendo. Definir las variables antes que necesite utilizarlas. Definir sus funciones en la parte inferior de su scope para mantenerlos fuera de su camino.
================================================
FILE: _posts/es_ES/javascript/2016-01-12-pseudomandatory-parameters-in-es6-functions.md
================================================
---
layout: post
title: Pseudo parámetros obligatorios en funciones ES6
tip-number: 12
tip-username: Avraam Mavridis
tip-username-profile: https://github.com/AvraamMavridis
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.
redirect_from:
- /es_es/pseudomandatory-parameters-in-es6-functions/
categories:
- es_ES
- javascript
---
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).
```javascript
const _err = function( message ){
throw new Error( message );
}
const getSum = (a = _err('a is not defined'), b = _err('b is not defined')) => a + b
getSum( 10 ) // throws Error, b is not defined
getSum( undefined, 10 ) // throws Error, a is not defined
```
`_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)
================================================
FILE: _posts/es_ES/javascript/2016-01-13-tip-to-measure-performance-of-a-javascript-block.md
================================================
---
layout: post
title: Tip para medir el rendimiento de un bloque de Javascript
tip-number: 13
tip-username: manmadareddy
tip-username-profile: https://twitter.com/manmadareddy
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)`
redirect_from:
- /es_es/tip-to-measure-performance-of-a-javascript-block/
categories:
- es_ES
- javascript
---
Para medir rápidamente el rendimiento de un bloque de Javascript, podemos utilizar las funciones de la consola como
[`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)
```javascript
console.time("Array initialize");
var arr = new Array(100),
len = arr.length,
i;
for (i = 0; i < len; i++) {
arr[i] = new Object();
};
console.timeEnd("Array initialize"); // Outputs: Array initialize: 0.711ms
```
Más informacion:
[Console object](https://github.com/DeveloperToolsWG/console-object),
[Javascript benchmarking](https://mathiasbynens.be/notes/javascript-benchmarking)
Demo: [jsfiddle](https://jsfiddle.net/meottb62/) - [codepen](http://codepen.io/anon/pen/JGJPoa) (outputs in browser console)
================================================
FILE: _posts/es_ES/javascript/2016-01-14-fat-arrow-functions.md
================================================
---
layout: post
title: Funciones de flechas de direcciones.
tip-number: 14
tip-username: pklinger
tip-username-profile: https://github.com/pklinger/
tip-tldr: Introducido como una nueva característica en ES6, funciones de dirección pueden ser una herramienta muy útil para escribir más código en un menor número de líneas
redirect_from:
- /es_es/fat-arrow-functions/
categories:
- es_ES
- javascript
---
Introducido como una nueva característica en ES6, funciones de dirección pueden ser una herramienta muy útil para escribir más código en un menor número de líneas. El nombre proviene de su sintaxis, `=>`, que es una "flecha", en comparación con una flecha delgada `->`. Algunos programas ya reconocen a este tipo de función de diferentes lenguajes como Haskell, como 'lambda expressions', o 'anonymous functions'. Se le llama en el anonimato, ya que estas funciones de dirección no tienen un nombre de función descriptiva.
### ¿Cuales son los beneficios?
* Sintaxis: menos LOC; no más escribir palabra clave `function` una y otra vez
* Semántica: captura de la palabra clave `this` del contexto que lo rodea
### Ejemplo de sintaxis sencilla
Have a look at these two code snippets, which do the exact same job, and you will quickly understand what fat arrow functions do:
Echar un vistazo a estos dos fragmentos de código, que hacen exactamente el mismo trabajo, y usted entenderá rápidamente qué hacen las funciones de dirección:
```javascript
// general syntax for fat arrow functions
param => expression
// may also be written with parentheses
// parentheses are required on multiple params
(param1 [, param2]) => expression
// using functions
var arr = [5,3,2,9,1];
var arrFunc = arr.map(function(x) {
return x * x;
});
console.log(arr)
// using fat arrow
var arr = [5,3,2,9,1];
var arrFunc = arr.map((x) => x*x);
console.log(arr)
```
As you can see, the fat arrow function in this case can save you time typing out the parentheses as well as the function and return keywords. I would advise you to always write parentheses around the parameter inputs, as the parentheses will be needed for multiple input parameters, such as in `(x,y) => x+y`. It is just a way to cope with forgetting them in different use cases. But the code above would also work like this: `x => x*x`. So far, these are only syntactical improvements, which lead to fewer LOC and better readability.
Como se puede ver, la función de flecha en este caso le puede ahorrar tiempo a escribir los paréntesis, así como la palabras clave function y return. Yo aconsejaría escribir siempre paréntesis en torno a los parámetros de entrada, como serán necesarios los paréntesis para varios parámetros de entrada, como en `(x,y) => x+y`. Pero el código anterior también sería el siguiente: `x => x*x`. Hasta ahora, estos son sólo mejoras sintácticas, que conducen a menos LOC y una mejor legibilidad.
### Léxico de unión `this`
There is another good reason to use fat arrow functions. There is the issue with the context of `this`. With arrow functions, you don't need to worry about `.bind(this)` or setting `that = this` anymore, as fat arrow functions pick the context of `this` from the lexical surrounding. Have a look at the next [example] (https://jsfiddle.net/pklinger/rw94oc11/):
Hay otra buena razón para utilizar las funciones de dirección. No es el problema con el contexto de `this`. Con las funciones de dirección, usted no necesita preocuparse por `.bind(this)` o el ajuste `that = this`, ya que las funciones de dirección recogen el contexto de `this` del léxico de los alrededores. Echar un vistazo a la siguiente [example] (https://jsfiddle.net/pklinger/rw94oc11/):
```javascript
// globally defined this.i
this.i = 100;
var counterA = new CounterA();
var counterB = new CounterB();
var counterC = new CounterC();
var counterD = new CounterD();
// bad example
function CounterA() {
// CounterA's `this` instance (!! gets ignored here)
this.i = 0;
setInterval(function () {
// `this` refers to global object, not to CounterA's `this`
// therefore starts counting with 100, not with 0 (local this.i)
this.i++;
document.getElementById("counterA").innerHTML = this.i;
}, 500);
}
// manually binding that = this
function CounterB() {
this.i = 0;
var that = this;
setInterval(function() {
that.i++;
document.getElementById("counterB").innerHTML = that.i;
}, 500);
}
// using .bind(this)
function CounterC() {
this.i = 0;
setInterval(function() {
this.i++;
document.getElementById("counterC").innerHTML = this.i;
}.bind(this), 500);
}
// fat arrow function
function CounterD() {
this.i = 0;
setInterval(() => {
this.i++;
document.getElementById("counterD").innerHTML = this.i;
}, 500);
}
```
Para más información acerca de las funciones de dirección se puede encontrar en [MDN] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions). To see different syntax options visit [this site] (http://jsrocks.org/2014/10/arrow-functions-and-their-scope/).
================================================
FILE: _posts/es_ES/javascript/2016-01-15-even-simpler-way-of-using-indexof-as-a-contains-clause.md
================================================
---
layout: post
title: Manera aún más sencilla de contener la cláusula al usar `indexOf`
tip-number: 15
tip-username: jhogoforbroke
tip-username-profile: https://twitter.com/jhogoforbroke
tip-tldr: JavaScript por defecto no tiene un método contains. Y para comprobar la existencia de una subcadena en una cadena o un elemento de un array puede hacer esto.
redirect_from:
- /es_es/even-simpler-way-of-using-indexof-as-a-contains-clause/
categories:
- es_ES
- javascript
---
JavaScript por defecto no tiene un método contains. Y para comprobar la existencia de una subcadena en una cadena o un elemento de un array puede hacer esto:
```javascript
var someText = 'javascript rules';
if (someText.indexOf('javascript') !== -1) {
}
// or
if (someText.indexOf('javascript') >= 0) {
}
```
Pero vea esto [Expressjs](https://github.com/strongloop/express) code snippets.
[examples/mvc/lib/boot.js](https://github.com/strongloop/express/blob/2f8ac6726fa20ab5b4a05c112c886752868ac8ce/examples/mvc/lib/boot.js#L26)
```javascript
for (var key in obj) {
// "reserved" exports
if (~['name', 'prefix', 'engine', 'before'].indexOf(key)) continue;
```
[lib/utils.js](https://github.com/strongloop/express/blob/2f8ac6726fa20ab5b4a05c112c886752868ac8ce/lib/utils.js#L93)
```javascript
exports.normalizeType = function(type){
return ~type.indexOf('/')
? acceptParams(type)
: { value: mime.lookup(type), params: {} };
};
```
[examples/web-service/index.js](https://github.com/strongloop/express/blob/2f8ac6726fa20ab5b4a05c112c886752868ac8ce/examples/web-service/index.js#L35)
```javascript
// key is invalid
if (!~apiKeys.indexOf(key)) return next(error(401, 'invalid api key'));
```
El gotcha es el [bitwise operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) **~**, "Operadores bit a bit realizan sus operaciones en representaciones binarias, sino que devuelven valores numéricos estándar de JavaScript."
Transforma `-1` en `0`, and `0` evalúa como false JavaScript:
```javascript
var someText = 'text';
!!~someText.indexOf('tex'); // someText contains "tex" - true
!~someText.indexOf('tex'); // someText NOT contains "tex" - false
~someText.indexOf('asd'); // someText doesn't contain "asd" - false
~someText.indexOf('ext'); // someText contains "ext" - true
```
### String.prototype.includes()
ES6 introdujo [includes() method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes) y se puede usar para determinar si o no una cadena incluye otra cadena:
```javascript
'something'.includes('thing'); // true
```
Con ECMAScript 2016 (ES7) incluso es posible utilizar estas técnicas con Arrays:
```javascript
!!~[1, 2, 3].indexOf(1); // true
[1, 2, 3].includes(1); // true
```
**Sólo se admite en Chrome, Firefox, Safari 9 o superior y Edge; No EI11 o inferior.**
**Es mejor utilizados en ambientes controlados.**
================================================
FILE: _posts/es_ES/javascript/2016-01-16-passing-arguments-to-callback-functions.md
================================================
---
layout: post
title: Paso de argumentos a las funciones de callback.
tip-number: 16
tip-username: minhazav
tip-username-profile: https://twitter.com/minhazav
tip-tldr: JavaScript modules and build steps are getting more numerous and complicated, but what about boilerplate in new frameworks? Modulos JavaScript y construir pasos son cada vez más numerosos y complicados, pero ¿qué pasa en nuevos frameworks?
redirect_from:
- /es_es/passing-arguments-to-callback-functions/
categories:
- es_ES
- javascript
---
Por defecto no se puede pasar argumentos a una función de callback. Por ejemplo:
```js
function callback() {
console.log('Hi human');
}
document.getElementById('someelem').addEventListener('click', callback);
```
You can take advantage of the closure scope in Javascript to pass arguments to callback functions. Check this example:
Puede aprovechar el closure scope en Javascript para pasar argumentos a funciones de callback. Compruebe este ejemplo:
```js
function callback(a, b) {
return function() {
console.log('sum = ', (a+b));
}
}
var x = 1, y = 2;
document.getElementById('someelem').addEventListener('click', callback(x, y));
```
### Que son closures?
Closures son funciones que hacen referencia a las variables independientes (gratis). En otras palabras, la función definida en el closure "recuerda" el scope en el que se creó. [Check MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) para conocer mas.
Así de esta manera los argumentos `x` y `y` están en el scope de la función de callback cuando se le llama.
Otro método para hacerlo es usando el método `bind`. Por ejemplo:
```js
var alertText = function(text) {
alert(text);
};
document.getElementById('someelem').addEventListener('click', alertText.bind(this, 'hello'));
```
Hay una ligera diferencia en el rendimiento de ambos métodos, ver [jsperf](http://jsperf.com/bind-vs-closure-23).
================================================
FILE: _posts/es_ES/javascript/2016-01-17-nodejs-run-a-module-if-it-is-not-required.md
================================================
---
layout: post
title: Node.js - ejecutar un módulo si no es `required`
tip-number: 17
tip-username: odsdq
tip-username-profile: https://twitter.com/odsdq
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.
redirect_from:
- /es_es/nodejs-run-a-module-if-it-is-not-required/
categories:
- es_ES
- javascript
---
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.
```js
if (!module.parent) {
// ran with `node something.js`
app.listen(8088, function() {
console.log('app listening on port 8088');
})
} else {
// used with `require('/.something.js')`
module.exports = app;
}
```
Ver [the documentation for modules](https://nodejs.org/api/modules.html#modules_module_parent) para mas informacion.
================================================
FILE: _posts/es_ES/javascript/2016-01-18-rounding-the-fast-way.md
================================================
---
layout: post
title: Redondeo, la manera mas rápida
tip-number: 18
tip-username: pklinger
tip-username-profile: https://github.com/pklinger
tip-tldr: El tip de hoy es sobre el rendimiento. Nunca llegó a través del operador doble tilde `~~`? A veces también se llama el doble operador NOT (operador de bits). Se puede utilizar como un sustituto más rápido para `Math.floor()`. ¿Porqué es eso?
redirect_from:
- /es_es/rounding-the-fast-way/
categories:
- es_ES
- javascript
---
El tip de hoy es sobre el rendimiento. [Nunca llegó a través del operador dobletilde] (http://stackoverflow.com/questions/5971645/what-is-the-double-tilde-operator-in-javascript) `~~`? A veces también se llama el doble operador NOT (operador de bits). Se puede utilizar como un sustituto más rápido para `Math.floor()`. ¿Porqué es eso?
One bitwise shift `~` transforms the 32 bit converted input into `-(input+1)`. The double bitwise shift therefore transforms the input into `-(-(input + 1)+1)` making it a great tool to round towards 0. For numeric input, it therefore mimics the `Math.ceil()` for negative and `Math.floor()` for positive input. On failure, `0` is returned, which might come in handy sometimes instead of `Math.floor()`, which returns a value of `NaN` on failure.
Un desplazamiento en modo bit `~` transforma 32 bits de entrada `-(input+1)`. Por tanto, el cambio de doble bit a bit transforma la entrada en `-(-(input + 1)+1)` por lo que es una gran herramienta para redondear hacia 0. Para la entrada numérica, de este modo imita el `Math.ceil()` para el negativo y `Math.floor()` para la entrada positiva. En caso de error, se devuelve `0`, lo que podría ser útil a veces en lugar de `Math.floor()`,que devuelve un valor de `NaN` en caso de fallo.
```javascript
// single ~
console.log(~1337) // -1338
// numeric input
console.log(~~47.11) // -> 47
console.log(~~-12.88) // -> -12
console.log(~~1.9999) // -> 1
console.log(~~3) // -> 3
// on failure
console.log(~~[]) // -> 0
console.log(~~NaN) // -> 0
console.log(~~null) // -> 0
// greater than 32 bit integer fails
console.log(~~(2147483647 + 1) === (2147483647 + 1)) // -> 0
```
A pesar de que `~~` puede funcionar mejor, por el bien de la legibilidad por favor utilice `Math.floor()`.
================================================
FILE: _posts/es_ES/javascript/2016-01-19-safe-string-concatenation.md
================================================
---
layout: post
title: Concatenación de Strings segura
tip-number: 19
tip-username: gogainda
tip-username-profile: https://twitter.com/gogainda
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
redirect_from:
- /es_es/safe-string-concatenation/
categories:
- es_ES
- javascript
---
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':
```javascript
var one = 1;
var two = 2;
var three = '3';
var result = ''.concat(one, two, three); //"123"
```
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:
```javascript
var one = 1;
var two = 2;
var three = '3';
var result = one + two + three; //"33" instead of "123"
```
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.
Puede leer mas sobre `concat` en MDN [page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/concat).
================================================
FILE: _posts/es_ES/javascript/2016-01-20-return-objects-to-enable-chaining-of-functions.md
================================================
---
layout: post
title: Devolver los objetos que permiten el encadenamiento de las funciones
tip-number: 20
tip-username: WakeskaterX
tip-username-profile: https://twitter.com/WakeStudio
tip-tldr: Al crear funciones en un objeto en Javascript orientado a objetos, devolver el objeto a la función le permitirá encadenar funciones.
redirect_from:
- /es_es/return-objects-to-enable-chaining-of-functions/
categories:
- es_ES
- javascript
---
Al crear funciones en un objeto en Javascript orientado a objetos, devolver el objeto a la función le permitirá encadenar funciones.
```js
function Person(name) {
this.name = name;
this.sayName = function() {
console.log("Hello my name is: ", this.name);
return this;
};
this.changeName = function(name) {
this.name = name;
return this;
};
}
var person = new Person("John");
person.sayName().changeName("Timmy").sayName();
```
================================================
FILE: _posts/es_ES/javascript/2016-01-21-shuffle-an-array.md
================================================
---
layout: post
title: Mezclar un Array
tip-number: 21
tip-username: 0xmtn
tip-username-profile: https://github.com/0xmtn/
tip-tldr: Fisher-Yates Shuffling es un algoritmo para mezclar un array.
redirect_from:
- /es_es/shuffle-an-array/
categories:
- es_ES
- javascript
---
Este codigo utiliza [Fisher-Yates Shuffling](https://www.wikiwand.com/en/Fisher%E2%80%93Yates_shuffle) Algoritmo para mezclar un array.
```javascript
function shuffle(arr) {
var i,
j,
temp;
for (i = arr.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return arr;
};
```
Ejemplo:
```javascript
var a = [1, 2, 3, 4, 5, 6, 7, 8];
var b = shuffle(a);
console.log(b);
// [2, 7, 8, 6, 5, 3, 1, 4]
```
================================================
FILE: _posts/es_ES/javascript/2016-01-22-two-ways-to-empty-an-array.md
================================================
---
layout: post
title: Dos formas de vacia un array
tip-number: 22
tip-username: microlv
tip-username-profile: https://github.com/microlv
tip-tldr: En JavaScript cuando se quiere vaciar un array, hay una muchas maneras, pero esta es la mas potente.
redirect_from:
- /es_es/two-ways-to-empty-an-array/
categories:
- es_ES
- javascript
---
Se define un array y desea vaciar su contenido.
Por lo general, usted lo haría así:
```javascript
// define Array
var list = [1, 2, 3, 4];
function empty() {
//empty your array
list = [];
}
empty();
```
Pero hay otra manera de vaciar un array que es más performante.
Debe utilizar un código como este:
```javascript
var list = [1, 2, 3, 4];
function empty() {
//empty your array
list.length = 0;
}
empty();
```
* `list = []` asigna una referencia a un nuevo array a una variable, mientras que las otras referencias no se ven afectadas.
Lo que significa que las referencias a los contenidos del array anterior todavía se mantienen en la memoria, lo que lleva a pérdidas de memoria.
* `list.length = 0` borra todo el contenido del array, lo que afecta otras referencias.
In other words, if you have two references to the same array (`a = [1,2,3]; a2 = a;`), and you delete the array's contents using `list.length = 0`, both references (a and a2) will now point to the same empty array. (So don't use this technique if you don't want a2 to hold an empty array!)
En otras palabras, si usted tiene dos referencias a el mismo array (`a = [1,2,3]; a2 = a;`), y se elimina el contenido del array usando `list.length = 0`, ambas referencias (a and a2) se apuntan ahora al mismo array vacío. (Así que no se utilice esta técnica si usted no quiere a2 para sostener un array vacío!)
Piense en lo que tendra esta salida:
```js
var foo = [1,2,3];
var bar = [1,2,3];
var foo2 = foo;
var bar2 = bar;
foo = [];
bar.length = 0;
console.log(foo, bar, foo2, bar2);
// [] [] [1, 2, 3] []
```
Stackoverflow mas detalles:
[difference-between-array-length-0-and-array](http://stackoverflow.com/questions/4804235/difference-between-array-length-0-and-array)
================================================
FILE: _posts/es_ES/javascript/2016-01-23-converting-to-number-fast-way.md
================================================
---
layout: post
title: Convertir a numero de la forma mas rapida
tip-number: 23
tip-username: sonnyt
tip-username-profile: http://twitter.com/sonnyt
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 +.
redirect_from:
- /es_es/converting-to-number-fast-way/
categories:
- es_ES
- javascript
---
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).
```javascript
var one = '1';
var numberOne = +one; // Number 1
```
You can also use the `-` (minus) operator which type-converts the value into number but also negates it.
También se puede utilizar el operador `-` (menos) qué convierte el valor en número, sino también la niega.
```javascript
var one = '1';
var negativeNumberOne = -one; // Number -1
```
================================================
FILE: _posts/es_ES/javascript/2016-01-24-use_===_instead_of_==.md
================================================
---
layout: post
title: Utilizar === en lugar de ==
tip-number: 24
tip-username: bhaskarmelkani
tip-username-profile: https://www.twitter.com/bhaskarmelkani
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 `==`.
redirect_from:
- /es_es/use_===_instead_of_==/
categories:
- es_ES
- javascript
---
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 `==`.
```js
[10] == 10 // is true
[10] === 10 // is false
'10' == 10 // is true
'10' === 10 // is false
[] == 0 // is true
[] === 0 // is false
'' == false // is true but true == "a" is false
'' === false // is false
```
================================================
FILE: _posts/es_ES/javascript/2016-01-25-Using-immediately-invoked-function-expression.md
================================================
---
layout: post
title: Invocar una funcion inmediatamente
tip-number: 25
tip-username: rishantagarwal
tip-username-profile: https://github.com/rishantagarwal
tip-tldr: Denominado como "Iffy" >dudoso< (IIFE - expresión de la función invocada inmediatamente) es una expresión de la función anónima que se invoca inmediatamente y tiene algunos usos importantes en Javascript.
redirect_from:
- /es_es/Using-immediately-invoked-function-expression/
categories:
- es_ES
- javascript
---
Denominado como "Iffy" >dudoso< (IIFE - expresión de la función invocada inmediatamente) es una expresión de la función anónima que se invoca inmediatamente y tiene algunos usos importantes en Javascript.
```javascript
(function() {
// Do something
}
)()
```
Es una expresión de función anónima que se invoca de inmediato, y tiene algunos usos particularmente importantes en JavaScript.
El par de paréntesis que rodean la función anónima convierte la función anónima en una expresión de función o expresión variable. Así que en lugar de una simple función anónima en el scope global, o donde quiera que se definió, ahora tenemos una expresión de función sin nombre.
Similarly, we can even create a named, immediately invoked function expression:
Del mismo modo, podemos incluso crear una llamada expresión de función, inmediatamente invocado:
```javascript
(someNamedFunction = function(msg) {
console.log(msg || "Nothing for today !!")
}) (); // Output --> Nothing for today !!
someNamedFunction("Javascript rocks !!"); // Output --> Javascript rocks !!
someNamedFunction(); // Output --> Nothing for today !!
```
Mas detalles URL's -
1. [Link 1](https://blog.mariusschulz.com/2016/01/13/disassembling-javascripts-iife-syntax)
2. [Link 2](http://javascriptissexy.com/12-simple-yet-powerful-javascript-tips/)
Performance:
[jsPerf](http://jsperf.com/iife-with-call)
================================================
FILE: _posts/es_ES/javascript/2016-01-26-filtering-and-sorting-a-list-of-strings.md
================================================
---
layout: post
title: Filtrar y ordenar una lista de Strings
tip-number: 26
tip-username: davegomez
tip-username-profile: https://github.com/davegomez
tip-tldr: Es posible que tenga una gran lista de nombres que necesitas filtrar con el fin de eliminar los duplicados y ordenarlos alfabéticamente.
redirect_from:
- /filtering-and-sorting-a-list-of-strings/
categories:
- es_ES
- javascript
---
Es posible que tenga una gran lista de nombres que necesita filtrar con el fin de eliminar los duplicados y ordenarlos alfabéticamente.
En nuestro ejemplo vamos a utilizar una lista de **palabras clave reservadas de JavaScript** que podemos encontrar en las diferentes versiones del lenguage, pero como se puede observar, hay una gran cantidad de palabras clave duplicadas y no están organizados alfabéticamente. Así que esta es una lista perfecta de cadenas de probar este consejo JavaScript ([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)).
```js
var keywords = ['do', 'if', 'in', 'for', 'new', 'try', 'var', 'case', 'else', 'enum', 'null', 'this', 'true', 'void', 'with', 'break', 'catch', 'class', 'const', 'false', 'super', 'throw', 'while', 'delete', 'export', 'import', 'return', 'switch', 'typeof', 'default', 'extends', 'finally', 'continue', 'debugger', 'function', 'do', 'if', 'in', 'for', 'int', 'new', 'try', 'var', 'byte', 'case', 'char', 'else', 'enum', 'goto', 'long', 'null', 'this', 'true', 'void', 'with', 'break', 'catch', 'class', 'const', 'false', 'final', 'float', 'short', 'super', 'throw', 'while', 'delete', 'double', 'export', 'import', 'native', 'public', 'return', 'static', 'switch', 'throws', 'typeof', 'boolean', 'default', 'extends', 'finally', 'package', 'private', 'abstract', 'continue', 'debugger', 'function', 'volatile', 'interface', 'protected', 'transient', 'implements', 'instanceof', 'synchronized', 'do', 'if', 'in', 'for', 'let', 'new', 'try', 'var', 'case', 'else', 'enum', 'eval', 'null', 'this', 'true', 'void', 'with', 'break', 'catch', 'class', 'const', 'false', 'super', 'throw', 'while', 'yield', 'delete', 'export', 'import', 'public', 'return', 'static', 'switch', 'typeof', 'default', 'extends', 'finally', 'package', 'private', 'continue', 'debugger', 'function', 'arguments', 'interface', 'protected', 'implements', 'instanceof', 'do', 'if', 'in', 'for', 'let', 'new', 'try', 'var', 'case', 'else', 'enum', 'eval', 'null', 'this', 'true', 'void', 'with', 'await', 'break', 'catch', 'class', 'const', 'false', 'super', 'throw', 'while', 'yield', 'delete', 'export', 'import', 'public', 'return', 'static', 'switch', 'typeof', 'default', 'extends', 'finally', 'package', 'private', 'continue', 'debugger', 'function', 'arguments', 'interface', 'protected', 'implements', 'instanceof'];
```
Dado que no queremos cambiar nuestra lista original, vamos a utilizar una función de orden superior llamado [`filter`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), que devolverá un nuevo array filtro basado en un predicado (* Función *) que se pasa a ella. El predicado comparará el índice de la palabra clave actual en la lista original con su `index` en la nueva lista y la pondra en un nuevo array sólo si los índices coinciden.
Por último vamos a ordenar la lista filtrada con ayuda de la funcion[`sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) que toma una función de comparación como el único argumento, devolviendo una lista ordenada alfabéticamente.
```js
var filteredAndSortedKeywords = keywords
.filter(function (keyword, index) {
return keywords.indexOf(keyword) === index;
})
.sort(function (a, b) {
if (a < b) return -1;
else if (a > b) return 1;
return 0;
});
```
**ES6** (ECMAScript 2015) usa [arrow functions](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) se ve un poco mas simple:
```js
const filteredAndSortedKeywords = keywords
.filter((keyword, index) => keywords.indexOf(keyword) === index)
.sort((a, b) => {
if (a < b) return -1;
else if (a > b) return 1;
return 0;
});
```
Y esta es la lista final filtrada y ordenada de palabras clave JavaScript reservados:
```js
console.log(filteredAndSortedKeywords);
// ['abstract', 'arguments', 'await', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'double', 'else', 'enum', 'eval', 'export', 'extends', 'false', 'final', 'finally', 'float', 'for', 'function', 'goto', 'if', 'implements', 'import', 'in', 'instanceof', 'int', 'interface', 'let', 'long', 'native', 'new', 'null', 'package', 'private', 'protected', 'public', 'return', 'short', 'static', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient', 'true', 'try', 'typeof', 'var', 'void', 'volatile', 'while', 'with', 'yield']
```
================================================
FILE: _posts/es_ES/javascript/2016-01-27-short-circiut-evaluation-in-js.md
================================================
---
layout: post
title: Evaluación de Short circuit en JS.
tip-number: 27
tip-username: bhaskarmelkani
tip-username-profile: https://www.twitter.com/bhaskarmelkani
tip-tldr: Evaluación de Short-circuit dice, el segundo argumento se ejecuta o evalúa sólo si el primer argumento no es suficiente para determinar el valor de la expresión, cuando el primer argumento de AND (&&) la función se evalúa como falsa, el valor total debe ser falso; y cuando el primer argumento de la función OR (||) da como resultado true, el valor total debe ser verdad.
redirect_from:
- /es_es/short-circiut-evaluation-in-js/
categories:
- es_ES
- javascript
---
[Evaluación Short-circuit](https://en.wikipedia.org/wiki/Short-circuit_evaluation) dice, el segundo argumento se ejecuta o evalúa sólo si el primer argumento no es suficiente para determinar el valor de la expresión: cuando el primer argumento de la función AND ('&&') se evalúa como falsa, el valor total debe ser falso; y cuando el primer argumento de la función OR ('||') da como resultado true, el valor total debe ser verdad.
Para el siguiente funcion `test` condición and `isTrue` y 'isFalse'.
```js
var test = true;
var isTrue = function(){
console.log('Test is true.');
};
var isFalse = function(){
console.log('Test is false.');
};
```
Usar logico AND - `&&`.
```js
// A normal if statement.
if(test){
isTrue(); // Test is true
}
// Above can be done using '&&' as -
( test && isTrue() ); // Test is true
```
Usar logico OR - `||`.
```js
test = false;
if(!test){
isFalse(); // Test is false.
}
( test || isFalse()); // Test is false.
```
La lógica OR también podría ser utilizado para establecer un valor predeterminado para el argumento de la función.
```js
function theSameOldFoo(name){
name = name || 'Bar' ;
console.log("My best friend's name is " + name);
}
theSameOldFoo(); // My best friend's name is Bar
theSameOldFoo('Bhaskar'); // My best friend's name is Bhaskar
```
La lógica AND podría ser utilizado para evitar excepciones utilizando las propiedades de undefined.
Ejemplo:-
```js
var dog = {
bark: function(){
console.log('Woof Woof');
}
};
// Calling dog.bark();
dog.bark(); // Woof Woof.
//But if dog is not defined, dog.bark() will raise an error "Cannot read property 'bark' of undefined."
// To prevent this, we can you &&.
dog&&dog.bark(); // This will only call dog.bark(), if dog is defined.
```
================================================
FILE: _posts/es_ES/javascript/2016-01-28-curry-vs-partial-application.md
================================================
---
layout: post
title: Currying vs partial application
tip-number: 28
tip-username: bhaskarmelkani
tip-username-profile: https://www.twitter.com/bhaskarmelkani
tip-tldr: Currying and partial application son dos maneras de transformar una funcion en otra funcion generalidad muy pequeña.
redirect_from:
- es_es/curry-vs-partial-application/
categories:
- es_ES
- javascript
---
**Currying**
Currying toma una función
f: X * Y -> R
y lo convierte en una función
f': X -> (Y -> R)
En lugar de llamar f con dos argumentos, invocamos f' con el primer argumento. El resultado es una función que entonces llamamos con el segundo argumento para producir el resultado.
Por lo tanto, si el f no es comparable se invoca como
f(3,5)
entonces el f' comparables es invocada como
f(3)(5)
Por ejemplo:
Uncurried add()
```javascript
function add(x, y) {
return x + y;
}
add(3, 5); // returns 8
```
Curried add()
```javascript
function addC(x) {
return function (y) {
return x + y;
}
}
addC(3)(5); // returns 8
```
**El algoritmo para currying.**
Curry toma una función binaria y devuelve una función unaria, función que devuelve una función unaria.
curry: (X × Y → R) → (X → (Y → R))
Codigo Javascript:
```javascript
function curry(f) {
return function(x) {
return function(y) {
return f(x, y);
}
}
}
```
**Partial application**
Partial application toma una funcion
f: X * Y -> R
y un valor fijo para el primer argumento para producir una nueva función
f`: Y -> R
f' hace lo mismo que f, pero sólo tiene que completar el segundo parámetro.
Por ejemplo: almacenando el primer argumento de la función de añadir a 5 resulta la función más 5.
```javascript
function plus5(y) {
return 5 + y;
}
plus5(3); // returns 8
```
**El algoritmo de partial application.**
partApply toma una función y un valor binario y produce una función unaria.
partApply : ((X × Y → R) × X) → (Y → R)
Codigo Javascript:
```javascript
function partApply(f, x) {
return function(y) {
return f(x, y);
}
}
```
================================================
FILE: _posts/es_ES/javascript/2016-01-29-speed-up-recursive-functions-with-memoization.md
================================================
---
layout: post
title: Acelerar las funciones recursivas con memoization
tip-number: 29
tip-username: hingsir
tip-username-profile: https://github.com/hingsir
tip-tldr: Fibonacci es muy familiar. Podemos escribir la siguiente función en 20 segundos, pero no eficiente. Se puede almacenar en caché los resultados previamente calculados para acelerarlo.
redirect_from:
- /es_es/speed-up-recursive-functions-with-memoization/
categories:
- es_ES
- javascript
---
Fibonacci es muy familiar. podemos escribir la siguiente función en 20 segundos.
```js
var fibonacci = function(n){
return n < 2 ? n : fibonacci(n-1) + fibonacci(n-2);
}
```
funciona, pero no es eficiente. Se pueden almacenar en caché los resultados previamente calculados para acelerarlo.
```js
var fibonacci = (function(){
var cache = {
0: 0,
1: 1
};
return function self(n){
return n in cache ? cache[n] : (cache[n] = self(n-1) + self(n-2));
}
})()
```
También, podemos definir una función de orden superior que acepta una función como argumento y devuelve una versión memoized de la función.
```js
var memoize = function(func){
var cache = {};
return function(){
var key = Array.prototype.slice.call(arguments).toString();
return key in cache ? cache[key] : (cache[key] = func.apply(this,arguments));
}
}
fibonacci = memoize(fibonacci);
```
Y hay una versión ES6 de la función memoize.
```js
var memoize = function(func){
const cache = {};
return (...args) => {
const key = [...args].toString();
return key in cache ? cache[key] : (cache[key] = func(...args));
}
}
fibonacci = memoize(fibonacci);
```
podemos usar `memoize()` en muchas otras situciones
* GCD(Greatest Common Divisor)
```js
var gcd = memoize(function(a,b){
var t;
if (a < b) t=b, b=a, a=t;
while(b != 0) t=b, b = a%b, a=t;
return a;
})
gcd(27,183); //=> 3
```
* Calculo Factorial
```js
var factorial = memoize(function(n) {
return (n <= 1) ? 1 : n * factorial(n-1);
})
factorial(5); //=> 120
```
================================================
FILE: _posts/es_ES/javascript/2016-01-30-converting-truthy-falsy-values-to-boolean.md
================================================
---
layout: post
title: Convertir valores truthy/falsy a boolean
tip-number: 30
tip-username: hakhag
tip-username-profile: https://github.com/hakhag
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.
redirect_from:
- /es_es/converting-truthy-falsy-values-to-boolean/
categories:
- es_ES
- javascript
---
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.
```js
!!"" // false
!!0 // false
!!null // false
!!undefined // false
!!NaN // false
!!"hello" // true
!!1 // true
!!{} // true
!![] // true
```
================================================
FILE: _posts/es_ES/javascript/2016-01-31-avoid-modifying-or-passing-arguments-into-other-functions—it-kills-optimization.md
================================================
---
layout: post
title: Evitar la modificación o pasando `arguments` en otras funciones - mata la optimización
tip-number: 31
tip-username: berkana
tip-username-profile: https://github.com/berkana
tip-tldr: Dentro de las funciones de JavaScript, el nombre de la variable `arguments` le permite acceder a todos los argumentos pasados a la función. `arguments` en un *array-like object*; `arguments` se puede acceder usando array notation, y tiene la propiedad *longitud*, pero no tiene muchos de los métodos incorporados en arrays que tienen como `filter` y `map` y `forEach`. Debido a esto, es una práctica bastante común para convertir `arguments` en una matriz utilizando el siguiente fragmento.
redirect_from:
- /es_es/avoid-modifying-or-passing-arguments-into-other-functions-it-kills-optimization/
categories:
- es_ES
- javascript
---
###Background
Dentro de las funciones de JavaScript, el nombre de la variable [`arguments`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments) le permite acceder a todos los argumentos pasados a la función. `arguments` es una *array-like object*; `arguments` se puede acceder usando la array notation, y tiene la propiedad *longitud*, pero no tiene por qué muchos de los métodos incorporados en los arrays que tienen como`filter` y `map` y `foreach`. Debido a esto, es una práctica bastante común para convertir `arguments` en un array utilizando:
```js
var args = Array.prototype.slice.call(arguments);
```
Este método `slice` del prototipo `array`, pasándole `arguments`; el método `slice` devuelve una copia superficial del `arguments` como un nuevo objeto de matriz. A la abreviatura común para esto es:
```js
var args = [].slice.call(arguments);
```
En este caso, en lugar de llamar `slice` del prototipo `Array`, se trata simplemente de ser llamado desde un array vacío literal.
###Optimización
Desafortunadamente, pasando `arguments` en cualquier llamada de función hará que el motor V8 JavaScript utilizado en Chrome y NodeJS para omitir la optimización de la función que hace esto, lo que puede resultar en un rendimiento considerablemente más lento. Ver este artículo [optimization killers](https://github.com/petkaantonov/bluebird/wiki/Optimization-killers). Pasando `arguments` a cualquier otra función que se conoce como *leaking `arguments`*.
En cambio, si quieres un array de los argumentos que le permite utilizar lo que necesita recurrir a este:
```js
var args = new Array(arguments.length);
for(var i = 0; i < args.length; ++i) {
args[i] = arguments[i];
}
```
Sí, es más prolija, pero en el código de producción, vale la pena para la optimización del rendimiento.
================================================
FILE: _posts/es_ES/javascript/2016-02-01-map-to-the-rescue-adding-order-to-object-properties.md
================================================
---
layout: post
title: Map() al rescate; añadir orden a las propiedades de los Objetos.
tip-number: 32
tip-username: loverajoel
tip-username-profile: https://twitter.com/loverajoel
tip-tldr: Un objeto es una colección desordenada de propiedades... que significa que si está tratando de guardar los datos ordenados dentro de un objeto, hay que revisarlo debido a que las propiedades de orden en los objetos no están garantizados.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /es_es/map-to-the-rescue-adding-order-to-object-properties/
categories:
- es_ES
- javascript
---
## Propiedades de orden del Objeto
> Un objeto es un miembro del tipo de objeto. Es una colección desordenada de las propiedades de cada uno de los cuales contiene un valor primitivo, objeto o función. Una función almacenada en una propiedad de un objeto se llama un método.[ECMAScript](http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf)
Veamos en acción
```js
var myObject = {
z: 1,
'@': 2,
b: 3,
1: 4,
5: 5
};
console.log(myObject) // Object {1: 4, 5: 5, z: 1, @: 2, b: 3}
for (item in myObject) {...
// 1
// 5
// z
// @
// b
```
Cada navegador tiene sus propias reglas sobre el orden en los objetos porque técnicamente, el orden no se especifica.
## Como solucionar esto?
### Map
Usando una nueva característica de ES6 llamada Map. [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) objeto itera sus elementos con el fin de inserción - un `for...of` devuelve un array de [clave, valor] para cada iteración.
```js
var myObject = new Map();
myObject.set('z', 1);
myObject.set('@', 2);
myObject.set('b', 3);
for (var [key, value] of myObject) {
console.log(key, value);
...
// z 1
// @ 2
// b 3
```
### Hack para navegadores antiguos
Sugerencias de Mozilla:
> Por lo tanto, si desea simular el orden asociado al array en un entorno cross-browser, se ve obligado a usar dos array independientes (uno para las key y el otro para los valores), o construir una array de objetos de single-property, etc.
```js
// usando dos arrays separados
var objectKeys = [z, @, b, 1, 5];
for (item in objectKeys) {
myObject[item]
...
// Creando un array de objetos de single-property
var myData = [{z: 1}, {'@': 2}, {b: 3}, {1: 4}, {5: 5}];
```
================================================
FILE: _posts/es_ES/javascript/2016-02-02-create-range-0-n-easily-using-one-line.md
================================================
---
layout: post
title: Crear rangos 0...(N-1) facilmente usando una linea
tip-number: 33
tip-username: SarjuHansaliya
tip-username-profile: https://github.com/SarjuHansaliya
tip-tldr: Podemos crear una función de rango que dará un rango entre 0...(N-1) utilizando una sola línea
redirect_from:
- /es_es/create-range-0-n-easily-using-one-line/
categories:
- es_ES
- javascript
---
A continuación mostraremos como crear el rango 0...N-1).
```js
Array.apply(null, {length: N}).map(Number.call, Number);
```
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()`.
```js
function add(a, b){
return (a+b);
}
add.call(null, 5, 6);
```
Esto devolverá una suma de 5 y 6.
`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:
```js
[1, 2, 3].map(function(value, index, arr){
//Code
}, this);
```
Debajo de la línea crea array de longitud dada.
```js
Array.apply(null, {length: N})
```
Poner todas las partes juntas a continuación es la solución.
```js
Array.apply(null, {length: N}).map(Number.call, Number);
```
Si tiene un rango 1...N, que sera como este.
```js
Array.apply(null, {length: N}).map(function(value, index){
return index+1;
});
```
================================================
FILE: _posts/es_ES/javascript/2016-02-03-implementing-asynchronous-loops.md
================================================
---
layout: post
title: Implementación de bucle asíncrono.
tip-number: 34
tip-username: madmantalking
tip-username-profile: https://github.com/madmantalking
tip-tldr: Puedes tener problemas al implementar bucles asíncronos.
redirect_from:
- /es_es/implementing-asynchronous-loops/
categories:
- es_ES
- javascript
---
Vamos a probar a escribir una función asíncrona que imprime el valor del índice del bucle cada segundo.
```js
for (var i=0; i<5; i++) {
setTimeout(function(){
console.log(i);
}, 1000);
}
```
La salida de los script antes mencionados resulta ser
```js
> 5
> 5
> 5
> 5
> 5
```
Así que esto definitivamente no funciona.
**Explicación**
Cada timeout se refiere a la original `i`, no una copia. Por lo que el bucle de incrementos `i` hasta que llega a 5, entonces comienza a dar timeuot y utilizar el valor actual de `i` (que es 5).
Pues bien, este problema parece fácil. Una solución inmediata es almacenar en caché el índice de bucle en una variable temporal.
```js
for (var i=0; i<5; i++) {
var temp = i;
setTimeout(function(){
console.log(temp);
}, 1000);
}
```
Pero de nuevo la salida de los script anteriores resulta ser
```js
> 4
> 4
> 4
> 4
> 4
```
Por lo tanto, eso no funciona bien, porque los bloques no crean un ámbito de aplicación y las variables de inicializadores se izan a la parte superior del scope. De hecho, el bloque anterior es el mismo que:
```js
var temp;
for (var i=0; i<5; i++) {
temp = i;
setTimeout(function(){
console.log(temp);
}, 1000);
}
```
**Solución**
Hay algunas maneras diferentes para copiar `i`. La forma más común es la creación de un closure declarando una función que se le pasa `i` como un argumento. Aquí hacemos esto como una función de auto-llamada.
```js
for (var i=0; i<5; i++) {
(function(num){
setTimeout(function(){
console.log(num);
}, 1000);
})(i);
}
```
En JavaScript, los argumentos se pasan por valor a una función. Así tipos primitivos como números, fechas, y las cadenas son básicamente copiados. Si los cambia dentro de la función, que no afecta el scope exterior. Los objetos son especiales: si la función cambia dentro de una propiedad, el cambio se refleja en todos los scopes.
Otro camino para esto sería con el uso de `let`.
```js
for (let i=0; i<5; i++) {
var temp = i;
setTimeout(function(){
console.log(temp);
}, 1000);
}
```
================================================
FILE: _posts/es_ES/javascript/2016-02-04-assignment-shorthands.md
================================================
---
layout: post
title: Operadores de Asignación
tip-number: 35
tip-username: hsleonis
tip-username-profile: https://github.com/hsleonis
tip-tldr: Asignación es muy común. A veces volvemos a escribir, perdemos tiempo los 'Programadores perezosos'. Por lo tanto, podemos utilizar algunos trucos para ayudarnos y hacer nuestro código más claro y más simple.
redirect_from:
- /es_es/assignment-shorthands/
categories:
- es_ES
- javascript
---
Asignación es muy común. A veces volvemos a escribir, perdemos tiempo los 'Programadores perezosos'. Por lo tanto, podemos utilizar algunos trucos para ayudarnos y hacer nuestro código más claro y más simple.
Este es el uso similar de
````javascript
x += 23; // x = x + 23;
y -= 15; // y = y - 15;
z *= 10; // z = z * 10;
k /= 7; // k = k / 7;
p %= 3; // p = p % 3;
d **= 2; // d = d ** 2;
m >>= 2; // m = m >> 2;
n <<= 2; // n = n << 2;
n ++; // n = n + 1;
n --; n = n - 1;
````
### If-else (Usando operador ternario)
Esto es lo que se escribe de manera regular.
````javascript
var newValue;
if(value > 10)
newValue = 5;
else
newValue = 2;
````
Podemos utilizar el operador ternario para que sea impresionante:
````javascript
var newValue = (value > 10) ? 5 : 2;
````
### Null, Undefined, Empty Checks
````javascript
if (variable1 !== null || variable1 !== undefined || variable1 !== '') {
var variable2 = variable1;
}
````
Abreviación:
````javascript
var variable2 = variable1 || '';
````
P.D.: Si variable1 en un numero, luego controla primero si es 0
### Object Array Notation
En lugar de usar:
````javascript
var a = new Array();
a[0] = "myString1";
a[1] = "myString2";
````
Utilice:
````javascript
var a = ["myString1", "myString2"];
````
### Associative array
En lugar de usar:
````javascript
var skillSet = new Array();
skillSet['Document language'] = 'HTML5';
skillSet['Styling language'] = 'CSS3';
````
Utilice:
````javascript
var skillSet = {
'Document language' : 'HTML5',
'Styling language' : 'CSS3'
};
````
================================================
FILE: _posts/es_ES/javascript/2016-02-05-observe-dom-changes.md
================================================
---
layout: post
title: Observar los cambios del DOM en extensiones.
tip-number: 36
tip-username: beyondns
tip-username-profile: https://github.com/beyondns
tip-tldr: AL desarrollar extensiones de sitios existentes no es tan fácil interactuar con el DOM a causa de la moderna dinamica de javascript.
redirect_from:
- /es_es/observe-dom-changes/
categories:
- es_ES
- javascript
---
[MutationObserver](https://developer.mozilla.org/en/docs/Web/API/MutationObserver) es una solución para escuchar a los cambios del DOM y hacer lo que quiere hacer con los elementos cuando cambiaron. En el siguiente ejemplo, hay una cierta emulación del contenido de la carga dinámica con una ayuda de contadores de tiempo, después de la primera creación del elemento "target" pasa "subTarget".
En código de la extensión en primer lugar rootObserver funciona hasta la apariencia del targetElement luego empieza el elementObserver. Esta observación en cascada ayuda a obtener finalmente el momento en que se encuentra subTargetElement.
Es útil para desarrollar extensiones a los sitios complejos con contenido de carga dinámica.
```js
const observeConfig = {
attributes: true,
childList: true,
characterData: true,
subtree: true
};
function initExtension(rootElement, targetSelector, subTargetSelector) {
var rootObserver = new MutationObserver(function(mutations) {
console.log("Inside root observer");
targetElement = rootElement.querySelector(targetSelector);
if (targetElement) {
rootObserver.disconnect();
var elementObserver = new MutationObserver(function(mutations) {
console.log("Inside element observer")
subTargetElement = targetElement.querySelector(subTargetSelector);
if (subTargetElement) {
elementObserver.disconnect();
console.log("subTargetElement found!")
}
})
elementObserver.observe(targetElement, observeConfig);
}
})
rootObserver.observe(rootElement, observeConfig);
}
(function() {
initExtension(document.body, "div.target", "div.subtarget")
setTimeout(function() {
del = document.createElement("div");
del.innerHTML = "
target
"
document.body.appendChild(del)
}, 3000);
setTimeout(function() {
var el = document.body.querySelector('div.target')
if (el) {
del = document.createElement("div");
del.innerHTML = "
subtarget
"
el.appendChild(del)
}
}, 5000);
})()
```
================================================
FILE: _posts/es_ES/javascript/2016-02-06-deduplicate-an-array.md
================================================
---
layout: post
title: Deduplique un Array
tip-number: 37
tip-username: danillouz
tip-username-profile: https://www.twitter.com/danillouz
tip-tldr: Cómo eliminar elementos duplicados, de diferentes tipos de datos, a partir de un Array.
redirect_from:
- /es_es/deduplicate-an-array/
categories:
- es_ES
- javascript
---
# Primitivos
Si una matriz sólo contiene valores primitivos, podemos desduplicar
solo utilizando [`filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) and [`indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) methods.
```javascript
var deduped = [ 1, 1, 'a', 'a' ].filter(function (el, i, arr) {
return arr.indexOf(el) === i;
});
console.log(deduped); // [ 1, 'a' ]
```
## ES2015
Podemos escribir esto de una manera más compacta utilizando [arrow function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions).
```javascript
var deduped = [ 1, 1, 'a', 'a' ].filter( (el, i, arr) => arr.indexOf(el) === i);
console.log(deduped); // [ 1, 'a' ]
```
Sin embargo, con la introducción de [Sets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) y de [`from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from) se puede lograr lo mismo como resultado de una manera más concisa.
```javascript
var deduped = Array.from( new Set([ 1, 1, 'a', 'a' ]) );
console.log(deduped); // [ 1, 'a' ]
```
# Objects
No podemos usar el mismo enfoque cuando los elementos son Objects,
Dado que los Objects se almacenan como referencia y se almacenan primitivas
por valor.
```javascript
1 === 1 // true
'a' === 'a' // true
{ a: 1 } === { a: 1 } // false
```
Por lo tanto tenemos que cambiar nuestro enfoque y utilizar una tabla hash.
```javascript
function dedup(arr) {
var hashTable = {};
return arr.filter(function (el) {
var key = JSON.stringify(el);
var match = Boolean(hashTable[key]);
return (match ? false : hashTable[key] = true);
});
}
var deduped = dedup([
{ a: 1 },
{ a: 1 },
[ 1, 2 ],
[ 1, 2 ]
]);
console.log(deduped); // [ {a: 1}, [1, 2] ]
```
Because a hash table in javascript is simply an `Object`, the keys
will always be of the type `String`. This means that normally we can't
distinguish between strings and numbers of the same value, i.e. `1` and
`'1'`.
Debido a una tabla hash en javascript es simplemente un `Object`, las claves
siempre será del tipo `string`. Esto significa que normalmente no podemos
distinguir entre cadenas y números del mismo valor, es decir `1` y
`'1'`.
```javascript
var hashTable = {};
hashTable[1] = true;
hashTable['1'] = true;
console.log(hashTable); // { '1': true }
```
Sin embargo, debido a que estamos utilizando [`JSON.stringify`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify), key que son del tipo `String`, se almacena como un valor de cadena escapada, que nos da única key en nuestra `hashTable`.
```javascript
var hashTable = {};
hashTable[JSON.stringify(1)] = true;
hashTable[JSON.stringify('1')] = true;
console.log(hashTable); // { '1': true, '\'1\'': true }
```
Esto significa elementos duplicados del mismo valor, pero de un tipo diferente,
aún serán deduplicables utilizando la misma aplicación.
```javascript
var deduped = dedup([
{ a: 1 },
{ a: 1 },
[ 1, 2 ],
[ 1, 2 ],
1,
1,
'1',
'1'
]);
console.log(deduped); // [ {a: 1}, [1, 2], 1, '1' ]
```
# Recursos
## Metodos
* [`filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)
* [`indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)
* [`from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
* [`JSON.stringify`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify)
## ES2015
* [arrow functions](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
* [Sets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)
## Stack overflow
* [remove duplicates from array](http://stackoverflow.com/questions/9229645/remove-duplicates-from-javascript-array/9229821#9229821)
================================================
FILE: _posts/es_ES/javascript/2016-02-07-flattening-multidimensional-arrays-in-javascript.md
================================================
---
layout: post
title: Arrays multidimensionales en JavaScript
tip-number: 38
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: Tres soluciones diferentes para combinar arrays multidimensional en un sola arrays.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /es_es/flattening-multidimensional-arrays-in-javascript/
categories:
- es_ES
- javascript
---
Estas son las tres formas conocidas para fusionar arrays multidimensional en una sola arrays.
Dado el array:
```js
var myArray = [[1, 2],[3, 4, 5], [6, 7, 8, 9]];
```
Queremos tener este resultado:
```js
[1, 2, 3, 4, 5, 6, 7, 8, 9]
```
### Solucion 1: usando [`concat()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) y [`apply()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)
```js
var myNewArray = [].concat.apply([], myArray);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
```
### Solucion 2: usando [`reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Flatten_an_array_of_arrays)
```js
var myNewArray = myArray.reduce(function(prev, curr) {
return prev.concat(curr);
});
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
```
### Solucion 3:
```js
var myNewArray3 = [];
for (var i = 0; i < myArray.length; ++i) {
for (var j = 0; j < myArray[i].length; ++j)
myNewArray3.push(myArray[i][j]);
}
console.log(myNewArray3);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
```
Echar un vistazo [here](https://jsbin.com/qeqicu/edit?js,console) estos 3 algoritmos en accion.
Para array infinitamente anidado probar Underscore [flatten()](https://github.com/jashkenas/underscore/blob/master/underscore.js#L501).
Si tiene curiosidad por la performance, [here](http://jsperf.com/flatten-an-array-loop-vs-reduce/6).
================================================
FILE: _posts/es_ES/javascript/2016-02-08-advanced-properties.md
================================================
---
layout: post
title: Propiedades avanzadas de Javascript
tip-number: 39
tip-username: mallowigi
tip-username-profile: https://github.com/mallowigi
tip-tldr: Cómo añadir propiedades privadas, getters y setters de objetos.
redirect_from:
- /es_es/advanced-properties/
categories:
- es_ES
- javascript
---
Es posible configurar las propiedades del objeto en Javascript, por ejemplo, para establecer las propiedades de ser pseudo-privada o de sólo lectura. Esta característica está disponible desde ECMAScript 5.1, por lo tanto, es soportado por todos los navegadores recientes.
Para ello, es necesario utilizar el método `defineProperty` del `Object` prototype de este modo:
```js
var a = {};
Object.defineProperty(a, 'readonly', {
value: 15,
writable: false
});
a.readonly = 20;
console.log(a.readonly); // 15
```
La sintaxis es la siguiente:
```js
Object.defineProperty(dest, propName, options)
```
o para múltiples definiciones:
```js
Object.defineProperties(dest, {
propA: optionsA,
propB: optionsB, //...
})
```
donde las opciones incluyen los siguientes atributos:
- *value*: si la propiedad no es una getter (ver abajo), value es un atributo obligatorio. `{a: 12}` === `Object.defineProperty(obj, 'a', {value: 12})`
- *writable*: establecer la propiedad como readonly. Tenga en cuenta que si la propiedad está en objetos anidados, sus propiedades siguen siendo editable.
- *enumerable*: establecer la propiedad como ocultos. Eso significa que bucles `for ... of` y `stringify` no incluirá el establecimiento con su resultado, pero la propiedad sigue ahí. Nota: Esto no significa que la propiedad es privada! Todavía puede ser accesible desde el exterior, sólo significa que no será impreso.
- *configurable*: establecer la propiedad como no modificable, por ejemplo, protegidos de la supresión o redefinición. Una vez más, si la propiedad es un objeto anidado, sus propiedades siguen siendo configurable.
Así que con el fin de crear una propiedad privada constante, se puede definir así:
```js
Object.defineProperty(obj, 'myPrivateProp', {value: val, enumerable: false, writable: false, configurable: false});
```
Además de la configuración de propiedades, `defineProperty` nos permite definir *propiedades dinámicas*, gracias al segundo parámetro que es una cadena. Por ejemplo, digamos que quiero crear propiedades de acuerdo con alguna configuración externa:
```js
var obj = {
getTypeFromExternal(): true // illegal in ES5.1
}
Object.defineProperty(obj, getTypeFromExternal(), {value: true}); // ok
// For the example sake, ES6 introduced a new syntax:
var obj = {
[getTypeFromExternal()]: true
}
```
¡Pero eso no es todo! propiedades avanzadas nos permite crear **getters** y **setters**, al igual que otros lenguajes de programación orientada a objetos! En ese caso, no se puede utilizar `writable`, `enumerable` y `configurable`, pero en su lugar:
```js
function Foobar () {
var _foo; // true private property
Object.defineProperty(obj, 'foo', {
get: function () { return _foo; }
set: function (value) { _foo = value }
});
}
var foobar = new Foobar();
foobar.foo; // 15
foobar.foo = 20; // _foo = 20
```
Aparte de la ventaja obvia de encapsulación y metodos de acceso avanzados, se dará cuenta de que no teníamos "call" de getter, en cambio, sólo la propiedad "get" sin paréntesis! ¡Esto es increíble! Por ejemplo, imaginemos que tenemos un objeto con propiedades anidadas largas, así:
```js
var obj = {a: {b: {c: [{d: 10}, {d: 20}] } } };
```
Ahora, en lugar de hacer `a.b.c[0].d` (donde una de las propiedades se pueden resolver como `undefined` y lanzar un error), que en su lugar puede crear un alias:
```js
Object.defineProperty(obj, 'firstD', {
get: function () { return a && a.b && a.b.c && a.b.c[0] && a.b.c[0].d }
})
console.log(obj.firstD) // 10
```
### Nota
Si se define un getter sin un setter y todavía intenta establecer un valor, obtendrá un error! Esto es particularmente importante cuando se utilizan funciones auxiliares tales como `$.extend` o `_.merge`. ¡Ten cuidado!
### Links
- [defineProperty](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
- [Defining properties in JavaScript](http://bdadam.com/blog/defining-properties-in-javascript.html)
================================================
FILE: _posts/es_ES/javascript/2016-02-09-using-json-stringify.md
================================================
---
layout: post
title: Usando JSON.Stringify
tip-number: 40
tip-username: vamshisuram
tip-username-profile: https://github.com/vamshisuram
tip-tldr: Crear un string seleccionando propiedades de un objeto JSON.
redirect_from:
- /es_es/using-json-stringify/
categories:
- es_ES
- javascript
---
Digamos que hay un objeto con propiedades"prop1", "prop2", "prop3".
Podemos pasarle __patrametro adicional__ a __JSON.stringify__ a escribir propiedades selectiva del objeto a cadena como:
```javascript
var obj = {
'prop1': 'value1',
'prop2': 'value2',
'prop3': 'value3'
};
var selectedProperties = ['prop1', 'prop2'];
var str = JSON.stringify(obj, selectedProperties);
// str
// {"prop1":"value1","prop2":"value2"}
```
__"str"__ sólo contendrá información sobre propiedades seleccionadas.
En lugar de un array podemos pasar una función también.
```javascript
function selectedProperties(key, val) {
// the first val will be the entire object, key is empty string
if (!key) {
return val;
}
if (key === 'prop1' || key === 'prop2') {
return val;
}
return;
}
```
The last optional param it takes is to modify the way it writes the object to string.
El último parámetro opcional se necesita si quiere modificar la forma en que se escribe el objeto de cadena.
```javascript
var str = JSON.stringify(obj, selectedProperties, '\t\t');
/* str output with double tabs in every line.
{
"prop1": "value1",
"prop2": "value2"
}
*/
```
================================================
FILE: _posts/es_ES/javascript/2016-02-10-array-average-and-median.md
================================================
---
layout: post
title: Array media y promedio.
tip-number: 41
tip-username: soyuka
tip-username-profile: https://github.com/soyuka
tip-tldr: Calcula la media y el promedio de los valores de la matriz
redirect_from:
- /es_es/array-average-and-median/
categories:
- es_ES
- javascript
---
Los siguientes ejemplos se basan en el siguiente array:
```javascript
let values = [2, 56, 3, 41, 0, 4, 100, 23];
```
Para obtener el promedio, tenemos que resumir los números y luego dividir por el número de valores. Los pasos son los siguientes:
- obtener la longitud del array
- sumar los valores
- obtener el promedio (`suma/length`)
```javascript
let values = [2, 56, 3, 41, 0, 4, 100, 23];
let sum = values.reduce((previous, current) => current += previous);
let avg = sum / values.length;
// avg = 28
```
O bien:
```javascript
let values = [2, 56, 3, 41, 0, 4, 100, 23];
let count = values.length;
values = values.reduce((previous, current) => current += previous);
values /= count;
// avg = 28
```
Ahora, para obtener media los pasos son los siguientes:
- ordenar el array
- obtener la media aritmética de los valores medios
```javascript
let values = [2, 56, 3, 41, 0, 4, 100, 23];
values.sort((a, b) => a - b);
let lowMiddle = Math.floor((values.length - 1) / 2);
let highMiddle = Math.ceil((values.length - 1) / 2);
let median = (values[lowMiddle] + values[highMiddle]) / 2;
// median = 13,5
```
Con un operador de bits:
```javascript
let values = [2, 56, 3, 41, 0, 4, 100, 23];
values.sort((a, b) => a - b);
let median = (values[(values.length - 1) >> 1] + values[values.length >> 1]) / 2
// median = 13,5
```
================================================
FILE: _posts/es_ES/javascript/2016-02-11-preventing-unapply-attacks.md
================================================
---
layout: post
title: La prevención de ataques de cancelar la aplicación
tip-number: 42
tip-username: emars
tip-username-profile: https://twitter.com/marseltov
tip-tldr: Congelar la construcción en los prototypes.
redirect_from:
- /es_es/preventing-unapply-attacks/
categories:
- es_ES
- javascript
---
Reemplazando el constructor de prototypes, código externo puede ocasionar que el código roto sea reescribiendo código para exponer y cambiar los argumentos ligados. Esto puede ser un problema serio que rompe las aplicaciones que funciona mediante el uso de métodos polyfill ES5.
```js
// example bind polyfill
function bind(fn) {
var prev = Array.prototype.slice.call(arguments, 1);
return function bound() {
var curr = Array.prototype.slice.call(arguments, 0);
var args = Array.prototype.concat.apply(prev, curr);
return fn.apply(null, args);
};
}
// unapply-attack
function unapplyAttack() {
var concat = Array.prototype.concat;
Array.prototype.concat = function replaceAll() {
Array.prototype.concat = concat; // restore the correct version
var curr = Array.prototype.slice.call(arguments, 0);
var result = concat.apply([], curr);
return result;
};
}
```
La función anterior descarta el array `prev` desde el enlace que significa que cualquier `.concat`, la primera llamada concat siguiente utilizando el ataque cancelar la aplicación generará un error.
Usando [Object.freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze), haciendo un objeto inmutable, se impide que cualquier sobreescritura de los objetos prototype.
```js
(function freezePrototypes() {
if (typeof Object.freeze !== 'function') {
throw new Error('Missing Object.freeze');
}
Object.freeze(Object.prototype);
Object.freeze(Array.prototype);
Object.freeze(Function.prototype);
}());
```
Puede leer mas [here](https://glebbahmutov.com/blog/unapply-attack/).
Aunque este concepto se llama 'ataque de cancelar la aplicación' debido a algún código de poder acceder a los closures que normalmente no estarían en su scope, es sobre todo un error considerar esto una característica de seguridad, debido a que no impedir que un atacante la ejecución de código con el que se extiende desde prototipos antes de la congelación ocurre, y también sigue teniendo el potencial para leer todos los scopes que utilizan diversas características del lenguaje. ECMA módulos darían aislamiento, que es mucho más fuerte que esta solución sin embargo sigue sin solucionar los problemas de los scripts de terceros.
================================================
FILE: _posts/es_ES/javascript/2016-02-12-use-destructuring-in-function-parameters.md
================================================
---
layout: post
title: Utilice la desestructuración de los parámetros de función
tip-number: 43
tip-username: dislick
tip-username-profile: https://github.com/dislick
tip-tldr: ¿Sabías que se puede utilizar una funcion de desestructuración de parametro parámetros?
redirect_from:
- /es_es/use-destructuring-in-function-parameters/
categories:
- es_ES
- javascript
---
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?
```javascript
var sayHello = function({ name, surname }) {
console.log(`Hello ${name} ${surname}! How are you?`);
};
sayHello({
name: 'John',
surname: 'Smith'
});
```
Esto es grande para las funciones que aceptan un objeto de opciones.
> 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.
================================================
FILE: _posts/es_ES/javascript/2016-02-13-know-the-passing-mechanism.md
================================================
---
layout: post
title: Conocer el mecanismo de paso
tip-number: 44
tip-username: bmkmanoj
tip-username-profile: https://github.com/bmkmanoj
tip-tldr: JavaScript solamente pasa por valor para ambos tipos primitiva y objeto (o referencia). En el caso de referencia el valor de referencia en sí se pasa por valor.
redirect_from:
- /es_es/calculate-the-max-min-value-from-an-array/
categories:
- es_ES
- javascript
---
JavaScript es pass-by-value, técnicamente. No es ni pass-by-value, ni pass-by-reference, pasando por el verdadero sentido de estos términos. Para entender este mecanismo de paso, echar un vistazo a los siguientes dos fragmentos de código de ejemplo y las explicaciones.
### Ejemplo 1
```js
var me = { // 1
'partOf' : 'A Team'
};
function myTeam(me) { // 2
me = { // 3
'belongsTo' : 'A Group'
};
}
myTeam(me);
console.log(me); // 4 : {'partOf' : 'A Team'}
```
En el ejemplo anterior, cuando `myTeam` se invoca, JavaScript es *pasar la referencia a* `me` *objeto como valor, ya que es un objeto* y la invocación de sí mismo crea dos referencias independientes para el mismo objeto, (aunque el nombre siendo el mismo aquí `me`, es engañosa y nos da la impresión de que es el único de referencia) y por lo tanto, la variable de referencia a sí mismos son independientes.
Cuando asignamos un nuevo objeto en la posición #`3`, estamos cambiando el valor de referencia en su totalidad dentro de la función `myTeam`, y no va a tener ningún impacto en el objeto original fuera de este scope de la función, desde donde fue aprobada y la referencia en el scope exterior se va a conservar el objeto original y por lo tanto la salida de `# 4'.
### Ejemplo 2
```js
var me = { // 1
'partOf' : 'A Team'
};
function myGroup(me) { // 2
me.partOf = 'A Group'; // 3
}
myGroup(me);
console.log(me); // 4 : {'partOf' : 'A Group'}
```
En el caso de invocar `myGroup`, estamos pasando el objeto `me`. Pero a diferencia del escenario de ejemplo 1, nosotros no estamos asignando esta variable `me` a cualquier nuevo objeto, lo que significa efectivamente el valor de referencia de objeto dentro del scope de la funcion `myGroup` todavía es el valor de referencia del objeto original y cuando estamos modificando la propiedad dentro de este scope, que está modificando de manera efectiva la propiedad del objeto original. Por lo tanto, se obtiene la salida de #`7`.
Lo mismo ocurre si esto no prueba que Javascript es pass-by-reference? No, no lo es. Recuerde, *JavaScript pasa la referencia como valor, en el caso de objetos*. La confusión surge ya que se tiende a no entender completamente lo que pase por referencia. Esta es la razón exacta, algunos prefieren llamar a esto como *Call-by-sharing*.
*Publicacion del autor [js-by-examples](https://github.com/bmkmanoj/js-by-examples/blob/master/examples/js_pass_by_value_or_reference.md)*
================================================
FILE: _posts/es_ES/javascript/2016-02-14-calculate-the-max-min-value-from-an-array.md
================================================
---
layout: post
title: Calcular el valor Max/Min de un array
tip-number: 45
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: Formas de utilizar las funciones Math.max() y Math.min() con array de números
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /es_es/detect-document-ready-in-pure-js/
categories:
- es_ES
- javascript
---
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.
```js
Math.max(1, 2, 3, 4); // 4
Math.min(1, 2, 3, 4); // 1
```
Estas funciones no funcionarán como tal con arrays de números. Sin embargo, hay algunas maneras de evitar esto.
[`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.
```js
var numbers = [1, 2, 3, 4];
Math.max.apply(null, numbers) // 4
Math.min.apply(null, numbers) // 1
```
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.
Una manera sencilla con ES2015 de conseguir esto [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator).
```js
var numbers = [1, 2, 3, 4];
Math.max(...numbers) // 4
Math.min(...numbers) // 1
```
Este operador hace que los valores del array a ser ampliado, o "spread", dentro de argumentos de la función.
================================================
FILE: _posts/es_ES/javascript/2016-02-15-detect-document-ready-in-pure-js.md
================================================
---
layout: post
title: Detectar cuando DOM esta listo en JS puro
tip-number: 46
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: La forma cross-browser para comprobar si el DOM se ha cargado en JavaScript puro.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /es_es/basics-declarations/
categories:
- es_ES
- javascript
---
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).
```js
if (document.readyState === 'complete') {
// The page is fully loaded
}
```
Como detectar cuando el document esta listo...
```js
let stateCheck = setInterval(() => {
if (document.readyState === 'complete') {
clearInterval(stateCheck);
// document ready
}
}, 100);
```
o con [onreadystatechange](https://developer.mozilla.org/en-US/docs/Web/Events/readystatechange)...
```js
document.onreadystatechange = () => {
if (document.readyState === 'complete') {
// document ready
}
};
```
Use `document.readyState === 'interactive'` para detectar cuando el DOM esta listo.
================================================
FILE: _posts/es_ES/javascript/2016-02-16-basics-declarations.md
================================================
---
layout: post
title: Declaraciones basicas
tip-number: 47
tip-username: adaniloff
tip-username-profile: https://github.com/adaniloff
tip-tldr: Entender y trabajar con declaraciones.
redirect_from:
- /es_es/basics-declarations/
categories:
- es_ES
- javascript
---
A continuación, las diferentes formas de declarar las variables en JavaScript.
Comentarios y console.log debería ser suficiente para explicar lo que está pasando aquí:
```js
var y, x = y = 1 //== var x; var y; x = y = 1
console.log('--> 1:', `x = ${x}, y = ${y}`)
// Will print
//--> 1: x = 1, y = 1
```
En primer lugar, apenas fijamos dos variables. No hay mucho aquí.
```js
;(() => {
var x = y = 2 // == var x; x = y = 2;
console.log('2.0:', `x = ${x}, y = ${y}`)
})()
console.log('--> 2.1:', `x = ${x}, y = ${y}`)
// Will print
//2.0: x = 2, y = 2
//--> 2.1: x = 1, y = 2
```
Como se puede ver, el código sólo ha cambiado la 'y' global, ya que no hemos declarado la variable en el closure.
```js
;(() => {
var x, y = 3 // == var x; var y = 3;
console.log('3.0:', `x = ${x}, y = ${y}`)
})()
console.log('--> 3.1:', `x = ${x}, y = ${y}`)
// Will print
//3.0: x = undefined, y = 3
//--> 3.1: x = 1, y = 2
```
Ahora declaramos dos variables a través var. Lo que significa que sólo viven en el contexto del closure.
```js
;(() => {
var y, x = y = 4 // == var x; var y; x = y = 4
console.log('4.0:', `x = ${x}, y = ${y}`)
})()
console.log('--> 4.1:', `x = ${x}, y = ${y}`)
// Will print
//4.0: x = 4, y = 4
//--> 4.1: x = 1, y = 2
```
Ambas variables han sido declaradas utilizando var y sólo después de que han puesto sus valores. Como local > global, x e y son locales en el closure, es decir, el global x e y no se tocaron.
```js
x = 5 // == x = 5
console.log('--> 5:', `x = ${x}, y = ${y}`)
// Will print
//--> 5: x = 5, y = 2
```
Esta última línea es explícito por sí mismo.
Puede probar esto y ver el resultado [thanks to babel](https://babeljs.io/repl/#?experimental=false&evaluate=true&loose=false&spec=false&code=var%20y%2C%20x%20%3D%20y%20%3D%201%20%2F%2F%3D%3D%20var%20x%3B%20var%20y%3B%20x%20%3D%20y%20%3D%201%0Aconsole.log('--%3E%201%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%0A%2F%2F%20Will%20print%0A%2F%2F--%3E%201%3A%20x%20%3D%201%2C%20y%20%3D%201%0A%0A%3B(()%20%3D%3E%20%7B%20%0A%20%20var%20x%20%3D%20y%20%3D%202%20%2F%2F%20%3D%3D%20var%20x%3B%20y%20%3D%202%3B%0A%20%20console.log('2.0%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%7D)()%0Aconsole.log('--%3E%202.1%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%0A%2F%2F%20Will%20print%0A%2F%2F2.0%3A%20x%20%3D%202%2C%20y%20%3D%202%0A%2F%2F--%3E%202.1%3A%20x%20%3D%201%2C%20y%20%3D%202%0A%0A%3B(()%20%3D%3E%20%7B%20%0A%20%20var%20x%2C%20y%20%3D%203%20%2F%2F%20%3D%3D%20var%20x%3B%20var%20y%20%3D%203%3B%0A%20%20console.log('3.0%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%7D)()%0Aconsole.log('--%3E%203.1%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%0A%2F%2F%20Will%20print%0A%2F%2F3.0%3A%20x%20%3D%20undefined%2C%20y%20%3D%203%0A%2F%2F--%3E%203.1%3A%20x%20%3D%201%2C%20y%20%3D%202%0A%0A%3B(()%20%3D%3E%20%7B%20%0A%20%20var%20y%2C%20x%20%3D%20y%20%3D%204%20%2F%2F%20%3D%3D%20var%20x%3B%20var%20y%3B%20x%20%3D%20y%20%3D%203%0A%20%20console.log('4.0%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%7D)()%0Aconsole.log('--%3E%204.1%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%0A%2F%2F%20Will%20print%0A%2F%2F4.0%3A%20x%20%3D%204%2C%20y%20%3D%204%0A%2F%2F--%3E%204.1%3A%20x%20%3D%201%2C%20y%20%3D%202%0A%0Ax%20%3D%205%20%2F%2F%20%3D%3D%20x%20%3D%205%0Aconsole.log('--%3E%205%3A'%2C%20%60x%20%3D%20%24%7Bx%7D%2C%20y%20%3D%20%24%7By%7D%60)%0A%0A%2F%2F%20Will%20print%0A%2F%2F--%3E%205%3A%20x%20%3D%205%2C%20y%20%3D%202).
Mas información disponible en [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var).
Agradecimientos especiales @kurtextrem por su colaboracion :)!
================================================
FILE: _posts/es_ES/javascript/2016-02-17-reminders-about-reduce-function-usage.md
================================================
---
layout: post
title: Reducir el uso de la función incorporada
tip-number: 48
tip-username: darul75
tip-username-profile: https://twitter.com/darul75
tip-tldr: Algunos recordatorios sobre cómo usar la función de reducir
redirect_from:
- /es_es/reminders-about-reduce-function-usage/
categories:
- es_ES
- javascript
---
Como está escrito en la documentación del método `reduce()` aplica una función contra un acumulador y cada valor del array (de izquierda a derecha) para reducirla a un solo valor.
### `reduce()`
[reduce()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) la funcion acepta 2 parametros (M: mandatory, O: optional):
- (M) la callback **reducer function** para ser aplicada se ocupa de un par de anterior (el resultado de cálculo anterior) y el próximo elemento hasta el final de la lista.
- (O) un **initial value** para ser utilizado como el primer argumento de la primera llamada de la callback.
Así que vamos a ver un uso común y luego una más sofisticada.
### Uso común (acumulacion, concatenacion)
Estamos en el sitio web de Amazon (precios en $) y nuestro carrito esta completo, vamos a calcular el total.
```javascript
// my current amazon caddy purchases
var items = [{price: 10}, {price: 120}, {price: 1000}];
// our reducer function
var reducer = function add(sumSoFar, nextPrice) { return sumSoFar + nextPrice.price; };
// do the job
var total = items.reduce(reducer, 0);
console.log(total); // 1130
```
Reducir el parámetro de la función opcional era entero primitivo de tipo 0 en el primer caso, pero podría haber sido un objeto, un Array... en lugar de un tipo primitivo,
pero vamos a ver esto más adelante.
Ahora, recibí un cupón de descuento de $20.
```javascript
var total = items.reduce(reducer,-20);
console.log(total); // 1110
```
### Uso avanzado (combinacion)
Este segundo ejemplo de sintaxis se inspira en Redux [combineReducers](http://redux.js.org/docs/api/combineReducers.html) function [source](https://github.com/reactjs/redux/blob/master/src/combineReducers.js#L93).
La idea separar la función de reducer por detras en funciones individuales separadas y al final calcular una nueva *función reductor grande sola*.
Para ilustrar esto, vamos a crear un único objeto literal con algunas funciones reductoras capaz de calcular los precios totales en moneda distinta $, € ...
```javascript
var reducers = {
totalInDollar: function(state, item) {
state.dollars += item.price;
return state;
},
totalInEuros : function(state, item) {
state.euros += item.price * 0.897424392;
return state;
},
totalInPounds : function(state, item) {
state.pounds += item.price * 0.692688671;
return state;
},
totalInYen : function(state, item) {
state.yens += item.price * 113.852;
return state;
}
// more...
};
```
Luego, creamos una nueva función navaja suiza
- Responsable de la aplicación de la funcion reduce en cada parial.
- Que devolverá una nueva callback de funcion reductor
```javascript
var combineTotalPriceReducers = function(reducers) {
return function(state, item) {
return Object.keys(reducers).reduce(
function(nextState, key) {
reducers[key](state, item);
return state;
},
{}
);
}
};
```
Ahora vamos a ver cómo usarla.
```javascript
var bigTotalPriceReducer = combineTotalPriceReducers(reducers);
var initialState = {dollars: 0, euros:0, yens: 0, pounds: 0};
var totals = items.reduce(bigTotalPriceReducer, initialState);
console.log(totals);
/*
Object {dollars: 1130, euros: 1015.11531904, yens: 127524.24, pounds: 785.81131152}
*/
```
Espero que este approach le puede dar otra idea de la utilización de la función reduce() para sus propias necesidades.
Su función reduce podía manejar un historial de cada cálculo por ejemplo, como se hace en Ramda Js [scan](http://ramdajs.com/docs/#scan)
[JSFiddle to play with](https://jsfiddle.net/darul75/81tgt0cd/)
================================================
FILE: _posts/es_ES/javascript/2016-02-26-extract-unix-timestamp-easily.md
================================================
---
layout: post
title: La manera más fácil de extraer marca de tiempo Unix en JS
tip-number: 49
tip-username: nmrony
tip-username-profile: https://github.com/nmrony
tip-tldr: En Javascript se puede conseguir fácilmente la marca de tiempo Unix
redirect_from:
- /es_es/extract-unix-timestamp-easily/
categories:
- es_ES
- javascript
---
Con frecuencia tenemos que calcular con marca de tiempo unix. Hay varias maneras de agarrar la marca de tiempo. La forma mas rapida y facil es
```js
const dateTime = Date.now();
const timestamp = Math.floor(dateTime / 1000);
```
or
```js
const dateTime = new Date().getTime();
const timestamp = Math.floor(dateTime / 1000);
```
Para conseguir marca de tiempo unix de una fecha específica pasar `YYYY-MM-DD` o `YYYY-MM-DDT00:00:00Z` como parámetro del constructor `Date`. Por ejemplo
```js
const dateTime = new Date('2012-06-08').getTime();
const timestamp = Math.floor(dateTime / 1000);
```
Usted puede añadir un signo `+` también cuando se declara un objeto `Date`, como a continuación
```js
const dateTime = +new Date();
const timestamp = Math.floor(dateTime / 1000);
```
o para una fecha especifica
```js
const dateTime = +new Date('2012-06-08');
const timestamp = Math.floor(dateTime / 1000);
```
Bajo el capó la ejecucion de llamadas del metodo `valueOf` del objeto `Date`. A continuación, el unario `+` operador llama `toNumber()` con ese valor devuelto. Para una explicación más detallada, consultar los siguientes enlaces
* [Date.prototype.valueOf](http://es5.github.io/#x15.9.5.8)
* [Unary + operator](http://es5.github.io/#x11.4.6)
* [toNumber()](http://es5.github.io/#x9.3)
* [Date Javascript MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)
* [Date.parse()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse)
================================================
FILE: _posts/es_ES/javascript/2016-03-03-helpful-console-log-hacks.md
================================================
---
layout: post
title: Utiles trucos para Console Logging
tip-number: 50
tip-username: zackhall
tip-username-profile: https://twitter.com/zthall
tip-tldr: Utiles técnicas utilizando breakpoints de coacción y condicionales.
redirect_from:
- /es_es/helpful-console-log-hacks/
categories:
- es_ES
- javascript
---
## Usando breakpoints condicionales
Si usted quiere observar un valor por consola cada vez que una función se llama, puede utilizar puntos de breakpoints condicionales para hacer esto. Abran sus herramientas dev, encontrar la función que desea registrar datos en la consola y un breakpoints con la siguiente condición:
```js
console.log(data.value) && false
```
Un breakpoint condicional detiene el hilo página sólo si la condición se evalúa como verdadera. Así que mediante el uso de console.log('foo') && false está garantizado que dan como resultado false, ya que está poniendo el falso literal en la condición AND. Así que esto no va a hacer una pausa cuando es evaluado, pero va a registrar datos en la consola. Esto también se puede utilizar para contar cuántas veces se llama una función o una callback.
He aquí cómo se puede establecer un punto de interrupción condicional en [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") y [Safari](https://developer.apple.com/library/mac/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/Debugger/Debugger.html "Managing Breakpoints in Safari").
## Impresión de una variable a la consola
¿Alguna vez ha entrado una variable en la consola y no fueron capaces de simplemente ver el código de la función? La forma más rápida para ver el código de la función es la de coaccionar a una cadena mediante la concatenación con una cadena vacía.
```js
console.log(funcVariable + '');
```
================================================
FILE: _posts/es_ES/javascript/2016-03-16-DOM-event-listening-made-easy.md
================================================
---
layout: post
title: Escuchar eventos DOM mas simple
tip-number: 51
tip-username: octopitus
tip-username-profile: https://github.com/octopitus
tip-tldr: Una forma elegante y fácil de manejar eventos DOM
redirect_from:
- /es_es/DOM-event-listening-made-easy/
categories:
- es_ES
- javascript
---
Muchos de nosotros todavía están haciendo estas cosas:
- `element.addEventListener('type', obj.method.bind(obj))`
- `element.addEventListener('type', function (event) {})`
- `element.addEventListener('type', (event) => {})`
Los ejemplos anteriores, crean nuevos controladores de eventos anónimos que no pueden ser retirados cuando ya no sean necesarios. Esto puede causar problemas de rendimiento o errores lógicos inesperados, cuando los controladores que ya no es necesario puden ser accidentalmente activado mediante interacciones del usuario inesperados o [event bubbling](http://www.javascripter.net/faq/eventbubbling.htm)
Patrones de gestión de eventos más seguras son las siguientes:
Utilice una referencia:
```js
const handler = function () {
console.log("Tada!")
}
element.addEventListener("click", handler)
// Later on
element.removeEventListener("click", handler)
```
Función llamada que remueve a sí mismo:
```js
element.addEventListener('click', function click(e) {
if (someCondition) {
return e.currentTarget.removeEventListener('click', click);
}
});
```
Un mejor enfoque:
```js
function handleEvent (eventName, {onElement, withCallback, useCapture = false} = {}, thisArg) {
const element = onElement || document.documentElement
function handler (event) {
if (typeof withCallback === 'function') {
withCallback.call(thisArg, event)
}
}
handler.destroy = function () {
return element.removeEventListener(eventName, handler, useCapture)
}
element.addEventListener(eventName, handler, useCapture)
return handler
}
// Anytime you need
const handleClick = handleEvent('click', {
onElement: element,
withCallback: (event) => {
console.log('Tada!')
}
})
// And anytime you want to remove it
handleClick.destroy()
```
================================================
FILE: _posts/es_ES/javascript/2016-04-05-return-values-with-the-new-operator.md
================================================
---
layout: post
title: Retorno de valores con el operador 'new'
tip-number: 52
tip-username: Morklympious
tip-username-profile: https://github.com/morklympious
tip-tldr: Comprender lo que se devuelve cuando el uso de new vs. sin usar new.
redirect_from:
- /es_es/get-file-extension/
categories:
- es_ES
- javascript
---
Usted va a correr dentro de algunas instancias en las que va a utilizar `new` para asignar nuevos objetos en JavaScript. Se va a volar tu mente a menos que lea este consejo para entender lo que está sucediendo por detrás.
El operador `new` en JavaScript es un operador que, en circunstancias razonables, devuelve una nueva instancia de un objeto. Digamos que tenemos una función constructora:
````js
function Thing() {
this.one = 1;
this.two = 2;
}
var myThing = new Thing();
myThing.one // 1
myThing.two // 2
````
__Nota__: `This` se refiere al nuevo objeto creado por `new`. De lo contrario, si `Thing()` se llama sin `new`, __objeto no creado__, y `this` va a apuntar al objeto global, que es `window`. Esto significa que:
1. Usted repentinamente tiene dos nuevas variables globales con nombre `one` y 'two`.
2. `myThing` ahora es undefined, ya que no devuelve nada en `Thing()`.
Ahora que se obtiene ese ejemplo, aquí es donde las cosas se ponen un poco torcidas. Digamos que quiero añadir algo a la función constructora, un poco de sabor:
````js
function Thing() {
this.one = 1;
this.two = 2;
return 5;
}
var myThing = new Thing();
````
Ahora, que hace myThing equal? Es 5? es un objeto? Es mi sentido lisiado de autoestima? El mundo nunca puede saber!
Excepto el mundo sabe:
````js
myThing.one // 1
myThing.two // 2
````
Curiosamente, nunca realmente vemos los cinco que supuestamente 'retorna' de nuestro constructor. Eso es raro, ¿verdad? ¿Qué hace la función? ¿Dónde está el cinco? Vamos a probar con otra cosa.
Vamos a retornar un tipo no primitivo, algo así como un objeto.
````js
function Thing() {
this.one = 1;
this.two = 2;
return {
three: 3,
four: 4
};
}
var myThing = new Thing();
````
Vamos a ver. Un console.log revela todo:
````js
console.log(myThing);
/*
Object {three: 3, four: 4}
What happened to this.one and this.two!?
They've been stomped, my friend.
*/
````
__Aquí es donde aprendemos:__ Cuando se llama a una función con la palabra clave `new`, puede setear propiedades en el uso de la palabra clave `this` (pero probablemente ya lo sabía). La devolución de un valor simple de una función que llamó a la palabra clave `new` no devolverá el valor que ha especificado, pero en su lugar devolverá la instancia `this` de la función (el que se introdujo en propiedades, como `this.one = 1;`).
Sin embargo, el retorno de un no-primitivo, como un `object`,` array`, o `function` será pisar fuerte en la instancia `this`, y volver ese no primitivo en su lugar, arruinando todo el duro trabajo que hizo todo lo posible para asignar `this`.
================================================
FILE: _posts/es_ES/javascript/2016-04-21-get-file-extension.md
================================================
---
layout: post
title: Obtener extensión de archivo
tip-number: 53
tip-username: richzw
tip-username-profile: https://github.com/richzw
tip-tldr: ¿Cómo conseguir la extensión del archivo de manera más eficiente?
redirect_from:
- /es_es/get-file-extension/
categories:
- es_ES
- javascript
---
### Pregunta: ¿Cómo conseguir la extensión de archivo?
```javascript
var file1 = "50.xsl";
var file2 = "30.doc";
getFileExtension(file1); //returs xsl
getFileExtension(file2); //returs doc
function getFileExtension(filename) {
/*TODO*/
}
```
### Solucion 1: Expresion regular
```js
function getFileExtension1(filename) {
return (/[.]/.exec(filename)) ? /[^.]+$/.exec(filename)[0] : undefined;
}
```
### Solucion 2: Metodo `split`
```js
function getFileExtension2(filename) {
return filename.split('.').pop();
}
```
Estas dos soluciones no podían manejar algunos casos extremos, aquí hay otra solución más robusta.
### Solucion 3: Metodos `slice`, `lastIndexOf`
```js
function getFileExtension3(filename) {
return filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2);
}
console.log(getFileExtension3('')); // ''
console.log(getFileExtension3('filename')); // ''
console.log(getFileExtension3('filename.txt')); // 'txt'
console.log(getFileExtension3('.hiddenfile')); // ''
console.log(getFileExtension3('filename.with.many.dots.ext')); // 'ext'
```
_¿Como funciona?_
- [String.lastIndexOf()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf) el método devuelve la última aparición del valor especificado (`'.'` en este caso). Devuelve `-1` si no se encuentra el valor.
- Los valores de retorno de `lastIndexOf` para el parámetro `'filename'` y `'.hiddenfile'` son `0` y `-1` respectivamente.[Zero-fill operador de desplazamiento a la derecha (>>>)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#%3E%3E%3E_%28Zero-fill_right_shift%29) transformará `-1` a `4294967295` y `-2` a `4294967294`, aquí es un truco para asegurar el nombre del archivo sin cambios en esos casos extremos.
- [String.prototype.slice()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice) extrae la extensión del índice que se calculó anteriormente. Si el índice es mayor que la longitud del nombre de archivo, el resultado es `""`.
### Comparación
| Solucion | Parametros | Resultados |
| ----------------------------------------- |:-------------------:|:--------:|
| Solucion 1: Expresion regular | '' 'filename' 'filename.txt' '.hiddenfile' 'filename.with.many.dots.ext' | undefined undefined 'txt' 'hiddenfile' 'ext' |
| Solucion 2: Metodo `split` | '' 'filename' 'filename.txt' '.hiddenfile' 'filename.with.many.dots.ext' | '' 'filename' 'txt' 'hiddenfile' 'ext' |
| Solucion 3: Metodos `slice`, `lastIndexOf` | '' 'filename' 'filename.txt' '.hiddenfile' 'filename.with.many.dots.ext' | '' '' 'txt' '' 'ext' |
### Demo de performance
[Here](https://jsbin.com/tipofu/edit?js,console) es la demostración de los códigos anteriores.
[Here](http://jsperf.com/extract-file-extension) es la prueba de rendimiento de esos 3 soluciones.
### Codigo
[How can I get file extensions with JavaScript](http://stackoverflow.com/questions/190852/how-can-i-get-file-extensions-with-javascript)
================================================
FILE: _posts/es_ES/javascript/2016-05-06-use-optional-arguments.md
================================================
---
layout: post
title: Cómo utilizar argumentos opcionales en funciones (con callback opcional)
tip-number: 54
tip-username: alphashuro
tip-username-profile: https://github.com/alphashuro
tip-tldr: Usted puede hacer argumentos de función y callback opcional
redirect_from:
- /es_es/use-optional-arguments/
categories:
- es_ES
- javascript
---
Ejemplo de función donde los argumentos 2 y 3 son opcionales
```javascript
function example( err, optionalA, optionalB, callback ) {
// recuperar los argumentos como array
var args = new Array(arguments.length);
for(var i = 0; i < args.length; ++i) {
args[i] = arguments[i];
};
// Primer argumento es el objeto de error
// shift() elimina el primer elemento del
// array y lo devuelve
err = args.shift();
// Si el último argumento es una función entonces es la funcion callback.
// pop() elimina el último elemento del array
// y lo devuelve
if (typeof args[args.length-1] === 'function') {
callback = args.pop();
}
// Si args aún mantiene elementos, estos son
// sus elementos opcionales que se podía
// recuperar uno por uno como este:
if (args.length > 0) optionalA = args.shift(); else optionalA = null;
if (args.length > 0) optionalB = args.shift(); else optionalB = null;
// continuar como de costumbre: comprobar si hay errores
if (err) {
return callback && callback(err);
}
// para los propósitos de tutoría, ingrese los parámetros opcionales
console.log('optionalA:', optionalA);
console.log('optionalB:', optionalB);
console.log('callback:', callback);
/* haz tus cosas */
}
// ES6 con código más corto
function example(...args) {
// primer argumento es el objeto de error
const err = args.shift();
// si el último argumento es una función entonces es la funcion callback.
const callback = (typeof args[args.length-1] === 'function') ? args.pop() : null;
// args si todavía tiene elementos, estos son los elementos opcionales que se podía recuperar de uno en uno como este:
const optionalA = (args.length > 0) ? args.shift() : null;
const optionalB = (args.length > 0) ? args.shift() : null;
// ... repetir para mas items
if (err && callback) return callback(err);
/* haz tus cosas */
}
// invocar la función de ejemplo con y sin argumentos opcionales
example(null, 'AA');
example(null, function (err) { /* do something */ });
example(null, 'AA', function (err) {});
example(null, 'AAAA', 'BBBB', function (err) {});
```
### ¿Cómo se determina si optionalA o optionalB se destina?
El diseño de su función para requerir optionalA con el fin de aceptar optionalB
================================================
FILE: _posts/es_ES/javascript/2016-05-12-make-easy-loop-on-array.md
================================================
---
layout: post
title: Crear un bucle fácil usando un array
tip-number: 55
tip-username: jamet-julien
tip-username-profile: https://github.com/jamet-julien
tip-tldr: A veces, necesitamos un ciclo sin fin sobre un array de items, como un carrusel de imágenes o un lista de reproducción de audio. Así es como tomar un array y darle "bucle poderosos"
redirect_from:
- /es_es/make-easy-loop-on-array/
categories:
- es_ES
- javascript
---
A veces, necesitamos un ciclo sin fin sobre un array de items, como un carrusel de imágenes o un lista de reproducción de audio. Así es como tomar un array y darle "bucle poderosos"
```js
var aList = ['A','B','C','D','E'];
function make_looper( arr ){
arr.loop_idx = 0;
// return current item
arr.current = function(){
if( this.loop_idx < 0 ){// First verification
this.loop_idx = this.length - 1;// update loop_idx
}
if( this.loop_idx >= this.length ){// second verification
this.loop_idx = 0;// update loop_idx
}
return arr[ this.loop_idx ];//return item
};
// increment loop_idx AND return new current
arr.next = function(){
this.loop_idx++;
return this.current();
};
// decrement loop_idx AND return new current
arr.prev = function(){
this.loop_idx--;
return this.current();
};
}
make_looper( aList);
aList.current();// -> A
aList.next();// -> B
aList.next();// -> C
aList.next();// -> D
aList.next();// -> E
aList.next();// -> A
aList.pop() ;// -> E
aList.prev();// -> D
aList.prev();// -> C
aList.prev();// -> B
aList.prev();// -> A
aList.prev();// -> D
```
Utilizando el operador ```%``` (módulo) es más vistoso. El modulo retorna el resto de la division ( ``` 2 % 5 = 1``` y ``` 5 % 5 = 0```):
```js
var aList = ['A','B','C','D','E'];
function make_looper( arr ){
arr.loop_idx = 0;
// return current item
arr.current = function(){
this.loop_idx = ( this.loop_idx ) % this.length;// no verification !!
return arr[ this.loop_idx ];
};
// increment loop_idx AND return new current
arr.next = function(){
this.loop_idx++;
return this.current();
};
// decrement loop_idx AND return new current
arr.prev = function(){
this.loop_idx += this.length - 1;
return this.current();
};
}
make_looper( aList);
aList.current();// -> A
aList.next();// -> B
aList.next();// -> C
aList.next();// -> D
aList.next();// -> E
aList.next();// -> A
aList.pop() ;// -> E
aList.prev();// -> D
aList.prev();// -> C
aList.prev();// -> B
aList.prev();// -> A
aList.prev();// -> D
```
================================================
FILE: _posts/es_ES/react/2016-01-02-keys-in-children-components-are-important.md
================================================
---
layout: post
title: Keys en componentes secundarios son importantes
tip-number: 02
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: La key es un atributo que se debe pasar a todos los componentes creados dinámicamente a partir de un array. Es un identificador único y constante que React usa para identificar cada componente en el DOM y saber si se trata de un componente diferente o el mismo. Utilizando keys asegura que el componente secundario se conserve y no se cree nuevamente y evita que cosas extrañas sucedan.
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /es_es/keys-in-children-components-are-important/
categories:
- es_ES
- react
---
La [key](https://facebook.github.io/react/docs/multiple-components.html#dynamic-children) es un atributo que se debe pasar a todos los componentes creados dinámicamente a partir de un array. Es un identificador único y constante que React usa para identificar cada componente en el DOM y saber si se trata de un componente diferente o el mismo. Utilizando keys asegura que el componente secundario se conserve y no se cree nuevamente y evita que cosas extrañas sucedan.
> La key no es realmente sobre el rendimiento, es más acerca de la identidad (que a su vez conduce a un mejor rendimiento). Aleatoriamente asignados y los valores cambiantes no forman una identidad [Paul O’Shannessy](https://github.com/facebook/react/issues/1342#issuecomment-39230939)
- Utilice un valor único existente del objeto.
- Definir las keys de los componentes padre, no en los componentes secundarios
```javascript
//bad
...
render() {
{% raw %}{{item.name}}{% endraw %}
}
...
//good
```
- [Usar el indice de un array es una mala practica.](https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318#.76co046o9)
- `random()` no funcionara.
```javascript
//bad
```
- Usted puede crear su propia única id. Asegúrese de que el método es rápido y adjuntarlo a su objeto.
- Cuando el número de children es grande o contiene componentes caros, utilice keys para mejorar el rendimiento.
- [Debe proporcionar el atributo clave para todos los children de ReactCSSTransitionGroup.](http://docs.reactjs-china.com/react/docs/animation.html)
================================================
FILE: _posts/zh_CN/angular/2016-01-01-angularjs-digest-vs-apply.md
================================================
---
layout: post
title: AngularJs - $digest vs $apply
tip-number: 01
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: JavaScript模块和构建步骤越来越复杂和多样化,但是新框架里的样板是什么样子的呢?
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /zh_cn/angularjs-digest-vs-apply/
categories:
- zh_CN
- angular
---
AngularJs最令人欣赏的特性之一就是双向数据绑定。AngularJs通过循环(`$digest`)检查model和view的变化实现此功能。想要理解框架底层的运行机制你需要理解这个概念。
当一个事件被触发时,Angular触发每个watcher. 这是我们已知的`$digest`循环。有时你需要强制手动运行一个新的循环,而且因为这是最影响性能的一方面,你必须选择一个正确的选项。
### `$apply`
这个核心方法可以让你显式启动`digest`循环。这意味着所有的watcher将会被检测;整个应用启动`$digest loop`。在内部在会执行一个可选的方法之后,会调用`$rootScope.$digest();`.
### `$digest`
这种情况下`$digest`方法在当前作用域和它的子作用域启动`$digest`循环。你需要注意他的父作用域将不会被检测也不会被影响。
### 推荐
- 仅当浏览器DOM事件在AngularJS之外被触发时使用`$apply`或`$digest`。
- 给`$apply`传递方法,它将包含错误处理机制而且允许整合在`digest`循环里的变化。
```javascript
$scope.$apply(() => {
$scope.tip = 'Javascript Tip';
});
```
- 如果你只需要更新当前的作用域或者它的子作用域的话,使用`$digest`,而且要防止在整个应用里运行新的`digest`循环。这在性能上的好处是显而易见的。
- `$apply()`对机器来说是一个困难的处理过程,在绑定过多的时候可能会引发性能问题。
- 如果你正使用`>AngularJS 1.2.X`版本,使用`$evalAsync`, 这个方法将在当前循环或下一个循环执行表达式,这能提高你的应用的性能。
================================================
FILE: _posts/zh_CN/javascript/2015-12-29-insert-item-inside-an-array.md
================================================
---
layout: post
title: 向数组中插入元素
tip-number: 00
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: 向一个数组中插入元素是平时很常见的一件事情。你可以使用push在数组尾部插入元素,可以用unshift在数组头部插入元素,也可以用splice在数组中间插入元素。
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /zh_cn/insert-item-inside-an-array/
categories:
- zh_CN
- javascript
---
# 向一个数组中插入元素
向一个数组中插入元素是平时很常见的一件事情。你可以使用push在数组尾部插入元素,可以用unshift在数组头部插入元素,也可以用splice在数组中间插入元素。
但是这些已知的方法,并不意味着没有更加高效的方法。让我们接着往下看……
## 向数组结尾添加元素
向数组结尾添加元素用push()很简单,但下面有一个更高效的方法
```javascript
var arr = [1,2,3,4,5];
var arr2 = [];
arr.push(6);
arr[arr.length] = 6;
arr2 = arr.concat([6]);
```
两种方法都是修改原始数组。不信?看看[jsperf](http://jsperf.com/push-item-inside-an-array)
### 手机上的效率
#### Android (v4.2.2)
1. _arr.push(6);_ and _arr[arr.length] = 6;_ 性能相同 // 3 319 694 ops/sec
3. _arr2 = arr.concat([6]);_ 比其他两个方法慢50.61%
#### Chrome Mobile (v33.0.0)
1. _arr[arr.length] = 6;_ // 6 125 975 ops/sec
2. _arr.push(6);_ 慢66.74%
3. _arr2 = arr.concat([6]);_ 慢87.63%
#### Safari Mobile (v9)
1. _arr[arr.length] = 6;_ // 7 452 898 ops/sec
2. _arr.push(6);_ 慢40.19%
3. _arr2 = arr.concat([6]);_ 慢49.78%
```javascript
最快的为
1. arr[arr.length] = 6; // 平均 5 632 856 ops/sec
2. arr.push(6); // 慢35.64%
3. arr2 = arr.concat([6]); // 慢62.67%
```
### 桌面上的效率
#### Chrome (v48.0.2564)
1. _arr[arr.length] = 6;_ // 21 602 722 ops/sec
2. _arr.push(6);_ 慢61.94%
3. _arr2 = arr.concat([6]);_ 慢87.45%
#### Firefox (v44)
1. _arr.push(6);_ // 56 032 805 ops/sec
2. _arr[arr.length] = 6;_ 慢0.52%
3. _arr2 = arr.concat([6]);_ 慢87.36%
#### IE (v11)
1. _arr[arr.length] = 6;_ // 67 197 046 ops/sec
2. _arr.push(6);_ 慢39.61%
3. _arr2 = arr.concat([6]);_ 慢93.41%
#### Opera (v35.0.2066.68)
1. _arr[arr.length] = 6;_ // 30 775 071 ops/sec
2. _arr.push(6);_ 慢71.60%
3. _arr2 = arr.concat([6]);_ 慢83.70%
#### Safari (v9.0.3)
1. _arr.push(6);_ // 42 670 978 ops/sec
2. _arr[arr.length] = 6;_ 慢0.80%
3. _arr2 = arr.concat([6]);_ 慢76.07%
```javascript
最快的为
1. arr[arr.length] = 6; // 平均42 345 449 ops/sec
2. arr.push(6); // 慢34.66%
3. arr2 = arr.concat([6]); // 慢85.79%
```
## 向数组的头部添加元素
现在我们试着向数组的头部添加元素:
```javascript
var arr = [1,2,3,4,5];
arr.unshift(0);
[0].concat(arr);
```
这里有一些小区别,unshift操作的是原始数组,concat返回一个新数组,参考[jsperf](http://jsperf.com/unshift-item-inside-an-array)
### 手机上的效率 :
#### Android (v4.2.2)
1. _[0].concat(arr);_ // 1 808 717 ops/sec
2. _arr.unshift(0);_ 慢97.85%
#### Chrome Mobile (v33.0.0)
1. _[0].concat(arr);_ // 1 269 498 ops/sec
2. _arr.unshift(0);_ 慢99.86%
#### Safari Mobile (v9)
1. _arr.unshift(0);_ // 3 250 184 ops/sec
2. _[0].concat(arr);_ 慢33.67%
```javascript
最快的为
1. [0].concat(arr); // 平均4 972 622 ops/sec
2. arr.unshift(0); // 慢64.70%
```
### 桌面上的效率
#### Chrome (v48.0.2564)
1. _[0].concat(arr);_ // 2 656 685 ops/sec
2. _arr.unshift(0);_ 慢96.77%
#### Firefox (v44)
1. _[0].concat(arr);_ // 8 039 759 ops/sec
2. _arr.unshift(0);_ 慢99.72%
#### IE (v11)
1. _[0].concat(arr);_ // 3 604 226 ops/sec
2. _arr.unshift(0);_ 慢98.31%
#### Opera (v35.0.2066.68)
1. _[0].concat(arr);_ // 4 102 128 ops/sec
2. _arr.unshift(0);_ 慢97.44%
#### Safari (v9.0.3)
1. _arr.unshift(0);_ // 12 356 477 ops/sec
2. _[0].concat(arr);_ 慢15.17%
```javascript
最快的为
1. [0].concat(arr); // 平均6 032 573 ops/sec
2. arr.unshift(0); // 慢78.65%
```
## 向数组中间添加元素
使用splice可以简单的向数组中间添加元素,这也是最高效的方法。
```javascript
var items = ['one', 'two', 'three', 'four'];
items.splice(items.length / 2, 0, 'hello');
```
我在许多浏览器和系统中进行了测试,结果都是相似的。希望这条小知识可以帮到你,也欢迎大家自行测试。
================================================
FILE: _posts/zh_CN/javascript/2016-01-03-improve-nested-conditionals.md
================================================
---
layout: post
title: 优化嵌套的条件语句
tip-number: 03
tip-username: AlbertoFuente
tip-username-profile: https://github.com/AlbertoFuente
tip-tldr: 我们怎样来提高和优化javascript里嵌套的`if`语句呢?
redirect_from:
- /zh_cn/improve-nested-conditionals/
categories:
- zh_CN
- javascript
---
我们怎样来提高和优化javascript里嵌套的`if`语句呢?
```javascript
if (color) {
if (color === 'black') {
printBlackBackground();
} else if (color === 'red') {
printRedBackground();
} else if (color === 'blue') {
printBlueBackground();
} else if (color === 'green') {
printGreenBackground();
} else {
printYellowBackground();
}
}
```
一种方法来提高嵌套的`if`语句是用`switch`语句。虽然它不那么啰嗦而且排列整齐,但是并不建议使用它,因为这对于调试错误很困难。这告诉你[为什么](https://toddmotto.com/deprecating-the-switch-statement-for-object-literals).
```javascript
switch(color) {
case 'black':
printBlackBackground();
break;
case 'red':
printRedBackground();
break;
case 'blue':
printBlueBackground();
break;
case 'green':
printGreenBackground();
break;
default:
printYellowBackground();
}
```
如果可以重构的话,我们可以试着简化函数。比如不需要为每个颜色写一个函数,而是将颜色作为函数的参数。
```javascript
function printBackground(color) {
if (!color || typeof color !== 'string') {
return; // Invalid color, return immediately
}
}
```
但是如果不能重构的话,我们必须避免过多的条件检查,避免过多使用`switch`。我们必须考虑最有效率的方法,使用`object`。
```javascript
switch(true) {
case (typeof color === 'string' && color === 'black'):
printBlackBackground();
break;
case (typeof color === 'string' && color === 'red'):
printRedBackground();
break;
case (typeof color === 'string' && color === 'blue'):
printBlueBackground();
break;
case (typeof color === 'string' && color === 'green'):
printGreenBackground();
break;
case (typeof color === 'string' && color === 'yellow'):
printYellowBackground();
break;
}
```
但是我们应该时刻注意避免太多判断在一个条件里,尽量少的使用`switch`,考虑最有效率的方法:借助`object`。
```javascript
var colorObj = {
'black': printBlackBackground,
'red': printRedBackground,
'blue': printBlueBackground,
'green': printGreenBackground,
'yellow': printYellowBackground
};
if (color in colorObj) {
colorObj[color]();
}
```
这里有更多相关的[内容](http://www.nicoespeon.com/en/2015/01/oop-revisited-switch-in-js/).
================================================
FILE: _posts/zh_CN/javascript/2016-01-04-sorting-strings-with-accented-characters.md
================================================
---
layout: post
title: 排列含音节字母的字符串
tip-number: 04
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: Javascript有一个原生方法**sort**可以排列数组。一次简单的`array.sort()`将每一个数组元素视为字符串并按照字母表排列。但是当你试图整理一个非ASCII元素的数组时,你可能会得到一个奇怪的结果。
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /zh_cn/sorting-strings-with-accented-characters/
categories:
- zh_CN
- javascript
---
Javascript有一个原生方法**[sort](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)**可以排列数组。一次简单的`array.sort()`将每一个数组元素视为字符串并按照字母表排列。你也可以提供[自定义排列方法](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Parameters)。
```javascript
['Shanghai', 'New York', 'Mumbai', 'Buenos Aires'].sort();
// ["Buenos Aires", "Mumbai", "New York", "Shanghai"]
```
但是当你试图整理一个如`['é', 'a', 'ú', 'c']`这样的非ASCII元素的数组时,你可能会得到一个奇怪的结果`['c', 'e', 'á', 'ú']`。这是因为排序方法只在英文下有用。
看一下下一个例子:
```javascript
// 西班牙语
['único','árbol', 'cosas', 'fútbol'].sort();
// ["cosas", "fútbol", "árbol", "único"] // bad order
// 德语
['Woche', 'wöchentlich', 'wäre', 'Wann'].sort();
// ["Wann", "Woche", "wäre", "wöchentlich"] // bad order
```
幸运的是,有两种方法可以解决这个问题,由ECMAScript国际化API提供的[localeCompare](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare)和[Intl.Collator](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Collator)。
> 两个方法都有自定义配置参数可以使其更好用。
### 使用`localeCompare()`
```javascript
['único','árbol', 'cosas', 'fútbol'].sort(function (a, b) {
return a.localeCompare(b);
});
// ["árbol", "cosas", "fútbol", "único"]
['Woche', 'wöchentlich', 'wäre', 'Wann'].sort(function (a, b) {
return a.localeCompare(b);
});
// ["Wann", "wäre", "Woche", "wöchentlich"]
```
### 使用`Intl.Collator()`
```javascript
['único','árbol', 'cosas', 'fútbol'].sort(Intl.Collator().compare);
// ["árbol", "cosas", "fútbol", "único"]
['Woche', 'wöchentlich', 'wäre', 'Wann'].sort(Intl.Collator().compare);
// ["Wann", "wäre", "Woche", "wöchentlich"]
```
- 两个方法都可以自定义区域位置。
- 根据[Firefox](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare#Performance),当比较大数量的字符串时,使用`Intl.Collator`更快。
所以当你处理一个由非英语组成的字符串数组时,记得使用此方法来避免排序出现意外。
================================================
FILE: _posts/zh_CN/javascript/2016-01-05-differences-between-undefined-and-null.md
================================================
---
layout: post
title: undefined与null的区别
tip-number: 05
tip-username: loverajoel
tip-username-profile: https://github.com/loverajoel
tip-tldr: 理解`undefined`与`null`的区别。
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /zh_cn/differences-between-undefined-and-null/
categories:
- zh_CN
- javascript
---
- `undefined`表示一个变量没有被声明,或者被声明了但没有被赋值
- `null`是一个表示“没有值”的值
- Javascript将未赋值的变量默认值设为`undefined`
- Javascript从来不会将变量设为`null`。它是用来让程序员表明某个用`var`声明的变量时没有值的。
- `undefined`不是一个有效的JSON,而`null`是
- `undefined`的类型(typeof)是`undefined`
- `null`的类型(typeof)是`object`. [为什么?](http://www.2ality.com/2013/10/typeof-null.html)
- 它们都是基本类型
- 他们都是[falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy)
(`Boolean(undefined) // false`, `Boolean(null) // false`)
- 你可以这样判断一个变量是否是[undefined](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/undefined)
```javascript
typeof variable === "undefined"
```
- 你可以这样判断一个变量是否是[null](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/null)
```javascript
variable === null
```
- **双等号**比较时它们相等,但**三等号**比较时不相等
```javascript
null == undefined // true
null === undefined // false
```
================================================
FILE: _posts/zh_CN/javascript/2016-01-06-writing-a-single-method-for-arrays-and-a-single-element.md
================================================
---
layout: post
title: 可以接受单参数与数组的方法
tip-number: 06
tip-username: mattfxyz
tip-username-profile: https://twitter.com/mattfxyz
tip-tldr: 写一个方法可以接受单个参数也可以接受一个数组,而不是分开写两个方法。这和jQuery的一些方法的工作原理很像(`css` 可以修改任何匹配到的选择器).
redirect_from:
- /zh_cn/writing-a-single-method-for-arrays-and-a-single-element/
categories:
- zh_CN
- javascript
---
写一个方法可以接受单个参数也可以接受一个数组,而不是分开写两个方法。这和jQuery的一些方法的工作原理很像(`css` 可以修改任何匹配到的选择器).
你只要把任何东西连接到一个数组. `Array.concat`可以接受一个数组也可以接受单个参数。
```javascript
function printUpperCase(words) {
var elements = [].concat(words || []);
for (var i = 0; i < elements.length; i++) {
console.log(elements[i].toUpperCase());
}
}
```
`printUpperCase`现在可以接受单个单词或多个单词的数组作为它的参数。同时也可以避免在不传递参数时抛出的`TypeError`错误的隐患。
```javascript
printUpperCase("cactus");
// => CACTUS
printUpperCase(["cactus", "bear", "potato"]);
// => CACTUS
// BEAR
// POTATO
```
================================================
FILE: _posts/zh_CN/javascript/2016-01-07-use-strict-and-get-lazy.md
================================================
---
layout: post
title: 使用"use strict" 变得懒惰
tip-number: 07
tip-username: nainslie
tip-username-profile: https://twitter.com/nat5an
tip-tldr: JavaScript的严格模式使开发者更容易写出“安全”的代码。
redirect_from:
- /zh_cn/use-strict-and-get-lazy/
categories:
- zh_CN
- javascript
---
(译者注:此片翻译较渣,欢迎指正,建议大家[阅读原文](http://www.jstips.co/en/use-strict-and-get-lazy/)或直接阅读[MDN对严格模式的中文介绍](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode) 并欢迎PR)
JavaScript的严格模式使开发者更容易写出“安全”的代码。
通常情况下,JavaScript允许程序员相当粗心,比如你可以引用一个从未用"var"声明的变量。或许对于一个刚入门的开发者来说这看起来很方便,但这也是变量拼写错误或者从作用域外引用变量时引发的一系列错误的原因。
程序员喜欢电脑帮我们做一些无聊的工作,喜欢它自动的检查我们工作上的错误。这就是"use strict"帮我们做的,它把我们的错误转变为了JavaScript错误。
我们把这个指令放在js文件顶端来使用它:
```javascript
// 全脚本严格模式
"use strict";
var v = "Hi! I'm a strict mode script!";
```
或者放在一个方法内:
```javascript
function f()
{
// 方法级严格模式
'use strict';
function nested() { return "And so am I!"; }
return "Hi! I'm a strict mode function! " + nested();
}
function f2() { return "I'm not strict."; }
```
通过在JavaScript文件或方法内引入此指令,使JavaScript引擎运行在严格模式下,这直接禁止了许多大项目中不受欢迎的操作。另外,严格模式也改变了以下行为:
* 只有被"var"声明过的变量才可以引用
* 试图写只读变量时将会报错
* 只能通过"new"关键字调用构造方法
* "this"不再隐式的指向全局变量
* 对eval()有更严格的限制
* 防止你使用预保留关键字命名变量
严格模式对于新项目来说是很棒的,但对于一些并没有使用它的老项目来说,引入它也是很有挑战性的。如果你把所有js文件都连接到一个大文件中的话,可能导致所有文件都运行在严格模式下,这可能也会有一些问题。
它不是一个声明,而是一个表达式,被低版本的JavaScript忽略。
严格模式的支持情况:
* Internet Explorer 10+
* Firefox 4+
* Chrome 13+
* Safari 5.1+
* Opera 12+
[MDN对严格模式的全面介绍](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode)
================================================
FILE: _posts/zh_CN/javascript/2016-01-08-converting-a-node-list-to-an-array.md
================================================
---
layout: post
title: 将Node List转换为数组(Array)
tip-number: 08
tip-username: Tevko
tip-username-profile: https://twitter.com/tevko
tip-tldr: 这是一个快速、安全、可重用的方法将node list转换为DOM元素的数组。
redirect_from:
- /zh_cn/converting-a-node-list-to-an-array/
categories:
- zh_CN
- javascript
---
`querySelectorAll`方法返回一个类数组对象称为node list。这些数据结构被称为“类数组”,因为他们看似数组却没有类似`map`、`foreach`这样的数组方法。这是一个快速、安全、可重用的方法将node list转换为DOM元素的数组:
```javascript
const nodelist = document.querySelectorAll('div');
const nodelistToArray = Array.apply(null, nodelist);
//之后 ..
nodelistToArray.forEach(...);
nodelistToArray.map(...);
nodelistToArray.slice(...);
//等...
```
`apply`方法可以在指定`this`时以数组形式向方法传递参数。[MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)规定`apply`可以接受类数组对象,恰巧就是`querySelectorAll`方法所返回的内容。如果我们不需要指定方法内`this`的值时传`null`或`0`即可。返回的结果即包含所有数组方法的DOM元素数组。
另外你可以使用`Array.prototype.slice`结合`Function.prototype.call`或`Function.prototype.apply`, 将类数组对象当做`this`传入:
```javascript
const nodelist = document.querySelectorAll('div');
const nodelistToArray = Array.prototype.slice.call(nodelist); // or equivalently Array.prototype.slice.apply(nodelist);
//之后 ..
nodelistToArray.forEach(...);
nodelistToArray.map(...);
nodelistToArray.slice(...);
//等...
```
如果你正在用ES2015你可以使用[展开运算符 `...`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_operator)
```js
const nodelist = [...document.querySelectorAll('div')]; // 返回一个真正的数组
//之后 ..
nodelist.forEach(...);
nodelist.map(...);
nodelist.slice(...);
//等...
```
================================================
FILE: _posts/zh_CN/javascript/2016-01-09-template-strings.md
================================================
---
layout: post
title: 模板字符串
tip-number: 09
tip-username: JakeRawr
tip-username-profile: https://github.com/JakeRawr
tip-tldr: ES6中,JS现在有了引号拼接字符串的替代品,模板字符串。
redirect_from:
- /zh_cn/template-strings/
categories:
- zh_CN
- javascript
---
ES6中,JS现在有了引号拼接字符串的替代品,模板字符串。
示例:
普通字符串
```javascript
var firstName = 'Jake';
var lastName = 'Rawr';
console.log('My name is ' + firstName + ' ' + lastName);
// My name is Jake Rawr
```
模板字符串
```javascript
var firstName = 'Jake';
var lastName = 'Rawr';
console.log(`My name is ${firstName} ${lastName}`);
// My name is Jake Rawr
```
在模板字符串中,你可以不用`\n`来生成多行字符串,在`${}`里做简单的逻辑运算(例如 2+3)甚至使用[逻辑运算符](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Conditional_Operator)。
```javascript
var val1 = 1, val2 = 2;
console.log(`${val1} is ${val1 < val2 ? 'less than': 'greater than'} ${val2}`)
// 1 is less than 2
```
你也可以使用函数修改末班字符串的输出内容;这被称为[带标签的模板字符串](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/template_strings#带标签的模板字符串),其中包含了带标签的模板字符串的示例.
或许你还想[阅读更多内容](https://hacks.mozilla.org/2015/05/es6-in-depth-template-strings-2)来了解模板字符串。
================================================
FILE: _posts/zh_CN/javascript/2016-01-10-check-if-a-property-is-in-a-object.md
================================================
---
layout: post
title: 检查某对象是否有某属性
tip-number: 10
tip-username: loverajoel
tip-username-profile: https://www.twitter.com/loverajoel
tip-tldr: 这是一些检查某对象是否有某属性的方法。
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /zh_cn/check-if-a-property-is-in-a-object/
categories:
- zh_CN
- javascript
---
当你需要检查某属性是否存在于一个[对象](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Working_with_Objects),你可能会这样做:
```javascript
var myObject = {
name: '@tips_js'
};
if (myObject.name) { ... }
```
这是可以的,但是你需要知道有两种原生方法可以解决此类问题。[`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`的对象都可以使用这两种方法。
### 看一下较大的区别
```javascript
var myObject = {
name: '@tips_js'
};
myObject.hasOwnProperty('name'); // true
'name' in myObject; // true
myObject.hasOwnProperty('valueOf'); // false, valueOf 继承自原型链
'valueOf' in myObject; // true
```
两者检查属性的深度不同,换言之`hasOwnProperty`只在本身有此属性时返回true,而`in`操作符不区分属性来自于本身或继承自原型链。
这是另一个例子
```javascript
var myFunc = function() {
this.name = '@tips_js';
};
myFunc.prototype.age = '10 days';
var user = new myFunc();
user.hasOwnProperty('name'); // true
user.hasOwnProperty('age'); // false, 因为age来自于原型链
```
[在线示例](https://jsbin.com/tecoqa/edit?js,console)!
同样建议阅读关于检查对象是否包含属性时常见错误的[讨论](https://github.com/loverajoel/jstips/issues/62)。
================================================
FILE: _posts/zh_CN/javascript/2016-01-11-hoisting.md
================================================
---
layout: post
title: 变量提升
tip-number: 11
tip-username: squizzleflip
tip-username-profile: https://twitter.com/squizzleflip
tip-tldr: 理解变量提升有助于管理函数作用域
redirect_from:
- /zh_cn/hoisting/
categories:
- zh_CN
- javascript
---
理解[变量提升](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/var#var_hoisting)可以帮助你组织方法作用域。只要记住变量声明和方法声明都会被提升到顶部。变量的定义不会提升,即使你在同一行声明和定义一个变量。变量**声明**是让系统知道有这个变量存在而**定义**是给其赋值。
```javascript
function doTheThing() {
// ReferenceError: notDeclared is not defined
console.log(notDeclared);
// Outputs: undefined
console.log(definedLater);
var definedLater;
definedLater = 'I am defined!'
// Outputs: 'I am defined!'
console.log(definedLater)
// Outputs: undefined
console.log(definedSimulateneously);
var definedSimulateneously = 'I am defined!'
// Outputs: 'I am defined!'
console.log(definedSimulateneously)
// Outputs: 'I did it!'
doSomethingElse();
function doSomethingElse(){
console.log('I did it!');
}
// TypeError: undefined is not a function
functionVar();
var functionVar = function(){
console.log('I did it!');
}
}
```
为了让你的代码更易读,将所有的变量声明在函数的顶端,这样可以更清楚的知道变量来自哪个作用域。在使用变量之前声明变量。将方法定义在函数的底部。
================================================
FILE: _posts/zh_CN/javascript/2016-01-12-pseudomandatory-parameters-in-es6-functions.md
================================================
---
layout: post
title: ES6中的伪强制参数
tip-number: 12
tip-username: Avraam Mavridis
tip-username-profile: https://github.com/AvraamMavridis
tip-tldr: 在许多编程语言中,方法的参数时默认强制需要的,开发人员需要明确定义一个可选的参数。
redirect_from:
- /zh_cn/tip-to-measure-performance-of-a-javascript-block/
categories:
- zh_CN
- javascript
---
在许多编程语言中,方法的参数是默认强制需要的,开发人员必须明确定义一个可选的参数。在Javascript 中每一个参数都是可选的,但是我们可以利用[**es6参数默认值**](http://exploringjs.com/es6/ch_parameter-handling.html#sec_parameter-default-values)特性的优点来达到强制要求这种目的,并且不污染函数体本身。
``` javascript
const _err = function( message ){
throw new Error( message );
}
const getSum = (a = _err('a is not defined'), b = _err('b is not defined')) => a + b
getSum( 10 ) // throws Error, b is not defined
getSum( undefined, 10 ) // throws Error, a is not defined
```
`_err` 是一个即时抛出错误的方法。如果参数中的任何一个没有值,参数默认的值将会被使用, `_err`方法将被调用,并且会抛出一个错误。你可以从[MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Default_parameters)看到更多关于**默认参数特性**的例子。
================================================
FILE: _posts/zh_CN/javascript/2016-01-13-tip-to-measure-performance-of-a-javascript-block.md
================================================
---
layout: post
title: 测量javascript代码块性能的小知识
tip-number: 13
tip-username: manmadareddy
tip-username-profile: https://twitter.com/manmadareddy
tip-tldr: 快速的测量javascript的性能,我们可以使用console的方法,例如 ```console.time(label)```和 ```console.timeEnd(label)```
redirect_from:
- /zh_cn/fat-arrow-functions/
categories:
- zh_CN
- javascript
---
快速的测量javascript的性能,我们可以使用console的方法,例如
[```console.time(label)```](https://developer.chrome.com/devtools/docs/console-api#consoletimelabel) 和 [```console.timeEnd(label)```](https://developer.chrome.com/devtools/docs/console-api#consoletimeendlabel)
```javascript
console.time("Array initialize");
var arr = new Array(100),
len = arr.length,
i;
for (i = 0; i < len; i++) {
arr[i] = new Object();
};
console.timeEnd("Array initialize"); // Outputs: Array initialize: 0.711ms
```
更多内容:
[Console object](https://github.com/DeveloperToolsWG/console-object),
[Javascript benchmarking](https://mathiasbynens.be/notes/javascript-benchmarking)
Demo: [jsfiddle](https://jsfiddle.net/meottb62/) - [codepen](http://codepen.io/anon/pen/JGJPoa) (在浏览器控制台输出)
> 注意:由于[Mozilla](https://developer.mozilla.org/zh-CN/docs/Web/API/Console/time)不建议将其使用在线上项目中,建议仅在开发中使用。
================================================
FILE: _posts/zh_CN/javascript/2016-01-14-fat-arrow-functions.md
================================================
---
layout: post
title: 箭头函数
tip-number: 14
tip-username: pklinger
tip-username-profile: https://github.com/pklinger/
tip-tldr: 介绍一个ES6的新特性,箭头函数或许一个让你用更少行写更多代码的方便工具。
redirect_from:
- /zh_cn/fat-arrow-functions/
categories:
- zh_CN
- javascript
---
介绍一个ES6的新特性,箭头函数或许一个让你用更少行写更多代码的方便工具。它的名字(fat arrow functions)来自于它的语法`=>`是一个比瘦箭头`->`要'胖的箭头'(译者注:但是国内貌似不分胖瘦就叫箭头函数)。Some programmers might already know this type of functions from different languages such as Haskell as 'lambda expressions' respectively 'anonymous functions'. It is called anonymous, as these arrow functions do not have a descriptive function name.(译者注:一些其他语言中的箭头函数,避免不准确就不翻译了 欢迎PR)
### 有什么益处呢?
* 语法: 更少的代码行; 不再需要一遍一遍的打`function`了
* 语义: 从上下文中捕获`this`关键字
### 简单的语法示例
观察一下这两个功能完全相同的代码片段。你将很快明白箭头函数做了什么。
```javascript
// 箭头函数的一般语法
param => expression
// 也可以用用小括号
// 多参数时小括号是必须的
(param1 [, param2]) => expression
// 使用functions
var arr = [5,3,2,9,1];
var arrFunc = arr.map(function(x) {
return x * x;
});
console.log(arr)
// 使用箭头函数
var arr = [5,3,2,9,1];
var arrFunc = arr.map((x) => x*x);
console.log(arr)
```
正如你所看到的,箭头函数在这种情况下省去了写小括号,function以及return的时间。我建议你总是使用小括号,因为对于像`(x,y) => x+y`这样多参数函数,小括号总是需要的。这仅是以防在不同使用场景下忘记小括号的一种方法。但是上面的代码和`x => x*x`是一样的。至此仅是语法上的提升,减少了代码行数并提高了可读性。
### Lexically binding `this`
这是另一个使用箭头函数的好原因。这是一个关于`this`上下文的问题。使用箭头函数,你不需要再担心`.bind(this)`也不用再设置`that = this`了,因为箭头函数继承了外围作用域的`this`值。看一下下面的[示例](https://jsfiddle.net/pklinger/rw94oc11/):
```javascript
// 全局定义 this.i
this.i = 100;
var counterA = new CounterA();
var counterB = new CounterB();
var counterC = new CounterC();
var counterD = new CounterD();
// 不好的例子
function CounterA() {
// CounterA的`this`实例 (!!调用时忽略了此实例)
this.i = 0;
setInterval(function () {
// `this` 指向全局(global)对象,而不是CounterA的`this`
// 所以从100开始计数,而不是0 (本地的this.i)
this.i++;
document.getElementById("counterA").innerHTML = this.i;
}, 500);
}
// 手动绑定 that = this
function CounterB() {
this.i = 0;
var that = this;
setInterval(function() {
that.i++;
document.getElementById("counterB").innerHTML = that.i;
}, 500);
}
// 使用 .bind(this)
function CounterC() {
this.i = 0;
setInterval(function() {
this.i++;
document.getElementById("counterC").innerHTML = this.i;
}.bind(this), 500);
}
// 箭头函数
function CounterD() {
this.i = 0;
setInterval(() => {
this.i++;
document.getElementById("counterD").innerHTML = this.i;
}, 500);
}
```
更多有关箭头函数的内容可以查看[MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions)。更多语法选项请看[这里](http://jsrocks.org/2014/10/arrow-functions-and-their-scope/).
================================================
FILE: _posts/zh_CN/javascript/2016-01-15-even-simpler-way-of-using-indexof-as-a-contains-clause.md
================================================
---
layout: post
title: 更简单的使用indexOf实现contains功能
tip-number: 15
tip-username: jhogoforbroke
tip-username-profile: https://twitter.com/jhogoforbroke
tip-tldr: JavaScript并未提供contains方法。检测子字符串是否存在于字符串或者变量是否存在于数组你可能会这样做。
redirect_from:
- /zh_cn/even-simpler-way-of-using-indexof-as-a-contains-clause/
categories:
- zh_CN
- javascript
---
JavaScript并未提供contains方法。检测子字符串是否存在于字符串或者变量是否存在于数组你可能会这样做:
```javascript
var someText = 'javascript rules';
if (someText.indexOf('javascript') !== -1) {
}
// or
if (someText.indexOf('javascript') >= 0) {
}
```
但是让我们看一下这些 [Expressjs](https://github.com/strongloop/express)代码段。
[examples/mvc/lib/boot.js](https://github.com/strongloop/express/blob/2f8ac6726fa20ab5b4a05c112c886752868ac8ce/examples/mvc/lib/boot.js#L26)
```javascript
for (var key in obj) {
// "reserved" exports
if (~['name', 'prefix', 'engine', 'before'].indexOf(key)) continue;
```
[lib/utils.js](https://github.com/strongloop/express/blob/2f8ac6726fa20ab5b4a05c112c886752868ac8ce/lib/utils.js#L93)
```javascript
exports.normalizeType = function(type){
return ~type.indexOf('/')
? acceptParams(type)
: { value: mime.lookup(type), params: {} };
};
```
[examples/web-service/index.js](https://github.com/strongloop/express/blob/2f8ac6726fa20ab5b4a05c112c886752868ac8ce/examples/web-service/index.js#L35)
```javascript
// key is invalid
if (!~apiKeys.indexOf(key)) return next(error(401, 'invalid api key'));
```
难点是 [位操作符](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) **~**, “按位操作符操作数字的二进制形式,但是返回值依然是标准的JavaScript数值。”
它将`-1`转换为`0`,而`0`在javascript为`false`,所以:
```javascript
var someText = 'text';
!!~someText.indexOf('tex'); // someText contains "tex" - true
!~someText.indexOf('tex'); // someText NOT contains "tex" - false
~someText.indexOf('asd'); // someText doesn't contain "asd" - false
~someText.indexOf('ext'); // someText contains "ext" - true
```
### String.prototype.includes()
在ES6中提供了[includes() 方法](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/includes)供我们判断一个字符串是否包含了另一个字符串:
```javascript
'something'.includes('thing'); // true
```
在ECMAScript 2016 (ES7)甚至可能将其应用于数组,像indexOf一样:
```javascript
!!~[1, 2, 3].indexOf(1); // true
[1, 2, 3].includes(1); // true
```
**不幸的是, 只有Chrome、Firefox、Safari 9及其更高版本和Edge支持了这功能。IE11及其更低版本并不支持**
**最好在受控的环境中使用此功能**
================================================
FILE: _posts/zh_CN/javascript/2016-01-16-passing-arguments-to-callback-functions.md
================================================
---
layout: post
title: 向回调方法传递参数
tip-number: 16
tip-username: minhazav
tip-username-profile: https://twitter.com/minhazav
tip-tldr: 通常下,你并不能给回调函数传递参数,但是你可以借助Javascript闭包的优势来传递参数给回调函数。
redirect_from:
- /zh_cn/passing-arguments-to-callback-functions/
categories:
- zh_CN
- javascript
---
通常下,你并不能给回调函数传递参数。 比如:
```js
function callback() {
console.log('Hi human');
}
document.getElementById('someelem').addEventListener('click', callback);
```
你可以借助Javascript闭包的优势来传递参数给回调函数。看这个例子:
```js
function callback(a, b) {
return function() {
console.log('sum = ', (a+b));
}
}
var x = 1, y = 2;
document.getElementById('someelem').addEventListener('click', callback(x, y));
```
**什么是闭包?**
闭包是指函数有自由独立的变量。换句话说,定义在闭包中的函数可以“记忆”它创建时候的环境。想了解更多请[参考MDN的文档](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures)。
这种方法使参数`x`和`y`在回调方法被调用时处于其作用域内。
另一个办法是使用`bind`方法。比如:
```js
var alertText = function(text) {
alert(text);
};
document.getElementById('someelem').addEventListener('click', alertText.bind(this, 'hello'));
```
两种方法之间有着微小的性能差异,请看[jsperf](http://jsperf.com/bind-vs-closure-23).
================================================
FILE: _posts/zh_CN/javascript/2016-01-17-nodejs-run-a-module-if-it-is-not-required.md
================================================
---
layout: post
title: Node.js - 运行未被引用的模块
tip-number: 17
tip-username: odsdq
tip-username-profile: https://twitter.com/odsdq
tip-tldr: 在Node里,你可以让你的程序根据其运行自`require('./something.js')`或者`node something.js`而做不同的处理。如果你想与你的一个独立的模块进行交互,这是非常有用的。
redirect_from:
- /zh_cn/nodejs-run-a-module-if-it-is-not-required/
categories:
- zh_CN
- javascript
---
在Node里,你可以让你的程序根据其运行自`require('./something.js')`或者`node something.js`而做不同的处理。如果你想与你的一个独立的模块进行交互,这是非常有用的。
```js
if (!module.parent) {
// 通过 `node something.js` 启动
app.listen(8088, function() {
console.log('app listening on port 8088');
})
} else {
// 通过 `require('/.something.js')` 被引用
module.exports = app;
}
```
更多内容请看 [modules的文档](https://nodejs.org/api/modules.html#modules_module_parent)
================================================
FILE: _posts/zh_CN/javascript/2016-01-18-rounding-the-fast-way.md
================================================
---
layout: post
title: 快速(但危险)的取整方法
tip-number: 18
tip-username: pklinger
tip-username-profile: https://github.com/pklinger
tip-tldr: 通常情况下`~~X`比`Math.trunc(X)`要快,但同时也会使你的代码做一些讨厌的事情。
redirect_from:
- /zh_cn/rounding-the-fast-way/
categories:
- zh_CN
- javascript
---
本条小知识关于性能...
你曾遇到过[双波浪线`~~`操作符](http://stackoverflow.com/questions/5971645/what-is-the-double-tilde-operator-in-javascript)吗?它也被称为“双按位非”操作符。你通常可以使用它作为代替`Math.trunc()`的更快的方法。为什么呢?
一个按位非操作符`~`首先将输入`input`截取为32位,然后将其转换为`-(input+1)`。因此双按位非操作符将输入转换为`-(-(input + 1)+1)`,使其成为一个趋向于0取整的好工具。对于数字的输入,它很像`Math.trunc()`。失败时返回`0`,这可能在解决`Math.trunc()`转换错误返回`NaN`时是一个很好的替代。
```js
// 单个 ~
console.log(~1337) // -1338
// 数字输入
console.log(~~47.11) // -> 47
console.log(~~1.9999) // -> 1
console.log(~~3) // -> 3
```
然而, 尽管`~~`可能有更好的性能,有经验的程序员通常坚持使用`Math.trunc()`。要明白为什么,这里有一个关于此操作符的冷静分析。
### 适用的情况
##### 当CPU资源很珍贵时
`~~`可能在各平台上都比`Math.trunc()`快,但是你应该在你所关心的所有平台上[测试这种猜想](https://jsperf.com/jsfvsbitnot/10)。同样,你通常需要执行数百万这样的操作来看看在运行时有没有明显的影响。
##### 当不需要关心代码清晰度时
如果你想迷惑其他人,或者想在`minifier/uglifier`时取得更大功效,这是一种相对廉价的方式。
### 禁用的情况
##### 当你的代码需要维护时
代码可读性始终是最重要的。无论你工作在一个团队,或是贡献给开源仓库,或是单飞。正如[名言所说](http://c2.com/cgi/wiki?CodeForTheMaintainer):
> Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live.(写代码时,要始终认为一个有暴力倾向并知道你住在哪里的人会最终维护你的代码。)
For a solo programmer, that psychopath is inevitably "you in six months".(这句不会翻译……)
##### 当你忘记`~~`永远趋向于0时
新手程序员或许更关注`~~`的聪明之处,却忘记了“只去掉小数部分”的意义。这在将浮点数转换为数组索引或关联有序的值时很容易导致**差一错误** ,这时明显需要一个不同的取整方法。 (代码可读性不高往往会导致此问题)
打个比方,如果你想得到离一个数“最近的整数”,你应该用`Math.round()`而不是`~~`,但是由于程序员的惰性和**_每次使用需要敲10个键_**的事实,人类的手指往往会战胜冷冷的逻辑,导致错误的结果。
相比之下,`Math.xyz()`(举例)函数的名字清楚的传达了它们的作用,减少了可能出现的意外的错误。
##### 当处理大数时
因为`~`首先将数组转换为32位,`~~`的结果伪值在 ±2.15*10^12左右。如果你没有明确的检查输入值的范围,当转换的值最终与原始值有很大差距时,用户就可能触发未知的行为:
```js
a = 2147483647.123 // 比32位最大正数,再多一点
console.log(~~a) // -> 2147483647 (ok)
a += 10000 // -> 2147493647.123 (ok)
console.log(~~a) // -> -2147483648 (huh?)
```
一个特别容易中招的地方是在处理Unix时间戳时(从1970年1月1日 00:00:00 UTC开始以秒测量)。一个快速获取的方法:
```js
epoch_int = ~~(+new Date() / 1000) // Date() 以毫秒计量,所以我们缩小它
```
然而,当处理2038年1月19日 03:14:07 UTC 之后的时间戳时(有时称为**Y2038 limit**), 可怕的事情发生了:
```js
// 2040年1月1日 00:00:00.123 UTC的时间戳
epoch = +new Date('2040-01-01') / 1000 + 0.123 // -> 2208988800.123
// 回到未来!
epoch_int = ~~epoch // -> -2085978496
console.log(new Date(epoch_int * 1000)) // -> Wed Nov 25 1903 17:31:44 UTC
// 这很搞笑,让我们来取得正确答案
epoch_flr = Math.floor(epoch) // -> 2208988800
console.log(new Date(epoch_flr * 1000)) // -> Sun Jan 01 2040 00:00:00 UTC
```
##### 当原始输入的数据类型不确定时
因为`~~`可以将任何非数字类型转换为`0`:
```js
console.log(~~[]) // -> 0
console.log(~~NaN) // -> 0
console.log(~~null) // -> 0
```
一些程序员将其看作适当输入验证的替代品。然而,这将导致奇怪的逻辑问题,因此你不能辨别违法输入还是真正的`0`。因此这_并不_推荐。
##### 当很多人认为`~~X == Math.floor(X)`时
很多人由于很多原因错误的把"双按位非"等同于`Math.floor()`。如果你不能准确地使用它,最终你很有可能会滥用它。
另一些人很细心的注意正数使用`Math.floor()`而负数使用`Math.ceil()`,但这又强制你在处理它的时候需要停下来想一想你处理的数是什么值。这又违背了使用`~~`快捷无陷阱的目的。
### 结论
尽量避免,并有节制的使用。
### 使用
1. 谨慎使用。
2. 在应用前检查值。
3. 仔细记录被转化值的相关假设。
4. 审查代码至少处理:
* 逻辑错误,不合法的输入作为合法的`0`传入其他代码模块
* 输入转换后范围错误
* 错误的舍入方向导致差一错误
================================================
FILE: _posts/zh_CN/javascript/2016-01-19-safe-string-concatenation.md
================================================
---
layout: post
title: 安全的字符串拼接
tip-number: 19
tip-username: gogainda
tip-username-profile: https://twitter.com/gogainda
tip-tldr: 假如你需要拼接一些不确定类型的变量为字符串,你需要确保算术运算符在你拼接时不会起作用。使用concat
redirect_from:
- /zh_cn/safe-string-concatenation/
categories:
- zh_CN
- javascript
---
假如你需要拼接一些不确定类型的变量为字符串,你需要确保算术运算符在你拼接时不会起作用。使用concat:
```javascript
var one = 1;
var two = 2;
var three = '3';
var result = ''.concat(one, two, three); //"123"
```
这应该就是你所期望的拼接结果。如果不这样,拼接时加号可能会导致你意想不到的结果:
```javascript
var one = 1;
var two = 2;
var three = '3';
var result = one + two + three; //"33" instead of "123"
```
关于性能,与用[```join```](http://www.sitepoint.com/javascript-fast-string-concatenation/)来拼接字符串相比 ```concat```的效率是几乎一样的。
你可以在[MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)了解更多关于```concat```方法的内容。
================================================
FILE: _posts/zh_CN/javascript/2016-01-20-return-objects-to-enable-chaining-of-functions.md
================================================
---
layout: post
title: 返回对象,使方法可以链式调用
tip-number: 20
tip-username: WakeskaterX
tip-username-profile: https://twitter.com/WakeStudio
tip-tldr: 在面向对象的Javascript中为对象建立一个方法时,返回当前对象可以让你在一条链上调用方法。
redirect_from:
- /zh_cn/return-objects-to-enable-chaining-of-functions/
categories:
- zh_CN
- javascript
---
在面向对象的Javascript中为对象建立一个方法时,返回当前对象可以让你在一条链上调用方法。
```js
function Person(name) {
this.name = name;
this.sayName = function() {
console.log("Hello my name is: ", this.name);
return this;
};
this.changeName = function(name) {
this.name = name;
return this;
};
}
var person = new Person("John");
person.sayName().changeName("Timmy").sayName();
```
================================================
FILE: _posts/zh_CN/javascript/2016-01-21-shuffle-an-array.md
================================================
---
layout: post
title: 对数组洗牌
tip-number: 21
tip-username: 0xmtn
tip-username-profile: https://github.com/0xmtn/
tip-tldr: Fisher-Yates Shuffling 算法对数组进行洗牌
redirect_from:
- /zh_cn/shuffle-an-array/
categories:
- zh_CN
- javascript
---
这段代码运用了[Fisher-Yates Shuffling](https://www.wikiwand.com/en/Fisher%E2%80%93Yates_shuffle)算法对数组进行洗牌。
```javascript
function shuffle(arr) {
var i,
j,
temp;
for (i = arr.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return arr;
};
```
调用示例:
```javascript
var a = [1, 2, 3, 4, 5, 6, 7, 8];
var b = shuffle(a);
console.log(b);
// [2, 7, 8, 6, 5, 3, 1, 4]
```
================================================
FILE: _posts/zh_CN/javascript/2016-01-22-two-ways-to-empty-an-array.md
================================================
---
layout: post
title: 清空数组的两种方法
tip-number: 22
tip-username: microlv
tip-username-profile: https://github.com/microlv
tip-tldr: 在JavaScript中清空一个数组有很多方法,但这是一个最高效的方法。
redirect_from:
- /zh_cn/two-ways-to-empty-an-array/
categories:
- zh_CN
- javascript
---
如果你定义了一个数组,然后你想清空它。
通常,你会这样做:
```javascript
// 定义一个数组
var list = [1, 2, 3, 4];
function empty() {
//清空数组
list = [];
}
empty();
```
但是,这有一个效率更高的方法来清空数组。
你可以这样写:
```javascript
var list = [1, 2, 3, 4];
function empty() {
//empty your array
list.length = 0;
}
empty();
```
* `list = []` 将一个新的数组的引用赋值给变量,其他引用并不受影响。
这意味着以前数组的内容被引用的话将依旧存在于内存中,这将导致内存泄漏。
* `list.length = 0` 删除数组里的所有内容,也将影响到其他引用。
然而,如果你复制了一个数组(A 和 Copy-A),如果你用`list.length = 0`清空了它的内容,复制的数组也会清空它的内容。
考虑一下将会输出什么:
```js
var foo = [1,2,3];
var bar = [1,2,3];
var foo2 = foo;
var bar2 = bar;
foo = [];
bar.length = 0;
console.log(foo, bar, foo2, bar2);
//[] [] [1, 2, 3] []
```
更多内容请看Stackoverflow:
[difference-between-array-length-0-and-array](http://stackoverflow.com/questions/4804235/difference-between-array-length-0-and-array)
================================================
FILE: _posts/zh_CN/javascript/2016-01-23-converting-to-number-fast-way.md
================================================
---
layout: post
title: 转换为数字的更快方法
tip-number: 23
tip-username: sonnyt
tip-username-profile: http://twitter.com/sonnyt
tip-tldr: 将字符串转换为数字是极为常见的。最简单和快速的方法是使用`+`(加号) 来实现。
redirect_from:
- /zh_cn/converting-to-number-fast-way/
categories:
- zh_CN
- javascript
---
将字符串转换为数字是极为常见的。最简单和快速的方法([jsPref](https://jsperf.com/number-vs-parseint-vs-plus/29))`+`(加号) 来实现。
```javascript
var one = '1';
var numberOne = +one; // Number 1
```
你也可以用`-`(减号)将其转化为负数值。
```javascript
var one = '1';
var negativeNumberOne = -one; // Number -1
```
================================================
FILE: _posts/zh_CN/javascript/2016-01-24-use_===_instead_of_==.md
================================================
---
layout: post
title: 使用 === 而不是 ==
tip-number: 24
tip-username: bhaskarmelkani
tip-username-profile: https://www.twitter.com/bhaskarmelkani
tip-tldr: == (或者 `!=`) 操作在需要的情况下自动进行了类型转换。`===` (或 `!==`)操作不会执行任何转换。`===`在比较值和类型时,可以说比`==`更快。
redirect_from:
- /zh_cn/use_===_instead_of_==/
categories:
- zh_CN
- javascript
---
`==` (或者 `!=`) 操作在需要的情况下自动进行了类型转换。`===` (或 `!==`)操作不会执行任何转换。`===`在比较值和类型时,可以说比`==`更快([jsPref](http://jsperf.com/strictcompare))。
```js
[10] == 10 // 为 true
[10] === 10 // 为 false
'10' == 10 // 为 true
'10' === 10 // 为 false
[] == 0 // 为 true
[] === 0 // 为 false
'' == false // 为 true 但 true == "a" 为false
'' === false // 为 false
```
================================================
FILE: _posts/zh_CN/javascript/2016-01-25-Using-immediately-invoked-function-expression.md
================================================
---
layout: post
title: 使用立即执行函数表达式
tip-number: 25
tip-username: rishantagarwal
tip-username-profile: https://github.com/rishantagarwal
tip-tldr: 立即执行函数表达式( IIFE - immediately invoked function expression)是一个立即执行的匿名函数表达式,它在Javascript中有一些很重要的用途。
redirect_from:
- /zh_cn/Using-immediately-invoked-function-expression/
categories:
- zh_CN
- javascript
---
立即执行函数表达式( IIFE - immediately invoked function expression)是一个立即执行的匿名函数表达式,它在Javascript中有一些很重要的用途。
```javascript
(function() {
// Do something
}
)()
```
这是一个立即执行的匿名函数表达式,它在有JavaScript一些特别重要的用途。
两对括号包裹着一个匿名函数,使匿名函数变成了一个函数表达式。于是,我们现在拥有了一个未命名的函数表达式,而不是一个全局作用域下或在任何地方定义的的简单函数。
类似地,我们也可以创建一个命名过的立即执行函数表达式:
```javascript
(someNamedFunction = function(msg) {
console.log(msg || "Nothing for today !!")
}) (); // 输出 --> Nothing for today !!
someNamedFunction("Javascript rocks !!"); // 输出 --> Javascript rocks !!
someNamedFunction(); // 输出 --> Nothing for today !!
```
更多内容, 请参考下面链接 -
1. [链接 1](https://blog.mariusschulz.com/2016/01/13/disassembling-javascripts-iife-syntax)
2. [链接 2](http://javascriptissexy.com/12-simple-yet-powerful-javascript-tips/)
效率:
[jsPerf](http://jsperf.com/iife-with-call)
================================================
FILE: _posts/zh_CN/javascript/2016-01-26-filtering-and-sorting-a-list-of-strings.md
================================================
---
layout: post
title: 过滤并排序字符串列表
tip-number: 26
tip-username: davegomez
tip-username-profile: https://github.com/davegomez
tip-tldr: 你可能有一个很多名字组成的列表,需要过滤掉重复的名字并按字母表将其排序。
redirect_from:
- /zh_cn/filtering-and-sorting-a-list-of-strings/
categories:
- zh_CN
- javascript
---
你可能有一个很多名字组成的列表,需要过滤掉重复的名字并按字母表将其排序。
在我们的例子里准备用不同版本语言的**JavaScript 保留字**的列表,但是你能发现,有很多重复的关键字而且它们并没有按字母表顺序排列。所以这是一个完美的字符串列表([数组](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array))来测试我们的JavaScript小知识。
```js
var keywords = ['do', 'if', 'in', 'for', 'new', 'try', 'var', 'case', 'else', 'enum', 'null', 'this', 'true', 'void', 'with', 'break', 'catch', 'class', 'const', 'false', 'super', 'throw', 'while', 'delete', 'export', 'import', 'return', 'switch', 'typeof', 'default', 'extends', 'finally', 'continue', 'debugger', 'function', 'do', 'if', 'in', 'for', 'int', 'new', 'try', 'var', 'byte', 'case', 'char', 'else', 'enum', 'goto', 'long', 'null', 'this', 'true', 'void', 'with', 'break', 'catch', 'class', 'const', 'false', 'final', 'float', 'short', 'super', 'throw', 'while', 'delete', 'double', 'export', 'import', 'native', 'public', 'return', 'static', 'switch', 'throws', 'typeof', 'boolean', 'default', 'extends', 'finally', 'package', 'private', 'abstract', 'continue', 'debugger', 'function', 'volatile', 'interface', 'protected', 'transient', 'implements', 'instanceof', 'synchronized', 'do', 'if', 'in', 'for', 'let', 'new', 'try', 'var', 'case', 'else', 'enum', 'eval', 'null', 'this', 'true', 'void', 'with', 'break', 'catch', 'class', 'const', 'false', 'super', 'throw', 'while', 'yield', 'delete', 'export', 'import', 'public', 'return', 'static', 'switch', 'typeof', 'default', 'extends', 'finally', 'package', 'private', 'continue', 'debugger', 'function', 'arguments', 'interface', 'protected', 'implements', 'instanceof', 'do', 'if', 'in', 'for', 'let', 'new', 'try', 'var', 'case', 'else', 'enum', 'eval', 'null', 'this', 'true', 'void', 'with', 'await', 'break', 'catch', 'class', 'const', 'false', 'super', 'throw', 'while', 'yield', 'delete', 'export', 'import', 'public', 'return', 'static', 'switch', 'typeof', 'default', 'extends', 'finally', 'package', 'private', 'continue', 'debugger', 'function', 'arguments', 'interface', 'protected', 'implements', 'instanceof'];
```
因为我们不想改变我们的原始列表,所以我们准备用高阶函数叫做[`filter`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/filter),它将基于我们传递的回调方法返回一个新的过滤后的数组。回调方法将比较当前关键字在原始列表里的索引和新列表中的索引,仅当索引匹配时将当前关键字push到新数组。
最后我们准备使用[`sort`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)方法排序过滤后的列表,`sort`只接受一个比较方法作为参数,并返回按字母表排序后的列表。
```js
var filteredAndSortedKeywords = keywords
.filter(function (keyword, index) {
return keywords.lastIndexOf(keyword) === index;
})
.sort(function (a, b) {
return a < b ? -1 : 1;
});
```
在**ES6** (ECMAScript 2015)版本下使用[箭头函数](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions)看起来更简单:
```js
const filteredAndSortedKeywords = keywords
.filter((keyword, index) => keywords.lastIndexOf(keyword) === index)
.sort((a, b) => a < b ? -1 : 1);
```
这是最后过滤和排序后的JavaScript保留字列表:
```js
console.log(filteredAndSortedKeywords);
// ['abstract', 'arguments', 'await', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'double', 'else', 'enum', 'eval', 'export', 'extends', 'false', 'final', 'finally', 'float', 'for', 'function', 'goto', 'if', 'implements', 'import', 'in', 'instanceof', 'int', 'interface', 'let', 'long', 'native', 'new', 'null', 'package', 'private', 'protected', 'public', 'return', 'short', 'static', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient', 'true', 'try', 'typeof', 'var', 'void', 'volatile', 'while', 'with', 'yield']
```
*感谢[@nikshulipa](https://github.com/nikshulipa)、[@kirilloid](https://twitter.com/kirilloid)、[@lesterzone](https://twitter.com/lesterzone)、[@tracker1](https://twitter.com/tracker1)、[@manuel_del_pozo](https://twitter.com/manuel_del_pozo)所有的回复与建议!*
================================================
FILE: _posts/zh_CN/javascript/2016-01-27-short-circuit-evaluation-in-js.md
================================================
---
layout: post
title: JS中的短路求值
tip-number: 27
tip-username: bhaskarmelkani
tip-username-profile: https://www.twitter.com/bhaskarmelkani
tip-tldr: 短路求值是说, 只有当第一个运算数的值无法确定逻辑运算的结果时,才对第二个运算数进行求值:当AND(`&&`)的第一个运算数的值为false时,其结果必定为false;当OR(`||`)的第一个运算数为true时,最后结果必定为true。
redirect_from:
- /zh_cn/short-circuit-evaluation-in-js/
categories:
- zh_CN
- javascript
---
[短路求值](https://zh.wikipedia.org/wiki/%E7%9F%AD%E8%B7%AF%E6%B1%82%E5%80%BC)是说, 只有当第一个运算数的值无法确定逻辑运算的结果时,才对第二个运算数进行求值:当AND(`&&`)的第一个运算数的值为false时,其结果必定为false;当OR(`||`)的第一个运算数为true时,最后结果必定为true。
对于下面的`test`条件和`isTrue`与`isFalse`方法
```js
var test = true;
var isTrue = function(){
console.log('Test is true.');
};
var isFalse = function(){
console.log('Test is false.');
};
```
使用逻辑与 - `&&`.
```js
// 普通的if语句
if(test){
isTrue(); // Test is true
}
// 上面的语句可以使用 '&&' 写为:
( test && isTrue() ); // Test is true
```
使用逻辑或 - `||`.
```js
test = false;
if(!test){
isFalse(); // Test is false.
}
( test || isFalse()); // Test is false.
```
逻辑或可以用来给参数设置默认值。
```js
function theSameOldFoo(name){
name = name || 'Bar' ;
console.log("My best friend's name is " + name);
}
theSameOldFoo(); // My best friend's name is Bar
theSameOldFoo('Bhaskar'); // My best friend's name is Bhaskar
```
逻辑与可以用来避免调用undefined参数的属性时报错
例如:-
```js
var dog = {
bark: function(){
console.log('Woof Woof');
}
};
// 调用 dog.bark();
dog.bark(); // Woof Woof.
// 但是当dog未定义时,dog.bark() 将会抛出"Cannot read property 'bark' of undefined." 错误
// 防止这种情况,我们可以使用 &&.
dog&&dog.bark(); // This will only call dog.bark(), if dog is defined.
```
================================================
FILE: _posts/zh_CN/javascript/2016-01-28-curry-vs-partial-application.md
================================================
---
layout: post
title: 柯里化(currying)与部分应用(partial application)
tip-number: 28
tip-username: bhaskarmelkani
tip-username-profile: https://www.twitter.com/bhaskarmelkani
tip-tldr: 柯里化(currying)与部分应用(partial application)是两种将一个函数转换为另一个有着较小普通参数个数的函数的方法。
redirect_from:
- /zh_cn/curry-vs-partial-application/
categories:
- zh_CN
- javascript
---
**柯里化(currying)**
柯里化是使一个函数
f: X * Y -> R
转变为
f': X -> (Y -> R)
与用两个参数调用f不同,我们用一个参数运行f'。返回的结果是一个函数,然后用第二个参数调用此函数,得到结果。
如此,如果未柯里化的函数f这样调用
f(3,5)
柯里化后的函数f'是这样调用的
f(3)(5)
比如:
未柯里化的函数add()
```javascript
function add(x, y) {
return x + y;
}
add(3, 5); // returns 8
```
柯里化后的add()
```javascript
function addC(x) {
return function (y) {
return x + y;
}
}
addC(3)(5); // returns 8
```
**柯里化的规则**
柯里化将一个二元函数,转变为一元函数,这个函数将返回另一个一元函数。
curry: (X × Y → R) → (X → (Y → R))
Javascript Code:
```javascript
function curry(f) {
return function(x) {
return function(y) {
return f(x, y);
}
}
}
```
**部分应用(partial application)**
部分应用将一个函数
f: X * Y -> R
的第一个参数固定而产生一个新的函数
f`: Y -> R
f'与f不同,只需要填写第二个参数,这也是f'比f少一个参数的原因。
比如:将函数add的第一个参数绑定为5来产生函数plus5。
```javascript
function plus5(y) {
return 5 + y;
}
plus5(3); // returns 8
```
**部分应用的规则**
部分应用使用一个二元函数和一个值产生了一个一元函数。
partApply : ((X × Y → R) × X) → (Y → R)
Javascript Code:
```javascript
function partApply(f, x) {
return function(y) {
return f(x, y);
}
}
```
================================================
FILE: _posts/zh_CN/javascript/2016-01-29-speed-up-recursive-functions-with-memoization.md
================================================
---
layout: post
title: 运用存储加速递归 Speed up recursive functions with memoization
tip-number: 29
tip-username: hingsir
tip-username-profile: https://github.com/hingsir
tip-tldr: 大家对斐波那契(Fibonacci)数列都很熟悉。我们可以再20秒内写出下面这样一个方法,它可以运行,但并不高效。它做了太多重复的运算,我们可以通过存储这些运算结果来使其加速。
redirect_from:
- /zh_cn/speed-up-recursive-functions-with-memoization/
categories:
- zh_CN
- javascript
---
大家对斐波那契(Fibonacci)数列都很熟悉。我们可以再20秒内写出下面这样一个方法。
```js
var fibonacci = function(n){
return n < 2 ? n : fibonacci(n-1) + fibonacci(n-2);
}
```
它可以运行,但并不高效。它做了太多重复的运算,我们可以通过存储这些运算结果来使其加速。
```js
var fibonacci = (function() {
var cache = [0, 1]; // cache the value at the n index
return function(n) {
if (cache[n] === undefined) {
for (var i = cache.length; i <= n; ++i) {
cache[i] = cache[i-1] + cache[i-2];
}
}
return cache[n];
}
})()
```
我们也可以定义一个高阶函数,它接收一个方法作为参数,返回一个该方法运用存储后的新方法。
```js
var memoize = function(func){
var cache = {};
return function(){
var key = Array.prototype.slice.call(arguments).toString();
return key in cache ? cache[key] : (cache[key] = func.apply(this,arguments));
}
}
fibonacci = memoize(fibonacci);
```
ES6版本的memoize函数如下:
```js
var memoize = function(func){
const cache = {};
return (...args) => {
const key = [...args].toString();
return key in cache ? cache[key] : (cache[key] = func(...args));
}
}
fibonacci = memoize(fibonacci);
```
我们可以将`memoize()`用在很多其他地方
* GCD(最大公约数)
```js
var gcd = memoize(function(a,b){
var t;
if (a < b) t=b, b=a, a=t;
while(b != 0) t=b, b = a%b, a=t;
return a;
})
gcd(27,183); //=> 3
```
* 阶乘运算
```js
var factorial = memoize(function(n) {
return (n <= 1) ? 1 : n * factorial(n-1);
})
factorial(5); //=> 120
```
================================================
FILE: _posts/zh_CN/javascript/2016-01-30-converting-truthy-falsy-values-to-boolean.md
================================================
---
layout: post
title: 将truthy/falsy转换为布尔值
tip-number: 30
tip-username: hakhag
tip-username-profile: https://github.com/hakhag
tip-tldr: 逻辑运算符是JavaScript的核心之一,在这里你将看到一种无论你传什么值都可以总是得到true或false的方法。
redirect_from:
- /zh_cn/converting-truthy-falsy-values-to-boolean/
categories:
- zh_CN
- javascript
---
你可以使用`!!`操作符将[truthy](https://developer.mozilla.org/zh-CN/docs/Glossary/Truthy)或[falsy](https://developer.mozilla.org/zh-CN/docs/Glossary/Falsy)值转换为布尔值。
```js
!!"" // false
!!0 // false
!!null // false
!!undefined // false
!!NaN // false
!!"hello" // true
!!1 // true
!!{} // true
!![] // true
```
================================================
FILE: _posts/zh_CN/javascript/2016-01-31-avoid-modifying-or-passing-arguments-into-other-functions—it-kills-optimization.md
================================================
---
layout: post
title: 避免修改和传递`arguments`给其他方法 — 影响优化
tip-number: 31
tip-username: berkana
tip-username-profile: https://github.com/berkana
tip-tldr: 在JavaScript的方法里,`arguments`参数可以让你访问传递给该方法的所有参数。`arguments`是一个*类数组对象*;`arguments`可是使用数组标记访问,而且它有*length*参数,但是它没有`filter`、`map`和`forEach`这样内建到数组内的方法。因此,如下代码是一个非常常见的将`arguments`转换为数组的办法
redirect_from:
- /zh_cn/avoid-modifying-or-passing-arguments-into-other-functions-it-kills-optimization/
categories:
- zh_CN
- javascript
---
### 背景
在JavaScript的方法里,[`arguments`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments)参数可以让你访问传递给该方法的所有参数。`arguments`是一个*类数组对象*;`arguments`可是使用数组标记访问,而且它有*length*参数,但是它没有`filter`、`map`和`forEach`这样内建到数组内的方法。因此,如下代码是一个非常常见的将`arguments`转换为数组的办法:
```js
var args = Array.prototype.slice.call(arguments);
```
将`arguments`传递给`Array`原型(prototype)上的`slice`方法;`slice`方法返回一个对`arguments`浅复制后的数组对象。更短的写法:
```js
var args = [].slice.call(arguments);
```
在这里,简单的调用了空数组的`slice`方法,而没有从`Array`的原型(prototype)上调用。
### 系统优化
不幸的是,传递`arguments`给任何参数,将导致Chrome和Node中使用的V8引擎跳过对其的优化,这也将使性能相当慢。看一下这篇文章[optimization killers](https://github.com/petkaantonov/bluebird/wiki/Optimization-killers)。传递`arguments`给任何方法被称为*leaking `arguments`*。
如果你想用一个包含参数(arguments)的数组,你需要求助于这个办法:
```js
var args = new Array(arguments.length);
for(var i = 0; i < args.length; ++i) {
args[i] = arguments[i];
}
```
没错,这很啰嗦,但是在生产环境中的代码里,为了系统性能优化,这是值得的。
================================================
FILE: _posts/zh_CN/javascript/2016-02-01-map-to-the-rescue-adding-order-to-object-properties.md
================================================
---
layout: post
title: Map()的营救;使对象属性有顺序
tip-number: 32
tip-username: loverajoel
tip-username-profile: https://twitter.com/loverajoel
tip-tldr: 对象是一个无序的对象集合。这意味着如果你想在对象里保存有序的数据,你需要重新处理它,因为对象里的数据不保证是有序的。
tip-writer-support: https://www.coinbase.com/loverajoel
redirect_from:
- /zh_cn/map-to-the-rescue-adding-order-to-object-properties/
categories:
- zh_CN
- javascript
---
## 对象属性顺序
> 一个对象是一个`Object`类型的实例。它是由一些未排序的元素组成的集合,其中包含了原始变量,对象,和函数。一个对象的属性所对应的函数被称为方法。[ECMAScript](http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf)
实际看一下
```js
var myObject = {
z: 1,
'@': 2,
b: 3,
1: 4,
5: 5
};
console.log(myObject) // Object {1: 4, 5: 5, z: 1, @: 2, b: 3}
for (item in myObject) {...
// 1
// 5
// z
// @
// b
```
因为技术实现,每个浏览器在排序时都有自己的规则,顺序是不确定的。
## 怎么解决呢?
### Map
使用ES6的新特性Map。[Map](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map) 对象以插入的顺序遍历元素。`for...of`循环为每一次循环返回一个[key, value]数组。
```js
var myObject = new Map();
myObject.set('z', 1);
myObject.set('@', 2);
myObject.set('b', 3);
for (var [key, value] of myObject) {
console.log(key, value);
...
// z 1
// @ 2
// b 3
```
### 攻克老浏览器
Mozilla 建议:
> 所以,如果过你想在跨浏览器环境中模拟一个有序的关联数组,你要么使用两个分开的数组(一个保存key,另一个保存value),要么构建一个单属性对象(single-property objects)的数组。
```js
// 使用分开的数组
var objectKeys = [z, @, b, 1, 5];
for (item in objectKeys) {
myObject[item]
...
// 构建一个单属性对象(single-property objects)的数组
var myData = [{z: 1}, {'@': 2}, {b: 3}, {1: 4}, {5: 5}];
```
================================================
FILE: _posts/zh_CN/javascript/2016-02-02-create-range-0-n-easily-using-one-line.md
================================================
---
layout: post
title: 仅用一行生成`[0, 1, ..., N-1]`数列
tip-number: 33
tip-username: SarjuHansaliya
tip-username-profile: https://github.com/SarjuHansaliya
tip-tldr: 我们可以创建一个函数,它可以仅用一行代码生成0...(N-1)数列。
redirect_from:
- /zh_cn/create-range-0-n-easily-using-one-line/
categories:
- zh_CN
- javascript
---
使用下面一行代码,我们就可以生成0...(N-1)数列。
### 方法1 (需要 ES5)
```js
Array.apply(null, {length: N}).map(Function.call, Number);
```
#### 简要说明
1. `Array.apply(null, {length: N})` 返回一个由`undefined`填充的长度为`N`的数组(例如 `A = [undefined, undefined, ...]`)。
2. `A.map(Function.call, Number)` 返回一个长度为`N`的数组,它的索引为`I`的元素为`Function.call.call(Number, undefined, I, A)`的结果。
3. `Function.call.call(Number, undefined, I, A)`可转化为`Number(I)`,正好就是`I`。
4. 结果为:`[0, 1, ..., N-1]`。
更全面的介绍,请看[这里](https://github.com/gromgit/jstips-xe/blob/master/tips/33.md).
### 方法2 (需要 ES6)
这里用到了`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)
```js
Array.from(new Array(N),(val,index)=>index);
```
#### 简要说明
1. `A = new Array(N)` 返回一个有`N`个_小孔_的数组 (例如 `A = [,,,...]`, 但是对于`x` in `0...N-1`时`A[x] = undefined`)。
2. `F = (val,index)=>index` 即 `function F (val, index) { return index; }`。
3. `Array.from(A, F)` 返回一个长度为`N`的数组,它的索引为`I`的元素为`F(A[I], I)`的结果,也就是`I`。
4. 结果为:`[0, 1, ..., N-1]`。
### One More Thing
如果你需要[1, 2, ..., N]序列, **方法1** 可改为:
```js
Array.apply(null, {length: N}).map(function(value, index){
return index + 1;
});
```
**方法2**可改为:
```js
Array.from(new Array(N),(val,index)=>index+1);
```
================================================
FILE: _posts/zh_CN/javascript/2016-02-03-implementing-asynchronous-loops.md
================================================
---
layout: post
title: 实现异步循环
tip-number: 34
tip-username: madmantalking
tip-username-profile: https://github.com/madmantalking
tip-tldr: 实现异步循环时,你可能会遇到问题。
redirect_from:
- /zh_cn/implementing-asynchronous-loops/
categories:
- zh_CN
- javascript
---
让我们试着写一个异步方法,每秒打印一次循环的索引值。
```js
for (var i=0; i<5; i++) {
setTimeout(function(){
console.log(i);
}, 1000 * (i+1));
}
```
如上程序的输出为:
```js
> 5
> 5
> 5
> 5
> 5
```
这明显是有问题的。
**原因**
每次时间结束(timeout)都指向原始的`i`,而并非它的拷贝。所以,for循环使`i`增长到5,之后`timeout`运行并调用了当前`i`的值(也就是5)。
好吧,这个问题看起来很简单。最直接的解决方法是将循环的索引缓存在一个临时变量里。
```js
for (var i=0; i<5; i++) {
var temp = i;
setTimeout(function(){
console.log(temp);
}, 1000 * (i+1));
}
```
但是再次运行,如上的程序输出为:
```js
> 4
> 4
> 4
> 4
> 4
```
这仍然有问题,这是因为并不存在块作用域,而且变量的声明被提升到了作用域顶端。实际上,如上代码和下面是一样的:
```js
var temp;
for (var i=0; i<5; i++) {
temp = i;
setTimeout(function(){
console.log(temp);
}, 1000 * (i+1));
}
```
**解决方法**
有几个不同的方式可以拷贝`i`。最普通且常用方法是通过声明函数来建立一个闭包,并将`i`传给此函数。我们这里使用了自调用函数。
```js
for (var i=0; i<5; i++) {
(function(num){
setTimeout(function(){
console.log(num);
}, 1000 * (i+1));
})(i);
}
```
在JavaScript里,参数是按值传递给函数的。像`Number`、`Date`和`String`这些原始类型为基本复制。当你们在一个函数内改变它的值,并不影响外面的作用域。但`Object`类型不一样:如果你在函数内部修改了它的参数,将会影响到所有包含该`Object`的作用域内它的参数。
另一种方法是使用`let`。在ES6中的`let`关键字是可以实现的,它和`var`不一样,因为它支持块作用域的。
```js
for (let i=0; i<5; i++) {
var temp = i;
setTimeout(function(){
console.log(i);
}, 1000 * (i+1));
}
```
================================================
FILE: _posts/zh_CN/javascript/2016-02-04-assignment-shorthands.md
================================================
---
layout: post
title: 赋值技巧
tip-number: 35
tip-username: hsleonis
tip-username-profile: https://github.com/hsleonis
tip-tldr: 赋值是很常见的。有时候打字对于我们这些“懒惰的程序员”来说是很费时间的。所以,我们可以使用一些小把戏来使我们的代码更清楚更简单。
redirect_from:
- /zh_cn/assignment-shorthands/
categories:
- zh_CN
- javascript
---
赋值是很常见的。有时候打字对于我们这些“懒惰的程序员”来说是很费时间的。
所以,我们可以使用一些小把戏来使我们的代码更清楚更简单。
这类似于使用:
```js
x += 23; // x = x + 23;
y -= 15; // y = y - 15;
z *= 10; // z = z * 10;
k /= 7; // k = k / 7;
p %= 3; // p = p % 3;
d **= 2; // d = d ** 2;
m >>= 2; // m = m >> 2;
n <<= 2; // n = n << 2;
n ++; // n = n + 1;
n --; n = n - 1;
```
### `++` 与 `--` 操作符
对于`++`操作符有些特殊。最好用下面的例子解释一下:
```js
var a = 2;
var b = a++;
// 现在 a == 3 b == 2
```
`a++`做了如下工作:
1. 返回`a`的值
2. `a`增加1
但是如果我们想让值先增加呢?这也很容易:
```js
var a = 2;
var b = ++a;
// 现在a和b都是3
```
看明白了吗?我将操作符放在了参数_前面_。
`--`操作符除了使值减小外,其他功能是类似的。
### If-else (使用三元运算符)
我们平时会这样写:
```js
var newValue;
if(value > 10)
newValue = 5;
else
newValue = 2;
```
我们可以使用三元运算符是它更简便:
```js
var newValue = (value > 10) ? 5 : 2;
```
### 检测Null、Undefined、空
```js
if (variable1 !== null || variable1 !== undefined || variable1 !== '') {
var variable2 = variable1;
}
```
简便写法:
```js
var variable2 = variable1 || '';
```
P.S.:如果`variable1`是一个数字,则先检查他是否为0。
### 对象数组表示法
不要用:
```js
var a = new Array();
a[0] = "myString1";
a[1] = "myString2";
```
使用:
```js
var a = ["myString1", "myString2"];
```
### 关联数组
不要用:
```js
var skillSet = new Array();
skillSet['Document language'] = 'HTML5';
skillSet['Styling language'] = 'CSS3';
```
使用:
```js
var skillSet = {
'Document language' : 'HTML5',
'Styling language' : 'CSS3'
};
```
================================================
FILE: _posts/zh_CN/javascript/2016-02-05-observe-dom-changes.md
================================================
---
layout: post
title: 扩展插件中观察DOM的变化
tip-number: 36
tip-username: beyondns
tip-username-profile: https://github.com/beyondns
tip-tldr: 当你为存在的网站开发扩展插件时,由于现代的动态Javascript,操作DOM并不是很容易。
redirect_from:
- /zh_cn/observe-dom-changes/
categories:
- zh_CN
- javascript
---
[MutationObserver](https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver)是监听DOM变化与当元素变化时做适当操作的一个解决方法。在下面的例子中我们使用计时器模拟了内容的动态加载,第一个元素"target"创建后,创建"subTarget"。
在扩展中的代码,`rootObserver`首先开始工作,直到`targetElement`被创建后`rootObserver`停止,然后`elementObserver`开始工作。这个级联观测可以在发现`subTargetElement`时提醒你。
这个方法在为动态加载内容的网站开发扩展插件时,是很有用的。
```js
const observeConfig = {
attributes: true,
childList: true,
characterData: true,
subtree: true
};
function initExtension(rootElement, targetSelector, subTargetSelector) {
var rootObserver = new MutationObserver(function(mutations) {
console.log("Inside root observer");
targetElement = rootElement.querySelector(targetSelector);
if (targetElement) {
rootObserver.disconnect();
var elementObserver = new MutationObserver(function(mutations) {
console.log("Inside element observer")
subTargetElement = targetElement.querySelector(subTargetSelector);
if (subTargetElement) {
elementObserver.disconnect();
console.log("subTargetElement found!")
}
})
elementObserver.observe(targetElement, observeConfig);
}
})
rootObserver.observe(rootElement, observeConfig);
}
(function() {
initExtension(document.body, "div.target", "div.subtarget")
setTimeout(function() {
del = document.createElement("div");
del.innerHTML = "
target
"
document.body.appendChild(del)
}, 3000);
setTimeout(function() {
var el = document.body.querySelector('div.target')
if (el) {
del = document.createElement("div");
del.innerHTML = "
"
document.body.appendChild(del);
}, 3000);
setTimeout(function() {
var el = document.body.querySelector('div.target');
if (el) {
del = document.createElement("div");
del.innerHTML = "