├── .gitignore ├── .lvimrc ├── LICENSE ├── README.md ├── build.js ├── deploy.sh ├── doc ├── de │ ├── index.json │ └── intro │ │ ├── authors.md │ │ ├── contributors.md │ │ ├── index.md │ │ └── license.md ├── en │ ├── array │ │ ├── constructor.md │ │ └── general.md │ ├── core │ │ ├── delete.md │ │ ├── eval.md │ │ ├── semicolon.md │ │ └── undefined.md │ ├── function │ │ ├── arguments.md │ │ ├── closures.md │ │ ├── constructors.md │ │ ├── general.md │ │ ├── scopes.md │ │ └── this.md │ ├── index.json │ ├── intro │ │ └── index.md │ ├── object │ │ ├── forinloop.md │ │ ├── general.md │ │ ├── hasownproperty.md │ │ └── prototype.md │ ├── other │ │ └── timeouts.md │ └── types │ │ ├── casting.md │ │ ├── equality.md │ │ ├── instanceof.md │ │ └── typeof.md ├── es │ ├── array │ │ ├── constructor.md │ │ └── general.md │ ├── core │ │ ├── delete.md │ │ ├── eval.md │ │ ├── semicolon.md │ │ └── undefined.md │ ├── function │ │ ├── arguments.md │ │ ├── closures.md │ │ ├── constructors.md │ │ ├── general.md │ │ ├── scopes.md │ │ └── this.md │ ├── index.json │ ├── intro │ │ └── index.md │ ├── object │ │ ├── forinloop.md │ │ ├── general.md │ │ ├── hasownproperty.md │ │ └── prototype.md │ ├── other │ │ └── timeouts.md │ └── types │ │ ├── casting.md │ │ ├── equality.md │ │ ├── instanceof.md │ │ └── typeof.md ├── fi │ ├── array │ │ ├── constructor.md │ │ └── general.md │ ├── core │ │ ├── eval.md │ │ ├── semicolon.md │ │ └── undefined.md │ ├── function │ │ ├── arguments.md │ │ ├── closures.md │ │ ├── constructors.md │ │ ├── general.md │ │ ├── scopes.md │ │ └── this.md │ ├── index.json │ ├── intro │ │ ├── authors.md │ │ ├── contributors.md │ │ ├── index.md │ │ ├── license.md │ │ └── translators.md │ ├── object │ │ ├── forinloop.md │ │ ├── general.md │ │ ├── hasownproperty.md │ │ └── prototype.md │ ├── other │ │ └── timeouts.md │ └── types │ │ ├── casting.md │ │ ├── equality.md │ │ ├── instanceof.md │ │ └── typeof.md ├── ja │ ├── array │ │ ├── constructor.md │ │ └── general.md │ ├── core │ │ ├── delete.md │ │ ├── eval.md │ │ ├── semicolon.md │ │ └── undefined.md │ ├── function │ │ ├── arguments.md │ │ ├── closures.md │ │ ├── constructors.md │ │ ├── general.md │ │ ├── scopes.md │ │ └── this.md │ ├── index.json │ ├── intro │ │ └── index.md │ ├── object │ │ ├── forinloop.md │ │ ├── general.md │ │ ├── hasownproperty.md │ │ └── prototype.md │ ├── other │ │ └── timeouts.md │ └── types │ │ ├── casting.md │ │ ├── equality.md │ │ ├── instanceof.md │ │ └── typeof.md ├── ko │ ├── array │ │ ├── constructor.md │ │ └── general.md │ ├── core │ │ ├── delete.md │ │ ├── eval.md │ │ ├── semicolon.md │ │ └── undefined.md │ ├── function │ │ ├── arguments.md │ │ ├── closures.md │ │ ├── constructors.md │ │ ├── general.md │ │ ├── scopes.md │ │ └── this.md │ ├── index.json │ ├── intro │ │ └── index.md │ ├── object │ │ ├── forinloop.md │ │ ├── general.md │ │ ├── hasownproperty.md │ │ └── prototype.md │ ├── other │ │ └── timeouts.md │ └── types │ │ ├── casting.md │ │ ├── equality.md │ │ ├── instanceof.md │ │ └── typeof.md ├── language.json ├── pl │ ├── array │ │ ├── constructor.md │ │ └── general.md │ ├── core │ │ ├── eval.md │ │ ├── semicolon.md │ │ └── undefined.md │ ├── function │ │ ├── arguments.md │ │ ├── closures.md │ │ ├── constructors.md │ │ ├── general.md │ │ ├── scopes.md │ │ └── this.md │ ├── index.json │ ├── intro │ │ ├── authors.md │ │ ├── contributors.md │ │ ├── hosting.md │ │ ├── index.md │ │ ├── license.md │ │ └── translators.md │ ├── object │ │ ├── forinloop.md │ │ ├── general.md │ │ ├── hasownproperty.md │ │ └── prototype.md │ ├── other │ │ └── timeouts.md │ └── types │ │ ├── casting.md │ │ ├── equality.md │ │ ├── instanceof.md │ │ └── typeof.md ├── ru │ ├── appendix │ │ └── fromtranslators.md │ ├── array │ │ ├── constructor.md │ │ └── general.md │ ├── core │ │ ├── eval.md │ │ ├── semicolon.md │ │ └── undefined.md │ ├── function │ │ ├── arguments.md │ │ ├── closures.md │ │ ├── constructors.md │ │ ├── general.md │ │ ├── scopes.md │ │ └── this.md │ ├── index.json │ ├── intro │ │ ├── authors.md │ │ ├── contributors.md │ │ ├── index.md │ │ ├── license.md │ │ └── translators.md │ ├── object │ │ ├── forinloop.md │ │ ├── general.md │ │ ├── hasownproperty.md │ │ └── prototype.md │ ├── other │ │ └── timeouts.md │ └── types │ │ ├── casting.md │ │ ├── equality.md │ │ ├── instanceof.md │ │ └── typeof.md ├── tr │ ├── array │ │ ├── constructor.md │ │ └── general.md │ ├── core │ │ ├── delete.md │ │ ├── eval.md │ │ ├── semicolon.md │ │ └── undefined.md │ ├── function │ │ ├── arguments.md │ │ ├── closures.md │ │ ├── constructors.md │ │ ├── general.md │ │ ├── scopes.md │ │ └── this.md │ ├── index.json │ ├── intro │ │ └── index.md │ ├── object │ │ ├── forinloop.md │ │ ├── general.md │ │ ├── hasownproperty.md │ │ └── prototype.md │ ├── other │ │ └── timeouts.md │ └── types │ │ ├── casting.md │ │ ├── equality.md │ │ ├── instanceof.md │ │ └── typeof.md ├── zh │ ├── array │ │ ├── constructor.md │ │ └── general.md │ ├── core │ │ ├── eval.md │ │ ├── semicolon.md │ │ └── undefined.md │ ├── function │ │ ├── arguments.md │ │ ├── closures.md │ │ ├── constructors.md │ │ ├── general.md │ │ ├── scopes.md │ │ └── this.md │ ├── index.json │ ├── intro │ │ ├── authors.md │ │ ├── contributors.md │ │ ├── index.md │ │ └── license.md │ ├── object │ │ ├── forinloop.md │ │ ├── general.md │ │ ├── hasownproperty.md │ │ └── prototype.md │ ├── other │ │ └── timeouts.md │ └── types │ │ ├── casting.md │ │ ├── equality.md │ │ ├── instanceof.md │ │ └── typeof.md └── zhtw │ ├── array │ ├── constructor.md │ └── general.md │ ├── core │ ├── delete.md │ ├── eval.md │ ├── semicolon.md │ └── undefined.md │ ├── function │ ├── arguments.md │ ├── closures.md │ ├── constructors.md │ ├── general.md │ ├── scopes.md │ └── this.md │ ├── index.json │ ├── intro │ └── index.md │ ├── object │ ├── forinloop.md │ ├── general.md │ ├── hasownproperty.md │ └── prototype.md │ ├── other │ └── timeouts.md │ └── types │ ├── casting.md │ ├── equality.md │ ├── instanceof.md │ └── typeof.md ├── garden.jade ├── package.json └── site ├── favicon.ico ├── image └── sidebar-icon.png ├── javascript ├── garden.js ├── html5.js ├── plugin.js └── prettify.js └── style ├── garden.css └── print.css /.gitignore: -------------------------------------------------------------------------------- 1 | /site/index.html 2 | /build 3 | /html 4 | /log 5 | /node_modules 6 | /site/de 7 | /site/ru 8 | /site/zh 9 | /site/en 10 | /site/fi 11 | /site/pl 12 | /site/tr 13 | /site/ko 14 | /site/ja 15 | /site/es 16 | /site/zhtw 17 | *.md~ 18 | *.src.md 19 | *.DS_store 20 | -------------------------------------------------------------------------------- /.lvimrc: -------------------------------------------------------------------------------- 1 | set wildignore=node_modules 2 | set tabstop=2 3 | set shiftwidth=2 4 | set softtabstop=2 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Ivo Wetzel. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JavaScript Garden 2 | ================= 3 | 4 | **JavaScript Garden** is a growing collection of documentation about the most 5 | quirky parts of the JavaScript programming language. It gives advice to 6 | avoid common mistakes, subtle bugs, as well as performance issues and bad 7 | practices that non-expert JavaScript programmers may encounter on their 8 | endeavours into the depths of the language. 9 | 10 | JavaScript Garden does **not** aim to teach you JavaScript. Former knowledge 11 | of the language is strongly recommended in order to understand the topics covered 12 | in this guide. In order to learn the basics of the language, please head over to 13 | the excellent [guide][1] on the Mozilla Developer Network. 14 | 15 | ### The authors 16 | 17 | This guide is the work of two lovely Stack Overflow users, [Ivo Wetzel][6] 18 | (Original English Language Version) and [Zhang Yi Jiang][5] (Design), and 19 | [many others](https://github.com/BonsaiDen/JavaScript-Garden/graphs/contributors) 20 | who've worked hard to provide translations or fixes. 21 | 22 | It's currently maintained by [Tim Ruffles](http://twitter.com/timruffles). 23 | 24 | ## Contributing 25 | 26 | Please submit fixes and translations as [pull requests](https://help.github.com/articles/using-pull-requests). 27 | 28 | ### License 29 | 30 | JavaScript Garden is published under the [MIT license][2] and hosted on 31 | [GitHub][4]. If you find errors or typos please [file an issue][3] or a pull 32 | request on the repository. You can also find us in the [JavaScript room][10] on 33 | Stack Overflow chat. 34 | 35 | [1]: https://developer.mozilla.org/en/JavaScript/Guide 36 | [2]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE 37 | [3]: https://github.com/BonsaiDen/JavaScript-Garden/issues 38 | [4]: https://github.com/BonsaiDen/JavaScript-Garden 39 | [5]: http://stackoverflow.com/users/313758/yi-jiang 40 | [6]: http://stackoverflow.com/users/170224/ivo-wetzel 41 | [8]: https://github.com/caio 42 | [9]: https://github.com/blixt 43 | [10]: http://chat.stackoverflow.com/rooms/17/javascript 44 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | remote=mine 3 | if [[ $PRODUCTION ]]; then 4 | echo "Deploy to production? (y/n)" 5 | read ans 6 | if [[ $ans == "y" ]]; then 7 | remote="origin" 8 | fi 9 | fi 10 | diffs=`git diff --name-status HEAD` 11 | if [[ "" != $diffs ]]; then 12 | echo "Can't deploy, unsaved changes:" 13 | echo $diffs 14 | exit 15 | fi 16 | git checkout gh-pages 17 | git reset --hard master 18 | echo "Starting build" 19 | node build.js 20 | echo "Build complete" 21 | rm -rf `ls -d * | grep -vP 'site|node_modules' | xargs` 22 | echo "Cleaned out directory" 23 | mv site/* . 24 | if [[ $BUILD_ONLY ]]; then 25 | exit 26 | fi 27 | rm -rf site 28 | git add . -A 29 | git commit -m 'latest' 30 | echo "Commit created" 31 | git push --force $remote gh-pages 32 | echo "Deployed to $remote" 33 | git checkout master 34 | -------------------------------------------------------------------------------- /doc/de/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "JavaScript Garden", 3 | "langTitle": "JavaScript Garden in Deutsch", 4 | "description": "Ein Guide über JavaScript's Ecken und Kanten.", 5 | "sections": [ 6 | { 7 | "title": "Einführung", 8 | "dir": "intro", 9 | "articles": [ 10 | "authors", 11 | "contributors", 12 | "license" 13 | ] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /doc/de/intro/authors.md: -------------------------------------------------------------------------------- 1 | ## The Authors 2 | 3 | This guide is the work of two lovely Stack Overflow users, [Ivo Wetzel][1] 4 | (Writing) and [Zhang Yi Jiang][2] (Design). 5 | 6 | [1]: http://stackoverflow.com/users/170224/ivo-wetzel 7 | [2]: http://stackoverflow.com/users/313758/yi-jiang 8 | 9 | -------------------------------------------------------------------------------- /doc/de/intro/contributors.md: -------------------------------------------------------------------------------- 1 | ## Contributors 2 | 3 | - [Caio Romão][1] (Spelling corrections) 4 | - [Andreas Blixt][2] (Language corrections) 5 | 6 | [1]: https://github.com/caio 7 | [2]: https://github.com/blixt 8 | 9 | -------------------------------------------------------------------------------- /doc/de/intro/index.md: -------------------------------------------------------------------------------- 1 | ## Einführung 2 | 3 | **JavaScript Garden** ist eine wachsende Sammlung von Erklärungen der verzwicktesten Teile von JavaScript. Es gibt 4 | Hinweise um häufige Fehler, Performance Probleme und schlechten Stil zu vermeiden. 5 | 6 | JavaScript Garden ist **keine** Anleitung um JavaScript zu lernen. Ein grundlegendes Verständnis der Sprache wird 7 | wärmstens empfohlen. Eine gute [Einführung][1] findet sich zum Beispiel im Mozilla Developer Network. 8 | 9 | ## Die Autoren 10 | 11 | Dieses Dokument wurde von zwei liebenswerten [Stack Overflow][2] Benutzern geschrieben: [Ivo Wetzel][3] 12 | (Text) and [Zhang Yi Jiang][4] (Design). 13 | 14 | ## Beitragende 15 | 16 | - [Beitragende](https://github.com/BonsaiDen/JavaScript-Garden/graphs/contributors) 17 | 18 | ## Hosting 19 | 20 | JavaScript Garden wird von GitHub bereitgestellt, aber es wird auch von [Cramer Development][7] unterstützt durch 21 | einen Mirror auf [JavaScriptGarden.info][8]. 22 | 23 | ## Lizenz 24 | 25 | JavaScript Garden wurde unter der [MIT Lizenz][9] veröffentlich und wird von [GitHub][10] veröffentlicht. Wenn du 26 | Fehler findest mach bitte ein [Ticket][11] auf oder einen pull request ins repository. Du kannst uns auch im 27 | [JavaScript Raum][12] des Stack Overflow Chats finden. 28 | 29 | Mehr demnächst. 30 | 31 | [1]: https://developer.mozilla.org/en/JavaScript/Guide 32 | [2]: http://stackoverflow.com/ 33 | [3]: http://stackoverflow.com/users/170224/ivo-wetzel 34 | [4]: http://stackoverflow.com/users/313758/yi-jiang 35 | [5]: https://github.com/caio 36 | [6]: https://github.com/blixt 37 | [7]: http://cramerdev.com/ 38 | [8]: http://javascriptgarden.info/ 39 | [9]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE 40 | [10]: https://github.com/BonsaiDen/JavaScript-Garden 41 | [11]: https://github.com/BonsaiDen/JavaScript-Garden/issues 42 | [12]: http://chat.[stackoverflow.com/rooms/17/javascript 43 | -------------------------------------------------------------------------------- /doc/de/intro/license.md: -------------------------------------------------------------------------------- 1 | ## License 2 | 3 | JavaScript Garden is published under the [MIT license][1] and hosted on 4 | [GitHub][2]. If you find errors or typos please [file an issue][3] or a pull 5 | request on the repository. You can also find us in the [JavaScript room][4] on 6 | Stack Overflow chat. 7 | 8 | [1]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE 9 | [2]: https://github.com/BonsaiDen/JavaScript-Garden 10 | [3]: https://github.com/BonsaiDen/JavaScript-Garden/issues 11 | [4]: http://chat.stackoverflow.com/rooms/17/javascript 12 | 13 | -------------------------------------------------------------------------------- /doc/en/array/constructor.md: -------------------------------------------------------------------------------- 1 | ## The `Array` Constructor 2 | 3 | Since the `Array` constructor is ambiguous in how it deals with its parameters, 4 | it is highly recommended to use the array literal - `[]` notation - 5 | when creating new arrays. 6 | 7 | [1, 2, 3]; // Result: [1, 2, 3] 8 | new Array(1, 2, 3); // Result: [1, 2, 3] 9 | 10 | [3]; // Result: [3] 11 | new Array(3); // Result: [] 12 | new Array('3') // Result: ['3'] 13 | 14 | In cases when there is only one argument passed to the `Array` constructor 15 | and when that argument is a `Number`, the constructor will return a new *sparse* 16 | array with the `length` property set to the value of the argument. It should be 17 | noted that **only** the `length` property of the new array will be set this way; 18 | the actual indexes of the array will not be initialized. 19 | 20 | var arr = new Array(3); 21 | arr[1]; // undefined 22 | 1 in arr; // false, the index was not set 23 | 24 | Being able to set the length of the array in advance is only useful in a few 25 | cases, like repeating a string, in which it avoids the use of a loop. 26 | 27 | new Array(count + 1).join(stringToRepeat); 28 | 29 | ### In Conclusion 30 | 31 | Literals are preferred to the Array constructor. They are shorter, have a clearer syntax, and increase code 32 | readability. 33 | 34 | -------------------------------------------------------------------------------- /doc/en/array/general.md: -------------------------------------------------------------------------------- 1 | ## Array Iteration and Properties 2 | 3 | Although arrays in JavaScript are objects, there are no good reasons to use 4 | the [`for in`](#object.forinloop) loop. In fact, there 5 | are a number of good reasons **against** the use of `for in` on arrays. 6 | 7 | > **Note:** JavaScript arrays are **not** *associative arrays*. JavaScript only 8 | > has [objects](#object.general) for mapping keys to values. And while associative 9 | > arrays **preserve** order, objects **do not**. 10 | 11 | Because the `for in` loop enumerates all the properties that are on the prototype 12 | chain and because the only way to exclude those properties is to use 13 | [`hasOwnProperty`](#object.hasownproperty), it is already up to **twenty times** 14 | slower than a normal `for` loop. 15 | 16 | ### Iteration 17 | 18 | In order to achieve the best performance when iterating over arrays, it is best 19 | to use the classic `for` loop. 20 | 21 | var list = [1, 2, 3, 4, 5, ...... 100000000]; 22 | for(var i = 0, l = list.length; i < l; i++) { 23 | console.log(list[i]); 24 | } 25 | 26 | There is one extra catch in the above example, which is the caching of the 27 | length of the array via `l = list.length`. 28 | 29 | Although the `length` property is defined on the array itself, there is still an 30 | overhead for doing the lookup on each iteration of the loop. And while recent 31 | JavaScript engines **may** apply optimization in this case, there is no way of 32 | telling whether the code will run on one of these newer engines or not. 33 | 34 | In fact, leaving out the caching may result in the loop being only **half as 35 | fast** as with the cached length. 36 | 37 | ### The `length` Property 38 | 39 | While the *getter* of the `length` property simply returns the number of 40 | elements that are contained in the array, the *setter* can be used to 41 | **truncate** the array. 42 | 43 | var foo = [1, 2, 3, 4, 5, 6]; 44 | foo.length = 3; 45 | foo; // [1, 2, 3] 46 | 47 | foo.length = 6; 48 | foo.push(4); 49 | foo; // [1, 2, 3, undefined, undefined, undefined, 4] 50 | 51 | Assigning a smaller length truncates the array. Increasing it creates a sparse array. 52 | 53 | ### In Conclusion 54 | 55 | For the best performance, it is recommended to always use the plain `for` loop 56 | and cache the `length` property. The use of `for in` on an array is a sign of 57 | badly written code that is prone to bugs and bad performance. 58 | 59 | -------------------------------------------------------------------------------- /doc/en/core/eval.md: -------------------------------------------------------------------------------- 1 | ## Why Not to Use `eval` 2 | 3 | The `eval` function will execute a string of JavaScript code in the local scope. 4 | 5 | var foo = 1; 6 | function test() { 7 | var foo = 2; 8 | eval('foo = 3'); 9 | return foo; 10 | } 11 | test(); // 3 12 | foo; // 1 13 | 14 | However, `eval` only executes in the local scope when it is being called 15 | directly *and* when the name of the called function is actually `eval`. 16 | 17 | var foo = 1; 18 | function test() { 19 | var foo = 2; 20 | var bar = eval; 21 | bar('foo = 3'); 22 | return foo; 23 | } 24 | test(); // 2 25 | foo; // 3 26 | 27 | The use of `eval` should be avoided. 99.9% of its "uses" can be achieved 28 | **without** it. 29 | 30 | ### `eval` in Disguise 31 | 32 | The [timeout functions](#other.timeouts) `setTimeout` and `setInterval` can both 33 | take a string as their first argument. This string will **always** get executed 34 | in the global scope since `eval` is not being called directly in that case. 35 | 36 | ### Security Issues 37 | 38 | `eval` also is a security problem, because it executes **any** code given to it. 39 | It should **never** be used with strings of unknown or untrusted origins. 40 | 41 | ### In Conclusion 42 | 43 | `eval` should never be used. Any code that makes use of it should be questioned 44 | in its workings, performance and security. If something requires `eval` in 45 | order to work, it should **not** be used in the first place. A *better design* 46 | should be used, that does not require the use of `eval`. 47 | 48 | -------------------------------------------------------------------------------- /doc/en/function/general.md: -------------------------------------------------------------------------------- 1 | ## Function Declarations and Expressions 2 | 3 | Functions in JavaScript are first class objects. That means they can be 4 | passed around like any other value. One common use of this feature is to pass 5 | an *anonymous function* as a callback to another, possibly an asynchronous function. 6 | 7 | ### The `function` Declaration 8 | 9 | function foo() {} 10 | 11 | The above function gets [hoisted](#function.scopes) before the execution of the 12 | program starts; thus, it is available *everywhere* in the scope it was 13 | *defined*, even if called before the actual definition in the source. 14 | 15 | foo(); // Works because foo was created before this code runs 16 | function foo() {} 17 | 18 | ### The `function` Expression 19 | 20 | var foo = function() {}; 21 | 22 | This example assigns the unnamed and *anonymous* function to the variable `foo`. 23 | 24 | foo; // 'undefined' 25 | foo(); // this raises a TypeError 26 | var foo = function() {}; 27 | 28 | Due to the fact that `var` is a declaration that hoists the variable name `foo` 29 | before the actual execution of the code starts, `foo` is already declared when 30 | the script gets executed. 31 | 32 | But since assignments only happen at runtime, the value of `foo` will default 33 | to [undefined](#core.undefined) before the corresponding code is executed. 34 | 35 | ### Named Function Expression 36 | 37 | Another special case is the assignment of named functions. 38 | 39 | var foo = function bar() { 40 | bar(); // Works 41 | } 42 | bar(); // ReferenceError 43 | 44 | Here, `bar` is not available in the outer scope, since the function only gets 45 | assigned to `foo`; however, inside of `bar`, it is available. This is due to 46 | how [name resolution](#function.scopes) in JavaScript works, the name of the 47 | function is *always* made available in the local scope of the function itself. 48 | 49 | -------------------------------------------------------------------------------- /doc/en/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "JavaScript Garden", 3 | "langTitle": "JavaScript Garden in English", 4 | "description": "A Guide to JavaScript's Quirks and Flaws.", 5 | "sections": [ 6 | { 7 | "title": "Intro", 8 | "dir": "intro", 9 | "articles": ["index"] 10 | }, 11 | { 12 | "title": "Objects", 13 | "dir": "object", 14 | "articles": [ 15 | "general", 16 | "prototype", 17 | "hasownproperty", 18 | "forinloop" 19 | ] 20 | }, 21 | { 22 | "title": "Functions", 23 | "dir": "function", 24 | "articles": [ 25 | "general", 26 | "this", 27 | "closures", 28 | "arguments", 29 | "constructors", 30 | "scopes" 31 | ] 32 | }, 33 | { 34 | "title": "Arrays", 35 | "dir": "array", 36 | "articles": [ 37 | "general", 38 | "constructor" 39 | ] 40 | }, 41 | { 42 | "title": "Types", 43 | "dir": "types", 44 | "articles": [ 45 | "equality", 46 | "typeof", 47 | "instanceof", 48 | "casting" 49 | ] 50 | }, 51 | { 52 | "title": "Core", 53 | "dir": "core", 54 | "articles": [ 55 | "eval", 56 | "undefined", 57 | "semicolon", 58 | "delete" 59 | ] 60 | }, 61 | { 62 | "title": "Other", 63 | "dir": "other", 64 | "articles": [ 65 | "timeouts" 66 | ] 67 | } 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /doc/en/intro/index.md: -------------------------------------------------------------------------------- 1 | ## Intro 2 | 3 | **JavaScript Garden** is a growing collection of documentation about the most 4 | quirky parts of the JavaScript programming language. It gives advice to 5 | avoid common mistakes and subtle bugs, as well as performance issues and bad 6 | practices, that non-expert JavaScript programmers may encounter on their 7 | endeavours into the depths of the language. 8 | 9 | JavaScript Garden does **not** aim to teach you JavaScript. Former knowledge 10 | of the language is strongly recommended in order to understand the topics covered 11 | in this guide. In order to learn the basics of the language, please head over to 12 | the excellent [guide][1] on the Mozilla Developer Network. 13 | 14 | ## The Authors 15 | 16 | This guide is the work of two lovely [Stack Overflow][2] users, [Ivo Wetzel][3] 17 | (Writing) and [Zhang Yi Jiang][4] (Design). 18 | 19 | It's currently maintained by [Tim Ruffles](http://truffles.me.uk). 20 | 21 | ## Contributors 22 | 23 | - Too many to list here, [see all contributors](https://github.com/BonsaiDen/JavaScript-Garden/graphs/contributors). 24 | 25 | 26 | ## Hosting 27 | 28 | JavaScript Garden is hosted on GitHub, but [Cramer Development][7] supports us 29 | with a mirror at [JavaScriptGarden.info][8]. 30 | 31 | ## License 32 | 33 | JavaScript Garden is published under the [MIT license][9] and hosted on 34 | [GitHub][10]. If you find errors or typos please [file an issue][11] or a pull 35 | request on the repository. You can also find us in the [JavaScript room][12] on 36 | Stack Overflow chat. 37 | 38 | [1]: https://developer.mozilla.org/en/JavaScript/Guide 39 | [2]: http://stackoverflow.com/ 40 | [3]: http://stackoverflow.com/users/170224/ivo-wetzel 41 | [4]: http://stackoverflow.com/users/313758/yi-jiang 42 | [5]: https://github.com/caio 43 | [6]: https://github.com/blixt 44 | [7]: http://cramerdev.com/ 45 | [8]: http://javascriptgarden.info/ 46 | [9]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE 47 | [10]: https://github.com/BonsaiDen/JavaScript-Garden 48 | [11]: https://github.com/BonsaiDen/JavaScript-Garden/issues 49 | [12]: http://chat.stackoverflow.com/rooms/17/javascript 50 | -------------------------------------------------------------------------------- /doc/en/object/forinloop.md: -------------------------------------------------------------------------------- 1 | ## The `for in` Loop 2 | 3 | Just like the `in` operator, the `for in` loop traverses the prototype 4 | chain when iterating over the properties of an object. 5 | 6 | > **Note:** The `for in` loop will **not** iterate over any properties that 7 | > have their `enumerable` attribute set to `false`; for example, the `length` 8 | > property of an array. 9 | 10 | // Poisoning Object.prototype 11 | Object.prototype.bar = 1; 12 | 13 | var foo = {moo: 2}; 14 | for(var i in foo) { 15 | console.log(i); // prints both bar and moo 16 | } 17 | 18 | Since it is not possible to change the behavior of the `for in` loop itself, it 19 | is necessary to filter out the unwanted properties inside the loop body; 20 | this is done using the [`hasOwnProperty`](#object.hasownproperty) method of 21 | `Object.prototype`. 22 | 23 | > **Note:** Since `for in` always traverses the complete prototype chain, it 24 | > will get slower with each additional layer of inheritance added to an object. 25 | 26 | ### Using `hasOwnProperty` for Filtering 27 | 28 | // still the foo from above 29 | for(var i in foo) { 30 | if (foo.hasOwnProperty(i)) { 31 | console.log(i); 32 | } 33 | } 34 | 35 | This version is the only correct one to use. Due to the use of `hasOwnProperty`, it 36 | will **only** print out `moo`. When `hasOwnProperty` is left out, the code is 37 | prone to errors in cases where the native prototypes - e.g. `Object.prototype` - 38 | have been extended. 39 | 40 | One widely used framework that extends `Object.prototype` is [Prototype][1]. 41 | When this framework is included, `for in` loops that do not use 42 | `hasOwnProperty` are guaranteed to break. 43 | 44 | ### In Conclusion 45 | 46 | It is recommended to **always** use `hasOwnProperty`. Assumptions should never 47 | be made about the environment the code is running in, or whether the native 48 | prototypes have been extended or not. 49 | 50 | [1]: http://www.prototypejs.org/ 51 | 52 | -------------------------------------------------------------------------------- /doc/en/object/hasownproperty.md: -------------------------------------------------------------------------------- 1 | ## `hasOwnProperty` 2 | 3 | To check whether an object has a property defined on *itself* and not somewhere 4 | on its [prototype chain](#object.prototype), it is necessary to use the 5 | `hasOwnProperty` method which all objects inherit from `Object.prototype`. 6 | 7 | > **Note:** It is **not** enough to check whether a property is `undefined`. The 8 | > property might very well exist, but its value just happens to be set to 9 | > `undefined`. 10 | 11 | `hasOwnProperty` is the only thing in JavaScript which deals with properties and 12 | does **not** traverse the prototype chain. 13 | 14 | // Poisoning Object.prototype 15 | Object.prototype.bar = 1; 16 | var foo = {goo: undefined}; 17 | 18 | foo.bar; // 1 19 | 'bar' in foo; // true 20 | 21 | foo.hasOwnProperty('bar'); // false 22 | foo.hasOwnProperty('goo'); // true 23 | 24 | Only `hasOwnProperty` will give the correct and expected result; this is 25 | essential when iterating over the properties of any object. There is **no** other 26 | way to exclude properties that are not defined on the object itself, but 27 | somewhere on its prototype chain. 28 | 29 | ### `hasOwnProperty` as a Property 30 | 31 | JavaScript does not protect the property name `hasOwnProperty`; thus, if the 32 | possibility exists that an object might have a property with this name, it is 33 | necessary to use an *external* `hasOwnProperty` to get correct results. 34 | 35 | var foo = { 36 | hasOwnProperty: function() { 37 | return false; 38 | }, 39 | bar: 'Here be dragons' 40 | }; 41 | 42 | foo.hasOwnProperty('bar'); // always returns false 43 | 44 | // Use another Object's hasOwnProperty and call it with 'this' set to foo 45 | ({}).hasOwnProperty.call(foo, 'bar'); // true 46 | 47 | // It's also possible to use hasOwnProperty from the Object 48 | // prototype for this purpose 49 | Object.prototype.hasOwnProperty.call(foo, 'bar'); // true 50 | 51 | 52 | ### In Conclusion 53 | 54 | Using `hasOwnProperty` is the **only** reliable method to check for the 55 | existence of a property on an object. It is recommended that `hasOwnProperty` 56 | is used in **every** [`for in` loop](#object.forinloop) to avoid errors from 57 | extended native [prototypes](#object.prototype). 58 | 59 | -------------------------------------------------------------------------------- /doc/en/types/casting.md: -------------------------------------------------------------------------------- 1 | ## Type Casting 2 | 3 | JavaScript is a *weakly typed* language, so it will apply *type coercion* 4 | **wherever** possible. 5 | 6 | // These are true 7 | new Number(10) == 10; // Number.toString() is converted 8 | // back to a number 9 | 10 | 10 == '10'; // Strings gets converted to Number 11 | 10 == '+10 '; // More string madness 12 | 10 == '010'; // And more 13 | isNaN(null) == false; // null converts to 0 14 | // which of course is not NaN 15 | 16 | // These are false 17 | 10 == 010; 18 | 10 == '-10'; 19 | 20 | > **ES5 Note:** Number literals that start with a `0` are interpreted as octal 21 | > (Base 8). Octal support for these has been **removed** in ECMAScript 5 strict 22 | > mode. 23 | 24 | To avoid the issues above, use of the [strict equal operator](#types.equality) 25 | is **highly** recommended. Although this avoids a lot of common pitfalls, there 26 | are still many further issues that arise from JavaScript's weak typing system. 27 | 28 | ### Constructors of Built-In Types 29 | 30 | The constructors of the built in types like `Number` and `String` behave 31 | differently when being used with the `new` keyword and without it. 32 | 33 | new Number(10) === 10; // False, Object and Number 34 | Number(10) === 10; // True, Number and Number 35 | new Number(10) + 0 === 10; // True, due to implicit conversion 36 | 37 | Using a built-in type like `Number` as a constructor will create a new `Number` 38 | object, but leaving out the `new` keyword will make the `Number` function behave 39 | like a converter. 40 | 41 | In addition, passing literals or non-object values will result in even more 42 | type coercion. 43 | 44 | The best option is to cast to one of the three possible types **explicitly**. 45 | 46 | ### Casting to a String 47 | 48 | '' + 10 === '10'; // true 49 | 50 | By prepending an empty string, a value can easily be cast to a string. 51 | 52 | ### Casting to a Number 53 | 54 | +'10' === 10; // true 55 | 56 | Using the **unary** plus operator, it is possible to cast to a number. 57 | 58 | ### Casting to a Boolean 59 | 60 | By using the **not** operator twice, a value can be converted a boolean. 61 | 62 | !!'foo'; // true 63 | !!''; // false 64 | !!'0'; // true 65 | !!'1'; // true 66 | !!'-1' // true 67 | !!{}; // true 68 | !!true; // true 69 | 70 | 71 | -------------------------------------------------------------------------------- /doc/en/types/instanceof.md: -------------------------------------------------------------------------------- 1 | ## The `instanceof` Operator 2 | 3 | The `instanceof` operator compares the constructors of its two operands. It is 4 | only useful when comparing custom made objects. Used on built-in types, it is 5 | nearly as useless as the [typeof operator](#types.typeof). 6 | 7 | ### Comparing Custom Objects 8 | 9 | function Foo() {} 10 | function Bar() {} 11 | Bar.prototype = new Foo(); 12 | 13 | new Bar() instanceof Bar; // true 14 | new Bar() instanceof Foo; // true 15 | 16 | // This just sets Bar.prototype to the function object Foo, 17 | // but not to an actual instance of Foo 18 | Bar.prototype = Foo; 19 | new Bar() instanceof Foo; // false 20 | 21 | ### Using `instanceof` with Native Types 22 | 23 | new String('foo') instanceof String; // true 24 | new String('foo') instanceof Object; // true 25 | 26 | 'foo' instanceof String; // false 27 | 'foo' instanceof Object; // false 28 | 29 | One important thing to note here is that `instanceof` does not work on objects 30 | that originate from different JavaScript contexts (e.g. different documents 31 | in a web browser), since their constructors will not be the exact same object. 32 | 33 | ### In Conclusion 34 | 35 | The `instanceof` operator should **only** be used when dealing with custom made 36 | objects that originate from the same JavaScript context. Just like the 37 | [`typeof`](#types.typeof) operator, every other use of it should be **avoided**. 38 | 39 | -------------------------------------------------------------------------------- /doc/es/array/constructor.md: -------------------------------------------------------------------------------- 1 | ## El constructor `Array` 2 | 3 | Desde el constructor `Array` es ambiguo en la forma en que ocupa sus párametros, 4 | es recomendable siempre el uso de arrays literales - la notación `[]` - 5 | cuando se crean nuevos arrays. 6 | 7 | [1, 2, 3]; // Resultado: [1, 2, 3] 8 | new Array(1, 2, 3); // Resultado: [1, 2, 3] 9 | 10 | [3]; // Resultado: [3] 11 | new Array(3); // Resultado: [] 12 | new Array('3') // Resultado: ['3'] 13 | 14 | En casos cuando sólo hay un argumento pasado al constructor del `Array`, 15 | y que el argumento es un `Número`, el contructor devolverá un array *disperso* 16 | con la propiedad `length` establecida al valor del argumento. Esto debe señalarse 17 | que la propiedad `length` **sólo** del nuevo array se establecerá de esa manera, 18 | los índices reales de la matriz no se iniciará. 19 | 20 | var arr = new Array(3); 21 | arr[1]; // undefined 22 | 1 in arr; // falso, el índice no se ha establecido 23 | 24 | El comportamiento de poder establecer la longitud de un array inicial sólo es útil 25 | en algunos casos array, como la repetición de una cadena, en la que se evita el uso 26 | del código de `bucle for`. 27 | 28 | new Array(count + 1).join(stringToRepeat); 29 | 30 | ### En conclusión 31 | 32 | El uso de un constructor `Array` debe ser devuelto como sea posible. 33 | Los literales son definitivamente preferidos. Estos son más cortos y tienen una 34 | sintaxis más limpia; por lo tanto, también se incrementa la legibilidad del código. 35 | 36 | -------------------------------------------------------------------------------- /doc/es/core/eval.md: -------------------------------------------------------------------------------- 1 | ## ¿Por qué no usar `eval`? 2 | 3 | La función `eval` ejecuta un string como código JavaScript en el ámbito local. 4 | 5 | var foo = 1; 6 | function test() { 7 | var foo = 2; 8 | eval('foo = 3'); 9 | return foo; 10 | } 11 | test(); // 3 12 | foo; // 1 13 | 14 | Pero `eval` sólo ejecutará en ámbito local cuando es llamado **directamente** *y* 15 | el nombre de la función llamada es `eval`. 16 | 17 | var foo = 1; 18 | function test() { 19 | var foo = 2; 20 | var bar = eval; 21 | bar('foo = 3'); 22 | return foo; 23 | } 24 | test(); // 2 25 | foo; // 3 26 | 27 | El uso de `eval` debe evitarse **a toda costa**. El 99.9% de su "uso" puede 28 | lograrse **sin** su uso.. 29 | 30 | ### `eval` disfrazado 31 | 32 | Las funciones de [tiempo de espera](#other.timeouts) `setTimeout` y `setInterval` pueden 33 | tomar un string como primer argumento. En este caso, el string **siempre** se ejecutará en 34 | el ámbito global ya que `eval` no ha sido llamado directamente. 35 | 36 | ### Problemas de seguridad 37 | 38 | `eval` es también un problema de seguridad ya que ejecuta **cualquier** código enviado, 39 | y **nunca** debe usarse con strings que no se conozcan o tengan un origen no confiable. 40 | 41 | ### En conclusión 42 | 43 | `eval` nunca debe ser usado, cualquier código que haga uso del mismo debe ser cuestionado 44 | en su funcionamiento, rendimiento y seguridad. En caso de que se necesite trabajar con 45 | `eval`, el diseño ha de ser cuestionado y **no** debe utilizarse en primer lugar, se 46 | debe usar un *mejor diseño*, que no requiera el uso de `eval`. 47 | 48 | -------------------------------------------------------------------------------- /doc/es/function/general.md: -------------------------------------------------------------------------------- 1 | ## La declaración de funciones y expresiones 2 | 3 | Las funciones en JavaScript son las primeras clases de objetos. Esto significa que se 4 | puede pasar como cualquier otro valor. Un uso común de está característica es pasar de 5 | una *función anónima* a otra, posiblemente una función asíncrona. Esto se conoce como `callback`. 6 | 7 | ### La declaración `function` 8 | 9 | function foo() {} 10 | 11 | La función anterior se [carga](#function.scopes) así mismo antes de iniciar la ejecución del 12 | programa; por lo tanto, está disponible en *todo* el scope (ámbito) de la aplicación 13 | donde se ha *definido*, aunque hubiera sido llamado antes de definirse en el código. 14 | 15 | foo(); // Funciona porque foo ha sido creado antes que este código se ejecute 16 | function foo() {} 17 | 18 | ### La expresión `function` 19 | 20 | var foo = function() {}; 21 | 22 | Este ejemplo asigna una función sin nombre y anónima a la variable `foo`. 23 | 24 | foo; // 'undefined' 25 | foo(); // Lanza TypeError 26 | var foo = function() {}; 27 | 28 | Debido a la declaración de `var`, que carga el nombre de la variable `foo` antes 29 | de la ejecución real del inicio del código, `foo` ya estará definidido cuando se 30 | ejecute el script. 31 | 32 | Pero se asigna sólo si ocurre en tiempo de ejecución, el valor de `foo` de forma 33 | predetermina es [undefined](#core.undefined) antes de que el código se ejecute. 34 | 35 | ### Expresión nombre de función 36 | 37 | Otro caso especial de asignación de nombre de funciones. 38 | 39 | var foo = function bar() { 40 | bar(); // Funciona 41 | } 42 | bar(); // ReferenceError 43 | 44 | Aquí `bar` no está disponible en el ámbito externo (scope), ya que la función sólo es 45 | asignada a `foo`; Sin embargo, dentro de `bar` si está disponible. Esto se debe a la forma 46 | en como trabaja la [resolución de nombres](#function.scopes) en JavaScript, el nombre de 47 | la función esta *siempre* disponible en el ámbito local de la propia función. 48 | 49 | -------------------------------------------------------------------------------- /doc/es/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Jardín de JavaScript", 3 | "langTitle": "JavaScript Garden es Español", 4 | "description": "Una guía sobre lo peculiar y defectos de JavaScript.", 5 | "sections": [ 6 | { 7 | "title": "Introducción", 8 | "dir": "intro", 9 | "articles": ["index"] 10 | }, 11 | { 12 | "title": "Objetos", 13 | "dir": "object", 14 | "articles": [ 15 | "general", 16 | "prototype", 17 | "hasownproperty", 18 | "forinloop" 19 | ] 20 | }, 21 | { 22 | "title": "Funciones", 23 | "dir": "function", 24 | "articles": [ 25 | "general", 26 | "this", 27 | "closures", 28 | "arguments", 29 | "constructors", 30 | "scopes" 31 | ] 32 | }, 33 | { 34 | "title": "Arrays", 35 | "dir": "array", 36 | "articles": [ 37 | "general", 38 | "constructor" 39 | ] 40 | }, 41 | { 42 | "title": "Types", 43 | "dir": "types", 44 | "articles": [ 45 | "equality", 46 | "typeof", 47 | "instanceof", 48 | "casting" 49 | ] 50 | }, 51 | { 52 | "title": "Núcleo", 53 | "dir": "core", 54 | "articles": [ 55 | "eval", 56 | "undefined", 57 | "semicolon" 58 | ] 59 | }, 60 | { 61 | "title": "Otros", 62 | "dir": "other", 63 | "articles": [ 64 | "timeouts" 65 | ] 66 | } 67 | ] 68 | } 69 | -------------------------------------------------------------------------------- /doc/es/intro/index.md: -------------------------------------------------------------------------------- 1 | ## Introducción 2 | 3 | **El Jardín de JavaScript** es una guía de documentación acerca de las 4 | partes más peculiares de este lenguaje de programación. Brinda consejos para evitar 5 | los errores más comunes y sutiles, así como problemas de rendimiento y de malas 6 | prácticas que los programadores menos experimentados en JavaScript pueden resolver 7 | en sus esfuerzos por profundizar en el lenguaje. 8 | 9 | El Jardín de JavaScript **no** prentende enseñar JavaScript. 10 | Se recomienda un conocimiento sobre el lenguaje para entender los temas tratados en 11 | esta guía. Con el fin de aprender los conceptos básicos del lenguaje, por favor 12 | diríjase a la excelente [guía][1] de los desarrolladores de Mozilla. 13 | 14 | ## Los autores 15 | 16 | Esta guía es el trabajo de dos encantadores usuarios del foro Stack Overflow, 17 | [Ivo Wetzel][3] (Escrito) y [Zhang Yi Jiang][4] (Diseño). 18 | 19 | ## Colaboradores 20 | 21 | - [Colaboradores](https://github.com/BonsaiDen/JavaScript-Garden/graphs/contributors) 22 | 23 | ## Hosting 24 | 25 | JavaScript Garden es hospedado en GitHub, además [Cramer Development][7] nos apoya 26 | con un sitio espejo en [JavaScriptGarden.info][8]. 27 | 28 | ## Licencia 29 | 30 | El Jardín de JavaScript es publicado bajo la [licencia MIT][9] y es hospedado en 31 | [GitHub][10]. Si encuentra algún error o errata por favor publique [una incidencia][11] o 32 | envie un pull request a nuestro repositorio. También nos puede encontrar en la 33 | [sala de chat de JavaScript][12] en Stack Overflow. 34 | 35 | [1]: https://developer.mozilla.org/en/JavaScript/Guide 36 | [2]: http://stackoverflow.com/ 37 | [3]: http://stackoverflow.com/users/170224/ivo-wetzel 38 | [4]: http://stackoverflow.com/users/313758/yi-jiang 39 | [5]: https://github.com/caio 40 | [6]: https://github.com/blixt 41 | [7]: http://cramerdev.com/ 42 | [8]: http://javascriptgarden.info/ 43 | [9]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE 44 | [10]: https://github.com/BonsaiDen/JavaScript-Garden 45 | [11]: https://github.com/BonsaiDen/JavaScript-Garden/issues 46 | [12]: http://chat.stackoverflow.com/rooms/17/javascript 47 | -------------------------------------------------------------------------------- /doc/es/object/forinloop.md: -------------------------------------------------------------------------------- 1 | ## El bucle `for in` 2 | 3 | Al igual que el operador `in`, el bucle `for in` también recorre sobre la 4 | cadena de prototipo cuando este se repite en una iteración en las propiedades de un objeto. 5 | 6 | > **Nota:** El bucle `for in` **no** se repetirá en cualquier propiedad que 7 | > tenga atributos `enumerables` asignados a `false`; por ejemplo, la propiedad 8 | > `length` de un array. 9 | 10 | // Envenenamiento en Object.prototype 11 | Object.prototype.bar = 1; 12 | 13 | var foo = {moo: 2}; 14 | for(var i in foo) { 15 | console.log(i); // Imprime ambos bar y moo 16 | } 17 | 18 | Dado que no es posible cambiar el comportamiento del bucle `for in` en sí mismo, es 19 | necesario filtrar las propiedades internas no deseadas dentro del bucle, 20 | esto se hace mediante el uso del método [`hasOwnProperty`](#object.hasownproperty) del 21 | `Object.prototype`. 22 | 23 | > **Nota:** Dado que `for in` siempre recorre por completo la cadena de prototipo, 24 | > este se pondrá más lento con cada capa adicional que un objeto herede. 25 | 26 | ### Usando `hasOwnProperty` para filtrado 27 | 28 | // Aún es el foo del código de arriba 29 | for(var i in foo) { 30 | if (foo.hasOwnProperty(i)) { 31 | console.log(i); 32 | } 33 | } 34 | 35 | Está versión es la única forma correcta de uso. Esto se debe **sólo** al uso de 36 | `hasOwnProperty` que imprimirá `moo`. Cuando `hasOwnProperty` se omita, el código es 37 | propenso a errores en los casos de prototipos nativos - ej. `Object.prototype` - 38 | se ha extendedido. 39 | 40 | Uno de los frameworks más usado que implementa estas funcionalidades es [Prototype][1]. Cuando el 41 | framework es incluido, el bucle `for in` que no utilicen `hasOwnProperty` no podrá garantizar que 42 | se interrumpa. 43 | 44 | ### En conclusión 45 | 46 | Se recomienda utilizar **siempre** el uso de `hasOwnProperty`. Nunca debe suponer 47 | ningún entorno donde el código se ejecute, o si los prototipos 48 | nativos han sido extendidos o no. 49 | 50 | [1]: http://www.prototypejs.org/ 51 | 52 | -------------------------------------------------------------------------------- /doc/es/object/hasownproperty.md: -------------------------------------------------------------------------------- 1 | ## `hasOwnProperty` 2 | 3 | Con el fin de comprobar si un objeto posee una propiedad definida *en sí* mismo y **no** 4 | en algún lugar de su [cadena de prototipo](#object.prototype), es necesario utilizar 5 | el método `hasOwnProperty` ya que todos los objetos herendan de `Object.prototype`. 6 | 7 | > **Nota:** **No** es suficiente con comprobar si una propiedad está `definida`. 8 | > La propiedad bien podría existir, pero su valor sólo pasa a ser definido como 9 | > `undefined`. 10 | 11 | `hasOwnProperty` es la única utilidad en JavaScript que se ocupa de las propiedades 12 | y **no** las salta en la cadena de prototipo. 13 | 14 | // Envenenamiento en Object.prototype 15 | Object.prototype.bar = 1; 16 | var foo = {goo: undefined}; 17 | 18 | foo.bar; // 1 19 | 'bar' in foo; // true 20 | 21 | foo.hasOwnProperty('bar'); // false 22 | foo.hasOwnProperty('goo'); // true 23 | 24 | Sólo `hasOwnProperty` retornará el resultado correcto y esperado, esto es 25 | ensencial cuando se repite una iteración en las propiedades de cualquier objeto. No hay 26 | otra maner de excluir las propiedades que no están definidas en el mismo objeto, pero 27 | en alguna parte de su cadena de prototipo si. 28 | 29 | ### `hasOwnProperty` como propiedad 30 | 31 | JavaScript **no** protege el nombre de la propiedad `hasOwnProperty`; de este modo, si existe 32 | la posibilidad de que un objeto tenga una propiedad con el mismo nombre, es necesario utilizar 33 | `hasOwnProperty` como propiedad *externa* con el fin de obtener resultados correctos. 34 | 35 | var foo = { 36 | hasOwnProperty: function() { 37 | return false; 38 | }, 39 | bar: 'Here be dragons' 40 | }; 41 | 42 | foo.hasOwnProperty('bar'); // siempre devolverá false 43 | 44 | // Utilice otro objeto con hasOwnProperty y llamelo con 'this' para asignarlo a foo 45 | ({}).hasOwnProperty.call(foo, 'bar'); // true 46 | 47 | ### En conclusión 48 | 49 | Cuando se necesite comprobar la existencia de una propiedad en un objeto, `hasOwnProperty` es 50 | el **único** método para hacerlo. También se recomienda el uso de `hasOwnProperty` como 51 | parte de un [bucle `for in`](#object.forinloop), esto evitará errores desde 52 | extenciones de [prototipos](#object.prototype) nativos. 53 | 54 | -------------------------------------------------------------------------------- /doc/es/types/casting.md: -------------------------------------------------------------------------------- 1 | ## Type Casting 2 | 3 | JavaScript is a *weakly typed* language, so it will apply *type coercion* 4 | **wherever** possible. 5 | 6 | // These are true 7 | new Number(10) == 10; // Number.toString() is converted 8 | // back to a number 9 | 10 | 10 == '10'; // Strings gets converted to Number 11 | 10 == '+10 '; // More string madness 12 | 10 == '010'; // And more 13 | isNaN(null) == false; // null converts to 0 14 | // which of course is not NaN 15 | 16 | // These are false 17 | 10 == 010; 18 | 10 == '-10'; 19 | 20 | > **ES5 Note:** Number literals that start with a `0` are interpreted as octal 21 | > (Base 8). Octal support for these has been **removed** in ECMAScript 5 strict 22 | > mode. 23 | 24 | In order to avoid the above, use of the [strict equal operator](#types.equality) 25 | is **highly** recommended. Although this avoids a lot of common pitfalls, there 26 | are still many further issues that arise from JavaScript's weak typing system. 27 | 28 | ### Constructors of Built-In Types 29 | 30 | The constructors of the built in types like `Number` and `String` behave 31 | differently when being used with the `new` keyword and without it. 32 | 33 | new Number(10) === 10; // False, Object and Number 34 | Number(10) === 10; // True, Number and Number 35 | new Number(10) + 0 === 10; // True, due to implicit conversion 36 | 37 | Using a built-in type like `Number` as a constructor will create a new `Number` 38 | object, but leaving out the `new` keyword will make the `Number` function behave 39 | like a converter. 40 | 41 | In addition, having literals or non-object values in there will result in even 42 | more type coercion. 43 | 44 | The best option is to cast to one of the three possible types **explicitly**. 45 | 46 | ### Casting to a String 47 | 48 | '' + 10 === '10'; // true 49 | 50 | By prepending an empty string, a value can easily be casted to a string. 51 | 52 | ### Casting to a Number 53 | 54 | +'10' === 10; // true 55 | 56 | Using the **unary** plus operator, it is possible to cast to a number. 57 | 58 | ### Casting to a Boolean 59 | 60 | By using the **not** operator twice, a value can be converted a boolean. 61 | 62 | !!'foo'; // true 63 | !!''; // false 64 | !!'0'; // true 65 | !!'1'; // true 66 | !!'-1' // true 67 | !!{}; // true 68 | !!true; // true 69 | 70 | 71 | -------------------------------------------------------------------------------- /doc/es/types/instanceof.md: -------------------------------------------------------------------------------- 1 | ## The `instanceof` Operator 2 | 3 | The `instanceof` operator compares the constructors of its two operands. It is 4 | only useful when comparing custom made objects. Used on built-in types, it is 5 | nearly as useless as the [typeof operator](#types.typeof). 6 | 7 | ### Comparing Custom Objects 8 | 9 | function Foo() {} 10 | function Bar() {} 11 | Bar.prototype = new Foo(); 12 | 13 | new Bar() instanceof Bar; // true 14 | new Bar() instanceof Foo; // true 15 | 16 | // This just sets Bar.prototype to the function object Foo 17 | // But not to an actual instance of Foo 18 | Bar.prototype = Foo; 19 | new Bar() instanceof Foo; // false 20 | 21 | ### Using `instanceof` with Native Types 22 | 23 | new String('foo') instanceof String; // true 24 | new String('foo') instanceof Object; // true 25 | 26 | 'foo' instanceof String; // false 27 | 'foo' instanceof Object; // false 28 | 29 | One important thing to note here is that `instanceof` does not work on objects 30 | that originate from different JavaScript contexts (e.g. different documents 31 | in a web browser), since their constructors will not be the exact same object. 32 | 33 | ### In Conclusion 34 | 35 | The `instanceof` operator should **only** be used when dealing with custom made 36 | objects that originate from the same JavaScript context. Just like the 37 | [`typeof`](#types.typeof) operator, every other use of it should be **avoided**. 38 | 39 | -------------------------------------------------------------------------------- /doc/fi/array/constructor.md: -------------------------------------------------------------------------------- 1 | ## `Array`-konstruktori 2 | 3 | `Array`-oletuskonstruktorin käytös ei ole lainkaan yksiselitteistä. Tämän vuoksi suositellaankin, että konstruktorin sijasta käytetään literaalinotaatiota `[]`. 4 | 5 | [1, 2, 3]; // Tulos: [1, 2, 3] 6 | new Array(1, 2, 3); // Tulos: [1, 2, 3] 7 | 8 | [3]; // Tulos: [3] 9 | new Array(3); // Tulos: [] 10 | new Array('3') // Tulos: ['3'] 11 | 12 | Mikäli `Array`-konstruktorille annetaan vain yksi argumentti ja se on tyypiltään `Number`, konstruktori palauttaa uuden *harvan* taulukon, jonka `length`-attribuutti on asetettu annetun numeron mukaisesti. On tärkeää huomata, että **ainoastaan** `length` asetetaan tällä tavoin, todellisia taulukon indeksejä ei alusteta. 13 | 14 | var arr = new Array(3); 15 | arr[1]; // undefined 16 | 1 in arr; // false, indeksiä ei ole alustettu 17 | 18 | Tämä on käytännöllistä vain harvoin, kuten merkkijonon toiston tapauksessa. Tällöin voidaan välttää `for-luupin` käyttämistä. 19 | 20 | new Array(count + 1).join(stringToRepeat); 21 | 22 | ### Yhteenveto 23 | 24 | `Array`-konstruktorin käyttöä tulee käyttää niin paljon kuin suinkin mahdollista. Sen sijaan on suositeltavaa käyttää literaalinotaatiota. Literaalit ovat lyhyempiä ja niiden syntaksi on selkeämpi. Tämän lisäksi ne tekevät koodista luettavampaa. 25 | 26 | -------------------------------------------------------------------------------- /doc/fi/array/general.md: -------------------------------------------------------------------------------- 1 | ## Taulukon iterointi ja attribuutit 2 | 3 | Vaikka taulukot ovatkin JavaScript-olioita, niiden tapauksessa ei välttämättä kannata käyttää [`for in loop`](#object.forinloop)-luuppia. Pikemminkin tätä tapaa tulee **välttää**. 4 | 5 | > **Huomio:** JavaScript-taulukot **eivät ole** *assosiatiivisia*. JavaScriptissa ainoastaan [oliot](#object.general) ovat avain-arvo-mappauksia. On huomattavaa, että toisin kuin assosiatiiviset taulukot, oliot **eivät** säilytä järjestystään. 6 | 7 | `for in`-luuppi iteroi kaikki prototyyppiketjun sisältämät ominaisuudet. Tämän vuoksi tulee käyttää erityistä [`hasOwnProperty`](#object.hasownproperty)-metodia, jonka avulla voidaan taata, että käsitellään oikeita ominaisuuksia. Tästä johtuen iteroint on jo lähtökohtaisesti jopa **kaksikymmentä** kertaa hitaampaa kuin normaalin `for`-luupin tapauksessa. 8 | 9 | ### Iterointi 10 | 11 | Taulukkojen tapauksessa paras suorituskyky voidaan saavuttaa käyttämällä klassista `for`-luuppia. 12 | 13 | var list = [1, 2, 3, 4, 5, ...... 100000000]; 14 | for(var i = 0, l = list.length; i < l; i++) { 15 | console.log(list[i]); 16 | } 17 | 18 | Edelliseen esimerkkiin liittyy yksi mutta. Listan pituus on tallennettu välimuistiin erikseen käyttämällä `l = list.length`-lauseketta. 19 | 20 | Vaikka `length`-ominaisuus määritelläänkin taulukossa itsessään, arvon hakeminen sisältää ylimääräisen operaation. Uudehkot JavaScript-ympäristöt **saattavat** optimoida tämän tapauksen. Tästä ei kuitenkaan ole mitään takeita. 21 | 22 | Todellisuudessa välimuistin käytön pois jättäminen voi hidastaa luuppia jopa puolella. 23 | 24 | ### `length`-ominaisuus 25 | 26 | `length`-ominaisuuden *getteri* palauttaa yksinkertaisesti taulukon sisältämien alkioiden määrän. Sen *setteriä* voidaan käyttää taulukon **typistämiseen**. 27 | 28 | var foo = [1, 2, 3, 4, 5, 6]; 29 | foo.length = 3; 30 | foo; // [1, 2, 3] 31 | 32 | foo.length = 6; 33 | foo; // [1, 2, 3] 34 | 35 | Pituuden pienemmäksi asettaminen typistää taulukkoa. Sen kasvattaminen ei kuitenkaan vaikuta mitenkään. 36 | 37 | ### Yhteenveto 38 | 39 | Parhaan suorituskyvyn kannalta on parhainta käyttää tavallista `for`-luuppia ja tallentaa `length`-ominaisuus välimuistiin. `for in`-luupin käyttö taulukon tapauksessa on merkki huonosti kirjoitetusta koodista, joka on altis bugeille ja heikolle suorituskyvylle. 40 | 41 | -------------------------------------------------------------------------------- /doc/fi/core/eval.md: -------------------------------------------------------------------------------- 1 | ## Miksi `eval`-funktiota tulee välttää 2 | 3 | `eval` suorittaa JavaScript-koodia sisältävän merkkijonon paikallisessa näkyvyysalueessa. 4 | 5 | var foo = 1; 6 | function test() { 7 | var foo = 2; 8 | eval('foo = 3'); 9 | return foo; 10 | } 11 | test(); // 3 12 | foo; // 1 13 | 14 | `eval` suoritetaan paikallisessa näkyvyysalueessa ainoastaan kun sitä kutsutaan **suorasti** *ja* kutsutun funktion nimi on todellisuudessa `eval`. 15 | 16 | var foo = 1; 17 | function test() { 18 | var foo = 2; 19 | var bar = eval; 20 | bar('foo = 3'); 21 | return foo; 22 | } 23 | test(); // 2 24 | foo; // 3 25 | 26 | `eval`-funktion käyttöä tulee välttää **ehdottomasti**. 99.9% sen "käyttötapauksista" voidaan toteuttaa **ilman** sitä. 27 | 28 | ### Piilotettu `eval` 29 | 30 | [Aikakatkaisufunktiot](#other.timeouts) `setTimeout` and `setInterval` voivat kumpikin ottaa merkkijonon ensimmäisenä argumenttinaan. Kyseinen merkkijono suoritetaan **aina** globaalissa näkyvyysalueessa, koska tuolloin `eval`-funktiota kutsutaan epäsuorasti. 31 | 32 | ### Turvallisuusongelmat 33 | 34 | `eval` on myös turvallisuusongelma. Se suorittaa **minkä tahansa** sille annetun koodin. Tämän vuoksi sitä ei tule **ikinä** käyttää tuntemattomasta tai epäluotttavasta lähteestä tulevien merkkijonojen kanssa. 35 | 36 | ### Yhteenveto 37 | 38 | `eval`-funktiota ei pitäisi käyttää koskaan. Mikä tahansa sitä käyttävä koodi on kyseenalaista sekä suorituskyvyn että turvallisuuden suhteen. Mikäli jokin tarvitsee `eval`-funktiota toimiakseen, tulee sen suunnittelutapa kyseenalaistaa. Tässä tapauksessa on parempi suunnitella toisin ja välttää `eval`-funktion käyttöä. 39 | 40 | -------------------------------------------------------------------------------- /doc/fi/function/general.md: -------------------------------------------------------------------------------- 1 | ## Funktiomääreet ja lausekkeet 2 | 3 | JavaScriptissä funktiot ovat ensimmäisen luokan olioita. Tämä tarkoittaa sitä, että niitä voidaan välittää kuten muitakin arvoja. Usein tätä käytetään takaisinkutsuissa käyttämällä *nimettömiä, mahdollisesti asynkronisia funktioita*. 4 | 5 | ### `function`-määre 6 | 7 | function foo() {} 8 | 9 | Yllä oleva funktio [hilataan](#function.scopes) ennen ohjelman suorituksen alkua. Se näkyy *kaikkialle* näkyvyysalueessaan, jossa se on *määritelty*. Tämä on totta jopa silloin, jos sitä kutsutaan ennen määrittelyään. 10 | 11 | foo(); // Toimii, koska foo on luotu ennen kuin koodi suoritetaan 12 | function foo() {} 13 | 14 | ### `function`-lauseke 15 | 16 | var foo = function() {}; 17 | 18 | Tämä esimerkki asettaa nimeämättömän ja *nimettömän* funktion muuttujan `foo` arvoksi. 19 | 20 | foo; // 'undefined' 21 | foo(); // tämä palauttaa TypeError-virheen 22 | var foo = function() {}; 23 | 24 | `var` on määre. Tästä johtuen se hilaa muuttujanimen `foo` ennen kuin itse koodia ryhdytään suorittamaan. 25 | 26 | Sijoituslauseet suoritetaan *vasta* kun niihin saavutaan. Tästä johtuen `foo` saa arvokseen [undefined](#core.undefined) ennen kuin varsinaista sijoitusta päästään suorittamaan. 27 | 28 | ### Nimetty funktiolauseke 29 | 30 | Nimettyjen funktioiden sijoitus tarjoaa toisen erikoistapauksen. 31 | 32 | var foo = function bar() { 33 | bar(); // Toimii 34 | } 35 | bar(); // ReferenceError 36 | 37 | Tässä tapauksessa `bar` ei ole saatavilla ulommalla näkyvyysalueessa. Tämä johtuu siitä, että se on sidottu `foo`:n sisälle. Tämä johtuu siitä, kuinka näkyvyysalueet ja niihin kuuluvat jäsenet [tulkitaan](#function.scopes). Funktion nimi on *aina* saatavilla sen paikallisessa näkyvyysalueessa itsessään. 38 | 39 | -------------------------------------------------------------------------------- /doc/fi/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "JavaScript-puutarha", 3 | "langTitle": "JavaScript-puutarha suomeksi", 4 | "description": "Opas JavaScriptin outouksiin ja vikoihin ", 5 | "sections": [ 6 | { 7 | "title": "Johdanto", 8 | "dir": "intro", 9 | "articles": [ 10 | "authors", 11 | "contributors", 12 | "translators", 13 | "license" 14 | ] 15 | }, 16 | { 17 | "title": "Oliot", 18 | "dir": "object", 19 | "articles": [ 20 | "general", 21 | "prototype", 22 | "hasownproperty", 23 | "forinloop" 24 | ] 25 | }, 26 | { 27 | "title": "Funktiot", 28 | "dir": "function", 29 | "articles": [ 30 | "general", 31 | "this", 32 | "closures", 33 | "arguments", 34 | "constructors", 35 | "scopes" 36 | ] 37 | }, 38 | { 39 | "title": "Taulukot", 40 | "dir": "array", 41 | "articles": [ 42 | "general", 43 | "constructor" 44 | ] 45 | }, 46 | { 47 | "title": "Tyypit", 48 | "dir": "types", 49 | "articles": [ 50 | "equality", 51 | "typeof", 52 | "instanceof", 53 | "casting" 54 | ] 55 | }, 56 | { 57 | "title": "Ydin", 58 | "dir": "core", 59 | "articles": [ 60 | "eval", 61 | "undefined", 62 | "semicolon" 63 | ] 64 | }, 65 | { 66 | "title": "Muuta", 67 | "dir": "other", 68 | "articles": [ 69 | "timeouts" 70 | ] 71 | } 72 | ] 73 | } 74 | -------------------------------------------------------------------------------- /doc/fi/intro/authors.md: -------------------------------------------------------------------------------- 1 | ## Tekijät 2 | 3 | Tämä opas pohjautuu kahden mukavan [Stack Overflow][3] käyttäjän työhön. He ovat [Ivo Wetzel][1] (kirjoittaminen) sekä [Zhang Yi Jiang][2] (ulkoasu). 4 | 5 | [1]: http://stackoverflow.com/users/170224/ivo-wetzel 6 | [2]: http://stackoverflow.com/users/313758/yi-jiang 7 | [3]: http://stackoverflow.com/ 8 | 9 | -------------------------------------------------------------------------------- /doc/fi/intro/contributors.md: -------------------------------------------------------------------------------- 1 | ## Osallistujat 2 | 3 | - [Osallistujat](https://github.com/BonsaiDen/JavaScript-Garden/graphs/contributors) 4 | -------------------------------------------------------------------------------- /doc/fi/intro/index.md: -------------------------------------------------------------------------------- 1 | ## Johdanto 2 | 3 | **JavaScript-puutarha** sisältää kasvavan kokoelman JavaScriptin ongelmallisiin osiin liittyvää dokumentaatiota. Se tarjoaa vinkkejä, joiden avulla välttää yleisiä virheitä, bugeja sekä suorituskykyongelmia ja huonoja tapoja, joita aloittelevat JavaScript-ohjelmoijat saattavat kohdata kieleen tutustuessaan. 4 | 5 | JavaScript-puutarha **ei** tähtää itse kielen opettamiseen. On suositeltavaa, että lukija ymmärtää jo kielen perusteet ennen itse tekstin lukemista. Nämä perusteet voit oppia esimerkiksi perehtymällä Mozilla Developer Networkin erinomaiseen [oppaaseen][1]. 6 | 7 | [1]: https://developer.mozilla.org/en/JavaScript/Guide 8 | 9 | -------------------------------------------------------------------------------- /doc/fi/intro/license.md: -------------------------------------------------------------------------------- 1 | ## Lisenssi 2 | 3 | JavaScript-puutarha on julkaistu [MIT-lisenssin][1]-alaisena ja se on saatavilla [GitHubissa][2]. Mikäli löydät virheitä, lisää se [seurantajärjestelmään][3] tai tee `pull`-pyyntö. Löydät meidät myös [JavaScript huoneesta][4] Stack Overflown chatista. 4 | 5 | [1]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE 6 | [2]: https://github.com/BonsaiDen/JavaScript-Garden 7 | [3]: https://github.com/BonsaiDen/JavaScript-Garden/issues 8 | [4]: http://chat.stackoverflow.com/rooms/17/javascript 9 | 10 | -------------------------------------------------------------------------------- /doc/fi/intro/translators.md: -------------------------------------------------------------------------------- 1 | ## Kääntäjät 2 | 3 | - [Juho Vepsäläinen][1] 4 | 5 | [1]: https://github.com/bebraw 6 | -------------------------------------------------------------------------------- /doc/fi/object/forinloop.md: -------------------------------------------------------------------------------- 1 | ## `for in`-luuppi 2 | 3 | Aivan kuten `in`-operaattori, myös `for in`-luuppi käy olion prototyyppiketjun läpi iteroidessaan sen ominaisuuksia. 4 | 5 | > **Huomio:** `for in`-luuppi **ei** iteroi ominaisuuksia, joiden `enumerable`-attribuutti on asetettu arvoon `false`. Eräs esimerkki tästä on taulukon `length`-ominaisuus. 6 | 7 | // Object.prototypen myrkyttäminen 8 | Object.prototype.bar = 1; 9 | 10 | var foo = {moo: 2}; 11 | for(var i in foo) { 12 | console.log(i); // tulostaa sekä bar että moo 13 | } 14 | 15 | Koska `for in`-luupin käytöstapaa ei voida muokata suoraan, tulee ei-halutut ominaisuudet karsia itse luupin sisällä. Tämä on mahdollista käyttäen `Object.prototype`-olion [`hasOwnProperty`](#object.hasownproperty)-metodia. 16 | 17 | > **Huomio:** `for in`-luupin suorittaminen hidastuu sitä enemmän, mitä pidempi olion prototyyppiketju on. Tämä johtuu siitä, että se joutuu käymään koko ketjun sisällön läpi. 18 | 19 | ### `hasOwnProperty`-metodin käyttäminen karsimiseen 20 | 21 | // foo kuten yllä 22 | for(var i in foo) { 23 | if (foo.hasOwnProperty(i)) { 24 | console.log(i); 25 | } 26 | } 27 | 28 | Tämä versio on ainut oikea. Se tulostaa **ainoastaan** `moo`, koska se käyttää `hasOwnProperty`-metodia oikein. Kun se jätetään pois, on koodi altis virheille tapauksissa, joissa prototyyppejä, kuten `Object.prototype`, on laajennettu. 29 | 30 | [Prototype][1] on eräs yleisesti käytetty ohjelmointialusta, joka tekee näin. Kun kyseistä alustaa käytetään, `for in`-luupit, jotka eivät käytä `hasOwnProperty`-metodia, menevät varmasti rikki. 31 | 32 | ### Yhteenveto 33 | 34 | On suositeltavaa käyttää **aina** `hasOwnProperty`-metodia. Ei ole kannattavaa tehdä ajoympäristöön tai prototyyppeihin liittyviä oletuksia. 35 | 36 | [1]: http://www.prototypejs.org/ 37 | 38 | -------------------------------------------------------------------------------- /doc/fi/object/hasownproperty.md: -------------------------------------------------------------------------------- 1 | ## `hasOwnProperty` 2 | 3 | Jotta voimme tarkistaa onko olion ominaisuus määritelty siinä *itsessään*, tulee käyttää erityistä `Object.prototype`-oliosta periytyvää `hasOwnProperty`-metodia. Tällä tavoin vältämme [prototyyppiketjun](#object.prototype) sisältämät ominaisuudet. 4 | 5 | > **Huomio:** **Ei** riitä tarkistaa vain että ominaisuuden arvo on `undefined`. Ominaisuus voi hyvinkin olla olemassa. Sen arvoksi on vain satuttu asettamaan `undefined`. 6 | 7 | `hasOwnProperty` on ainut JavaScriptin sisältämä metodi, joka käsittelee ominaisuuksia **eikä** käy prototyyppiketjun sisältöä läpi. 8 | 9 | // Object.prototypen myrkyttäminen 10 | Object.prototype.bar = 1; 11 | var foo = {goo: undefined}; 12 | 13 | foo.bar; // 1 14 | 'bar' in foo; // tosi 15 | 16 | foo.hasOwnProperty('bar'); // epätosi 17 | foo.hasOwnProperty('goo'); // tosi 18 | 19 | Ainoastaan `hasOwnProperty` palauttaa oikean ja odotetun tuloksen. Sen tietäminen on olennaista minkä tahansa olion ominaisuuksia iteroidessa. Tämä on **ainut** tapa löytää olion itsensä ominaisuudet prototyyppiketjusta riippumatta. 20 | 21 | ### `hasOwnProperty` ominaisuutena 22 | 23 | JavaScript **ei** suojele `hasOwnProperty`-metodin nimeä. Täten on mahdollista, että olio voi sisältää samannimisen ominaisuuden. Jotta voimme saada oikeita tuloksia, tulee sen sijaan käyttää *ulkoista* `hasOwnProperty`-metodia. 24 | 25 | var foo = { 26 | hasOwnProperty: function() { 27 | return false; 28 | }, 29 | bar: 'Olkoon vaikka lohikäärmeitä' 30 | }; 31 | 32 | foo.hasOwnProperty('bar'); // palauttaa aina epätoden 33 | 34 | // Käytä toisen olion hasOwnProperty-metodia ja kutsu sitä asettamalla 35 | // 'this' foohon 36 | ({}).hasOwnProperty.call(foo, 'bar'); // tosi 37 | 38 | ### Yhteenveto 39 | 40 | Mikäli pitää selvittää kuuluuko ominaisuus olioon vai ei, **ainoastaan** `hasOwnProperty` voi kertoa sen. Tämän lisäksi on suositeltavaa käyttää `hasOwnProperty`-metodia osana **jokaista** [`for in`-luuppia](#object.forinloop). Tällä tavoin voidaan välttää natiivien [prototyyppien](#object.prototype) laajentamiseen liittyviä ongelmia. 41 | 42 | -------------------------------------------------------------------------------- /doc/fi/types/casting.md: -------------------------------------------------------------------------------- 1 | ## Tyyppimuunnokset 2 | 3 | JavaScript on tyypitetty *heikosti*. Tämä tarkoittaa sitä, että se pyrkii *pakottamaan tyyppejä* *aina* kun se on mahdollista. 4 | 5 | // Nämä ovat totta 6 | new Number(10) == 10; // Number.toString() muutetaan 7 | // takaisin numeroksi 8 | 9 | 10 == '10'; // Merkkijonot muutetaan Number-tyyppiin 10 | 10 == '+10 '; // Lisää merkkijonohauskuutta 11 | 10 == '010'; // Ja lisää 12 | isNaN(null) == false; // null muuttuu nollaksi, 13 | // joka ei ole NaN 14 | 15 | // Nämä ovat epätosia 16 | 10 == 010; 17 | 10 == '-10'; 18 | 19 | > **ES5 Huomio:** Nollalla alkavat numeroliteraalit tulkitaan oktaaleina (kantaluku 8). Tuki oktaaleille on **poistettu** ECMAScript 5:den tiukassa moodissa. 20 | 21 | Yllä havaittu käytös voidaan välttää käyttämällä [tiukkaa vertailuoperaattoria](#types.equality). Sen käyttöä suositellaan **lämpimästi**. Vaikka se välttääkin useita yleisiä ongelma, sisältää se omat ongelmansa, jotka johtavat juurensa JavaScriptin heikkoon tyypitykseen. 22 | 23 | ### Natiivien tyyppien konstruktorit 24 | 25 | Natiivien tyyppien, kuten `Number` tai `String`, konstruktorit käyttäytyvät eri tavoin `new`-avainsanan kanssa ja ilman. 26 | 27 | new Number(10) === 10; // Epätosi, Object ja Number 28 | Number(10) === 10; // Tosi, Number ja Number 29 | new Number(10) + 0 === 10; // Tosi, johtuu tyyppimuunnoksesta 30 | 31 | `Number`-tyypin kaltaisen natiivityypin käyttäminen luo uuden `Number`-olion. `new`-avainsanan pois jättäminen tekee `Number`-funktiosta pikemminkin muuntimen. 32 | 33 | Tämän lisäksi literaalit tai ei-oliomaiset arvot johtavat edelleen uusiin tyyppimuunnoksiin. 34 | 35 | Paras tapa suorittaa tyyppimuunnoksia on tehdä niitä **selvästi**. 36 | 37 | ### Muunnos merkkijonoksi 38 | 39 | '' + 10 === '10'; // tosi 40 | 41 | Arvo voidaan muuttaa merkkijonoksi helposti lisäämällä sen eteen tyhjä merkkijono. 42 | 43 | ### Muunnos numeroksi 44 | 45 | +'10' === 10; // tosi 46 | 47 | **Unaarinen** plus-operaattori mahdollistaa numeroksi muuttamisen. 48 | 49 | ### Muunnos totuusarvoksi 50 | 51 | Arvo voidaan muuttaa totuusarvoksi käyttämällä **not**-operaattoria kahdesti. 52 | 53 | !!'foo'; // tosi 54 | !!''; // epätosi 55 | !!'0'; // tosi 56 | !!'1'; // tosi 57 | !!'-1' // tosi 58 | !!{}; // tosi 59 | !!true; // tosi 60 | 61 | 62 | -------------------------------------------------------------------------------- /doc/fi/types/instanceof.md: -------------------------------------------------------------------------------- 1 | ## `instanceof`-operaattori 2 | 3 | `instanceof`-operaattori vertaa kahden operandinsa konstruktoreita keskenään. Se on hyödyllinen ainoastaan, kun vertaillaan itsetehtyjä olioita. Natiivien tyyppien tapauksessa se on lähes yhtä hyödytön kuin [typeof-operaattori](#types.typeof). 4 | 5 | ### Itsetehtyjen olioiden vertailu 6 | 7 | function Foo() {} 8 | function Bar() {} 9 | Bar.prototype = new Foo(); 10 | 11 | new Bar() instanceof Bar; // tosi 12 | new Bar() instanceof Foo; // tosi 13 | 14 | // Tämä asettaa vain Bar.prototype-ominaisuudeksi 15 | // funktio-olion Foo 16 | // Se ei kuitenkaan ole Foon todellinen instanssi 17 | Bar.prototype = Foo; 18 | new Bar() instanceof Foo; // epätosi 19 | 20 | ### `instanceof` ja natiivit tyypit 21 | 22 | new String('foo') instanceof String; // tosi 23 | new String('foo') instanceof Object; // tosi 24 | 25 | 'foo' instanceof String; // epätosi 26 | 'foo' instanceof Object; // epätosi 27 | 28 | On tärkeää huomata, että `instanceof` ei toimi olioilla, jotka tulevat muista JavaScript-konteksteista (esim. selaimen eri dokumenteista). Tässä tapauksessa niiden konstruktorit viittaavat eri olioon. 29 | 30 | ### Yhteenveto 31 | 32 | `instanceof`-operaattoria tulee käyttää **ainoastaan**, mikäli käsitellään itsetehtyjä olioita saman JavaScript-kontekstin sisällä. Kuten [`typeof`](#types.typeof)-operaattorikin, myös muita sen käyttöjä tulee **välttää**. 33 | 34 | -------------------------------------------------------------------------------- /doc/ja/array/constructor.md: -------------------------------------------------------------------------------- 1 | ## `Array`コンストラクター 2 | 3 | `Array`コンストラクターはそのパラメーターの扱い方が曖昧なので、新しい配列を作る時には、常に配列リテラル - `[]`記法 - を使用する事を強くお勧めします。 4 | 5 | [1, 2, 3]; // 結果: [1, 2, 3] 6 | new Array(1, 2, 3); // 結果: [1, 2, 3] 7 | 8 | [3]; // Result: [3] 9 | new Array(3); // 結果: [] 10 | new Array('3') // 結果: ['3'] 11 | 12 | このケースの場合、`Array`コンストラクターに渡される引数は一つだけですが、その引数は`Number`になります。コンストラクターは、引数に値がセットされた`length`プロパティを伴った新しい*疎*配列を返します。特筆すべきなのは、新しい配列の`length`プロパティ**のみ**が、このようにセットされるという事です。実際の配列のインデックスは初期化されません。 13 | 14 | var arr = new Array(3); 15 | arr[1]; // undefined 16 | 1 in arr; // false, インデックスがセットされていない 17 | 18 | 配列の長さが先行してセットされるという振舞いは、いくつかの場合に便利です。例えば、文字の繰り返しや、`for loop`を使用したコードの回避などの場合です。 19 | 20 | new Array(count + 1).join(stringToRepeat); 21 | 22 | ### 終わりに 23 | 24 | `Array`コンストラクターの使用は出来る限り避けてください。リテラルが当然望ましい形です。それらは、短かく明快な文法をもっている為に、コードの可読性を高めてくれます。 25 | 26 | -------------------------------------------------------------------------------- /doc/ja/array/general.md: -------------------------------------------------------------------------------- 1 | ## 配列の繰り返しとプロパティ 2 | 3 | JavaScriptの配列もまたオブジェクトですが、[`for in ループ`](#object.forinloop)を配列の繰り返し処理で使用することの良い理由は1つもありません。実際、配列に`for in`を使用**しない**為の正当な理由はたくさんあります。 4 | 5 | > **注意:** JavaScriptの配列は*連想配列*では**ありません**。JavaScriptは[objects](#object.general)だけがキーバリューをマッピングするものです。 6 | > また、連想配列は順序を**保持**しますが、オブジェクトは**保持しません**。 7 | 8 | `for in`ループはプロトタイプチェーン上の全てのプロパティを列挙するため、[`hasOwnProperty`](#object.hasownproperty)をそれらのプロパティの存在判定に使います。この為、通常の`for`ループよりも**20倍**遅くなります。 9 | 10 | ### 繰り返し 11 | 12 | 配列の要素を繰り返すとのに、最高のパフォーマンスを出したければ昔ながらの`for`ループを使うのが一番です。 13 | 14 | var list = [1, 2, 3, 4, 5, ...... 100000000]; 15 | for(var i = 0, l = list.length; i < l; i++) { 16 | console.log(list[i]); 17 | } 18 | 19 | 上記の例では1つ追加の仕掛けがありますが、それは`l = list.length`によって配列の長さをキャッシュする部分です。 20 | 21 | `length`プロパティは配列自身に定義されてはいますが、ループ中の繰り返しで毎回これを参照してしまうと、やはりオーバーヘッドが存在してしまいます。最近のJavaScriptエンジンはこのような場合に最適化する**はず**ですが、コードが新しいエンジンで実行されるかどうか、知る方法はありません。 22 | 23 | 実際には、キャッシュを抜きにするとループの結果はキャッシュされたものに比べてたった**半分の速度**にしかなりません。 24 | 25 | ### `length`プロパティ 26 | 27 | `length`プロパティの*ゲッター*は単に配列に含まれる要素の数を返すだけにも関わらず、*セッター*は配列を**トランケート**する為にも使用できます。 28 | 29 | var foo = [1, 2, 3, 4, 5, 6]; 30 | foo.length = 3; 31 | foo; // [1, 2, 3] 32 | 33 | foo.length = 6; 34 | foo; // [1, 2, 3] 35 | 36 | より小さいlengthを割り当てると配列をトランケートしますが、lengthが大きくなっても配列には何も影響しません。 37 | 38 | ### 終わりに 39 | 40 | 最高のパフォーマンスの為には、常に`for`ループを使用し、`length`プロパティをキャッシュする事をお勧めします。`for in`ループを配列で使用するのは、バグや最低のパフォーマンスの傾向があるコードを書く前兆になります。 41 | 42 | -------------------------------------------------------------------------------- /doc/ja/core/delete.md: -------------------------------------------------------------------------------- 1 | ## `delete`演算子 2 | 3 | 端的に言って、JavaScriptの関数やその他の要素は`DontDelete`属性が設定されているので、グローバル変数を消去する事は*不可能*です。 4 | 5 | ### グローバルコードと関数コード 6 | 7 | 変数や、関数がグローバルまたは[関数スコープ](#function.scopes)で定義された時は、そのプロパティは有効なオブジェクトかグローバルオブジェクトになります。このようなプロパティは属性のセットを持っていますが、それらの内の1つが`DontDelete`になります。変数や関数がグローバルや関数コードで宣言されると、常に`DontDelete`属性を作るために、消去できません。 8 | 9 | // グローバル変数: 10 | var a = 1; // DontDelete属性が設定される 11 | delete a; // false 12 | a; // 1 13 | 14 | // 通常関数: 15 | function f() {} // DontDelete属性が設定される 16 | delete f; // false 17 | typeof f; // "function" 18 | 19 | // 再代入も役に立たない: 20 | f = 1; 21 | delete f; // false 22 | f; // 1 23 | 24 | ### 明示的なプロパティ 25 | 26 | 明示的にプロパティを設定することが、通常通りの消去を可能にします。 27 | 28 | // プロパティを明示的に設定する 29 | var obj = {x: 1}; 30 | obj.y = 2; 31 | delete obj.x; // true 32 | delete obj.y; // true 33 | obj.x; // undefined 34 | obj.y; // undefined 35 | 36 | 上記の例の中で、`obj.x`と`obj.y`はそれぞれ`DontDelete`属性が無い為に消去できます。これが下記の例でも動作する理由です。 37 | 38 | // IE以外では、これも動作する 39 | var GLOBAL_OBJECT = this; 40 | GLOBAL_OBJECT.a = 1; 41 | a === GLOBAL_OBJECT.a; // true - ただのグローバルのvar 42 | delete GLOBAL_OBJECT.a; // true 43 | GLOBAL_OBJECT.a; // undefined 44 | 45 | ここでは`a`. [`this`](#function.this)を消す為にグローバルオブジェクトと明示的に宣言した`a`をそのプロパティとして参照させて、消去する事を許可するトリックを使います。 46 | 47 | IE(最低でも6-8で)は多少のバグがある為に、上記のコードは動作しません。 48 | 49 | 50 | ### 関数の引数と組み込み引数 51 | 52 | 関数の通常の引数である、[`arguments` objects](#function.arguments)と組み込みのプロパティもまた、`DontDelete`が設定されています。 53 | 54 | // 関数の引数とプロパティ: 55 | (function (x) { 56 | 57 | delete arguments; // false 58 | typeof arguments; // "object" 59 | 60 | delete x; // false 61 | x; // 1 62 | 63 | function f(){} 64 | delete f.length; // false 65 | typeof f.length; // "number" 66 | 67 | })(1); 68 | 69 | ### ホストオブジェクト 70 | 71 | `delete`演算子の挙動はホストオブジェクトにとって予測不可能になりかねません。仕様によりホストオブジェクトは、あらゆる挙動の実行が許可されている為です。 72 | 73 | ### 終わりに 74 | 75 | `delete`演算子は、しばしば予期せぬ挙動をします。唯一安全な使用方法は通常のオブジェクトに明示的に設定されたプロパティを扱う場合だけです。 76 | -------------------------------------------------------------------------------- /doc/ja/core/eval.md: -------------------------------------------------------------------------------- 1 | ## なぜ、`eval`を使ってはいけないのか 2 | 3 | `eval`関数はローカルスコープ中のJavaScriptコードの文字列を実行します。 4 | 5 | var foo = 1; 6 | function test() { 7 | var foo = 2; 8 | eval('foo = 3'); 9 | return foo; 10 | } 11 | test(); // 3 12 | foo; // 1 13 | 14 | しかし、`eval`は**直接**ローカルスコープから呼ばれて、*かつ*呼んだ関数の名前が実際の`eval`でないと実行しません。 15 | 16 | var foo = 1; 17 | function test() { 18 | var foo = 2; 19 | var bar = eval; 20 | bar('foo = 3'); 21 | return foo; 22 | } 23 | test(); // 2 24 | foo; // 3 25 | 26 | `eval`の使用は**全てのコスト**を払ってでも回避するべきです。その「使用法」の99.9%で、これ**無し**でも実装できます。 27 | 28 | ### 偽装された`eval` 29 | 30 | [timeout functions](#other.timeouts)である`setTimeout`と`setInterval`はどちらも最初の引数として文字列を取る事ができます。この文字列は`eval`がこの場合直接呼ばれていないので、**常に**グローバルスコープで実行されてしまいます。 31 | 32 | ### セキュリティの問題 33 | 34 | `eval`はまたセキュリティの問題もあります。なぜなら、**どんな**コードを与えられても実行してしまうからで、**絶対**に不明または信頼できない発行元の文字列は使ってはいけません。 35 | 36 | ### 終わりに 37 | 38 | `eval`は絶対に使用しないでください。これを使用しているどんなコードも、その働き、パフォーマンスやセキュリティについて問われてしまいます。`eval`が必要な場合でも、最初の段階で使用**しない**でください。*より良いデザイン*を使用するべきで、それには`eval`を使う必要性はありません。 39 | 40 | -------------------------------------------------------------------------------- /doc/ja/core/undefined.md: -------------------------------------------------------------------------------- 1 | ## `undefined`と`null` 2 | 3 | JavaScriptは`nothing`を表す2つの別個の値を持っています。これら2つの内で`undefined`はより便利な存在です。 4 | 5 | ### `undefined`の値 6 | 7 | `undefined`はただ1つの値`undefined`を持つ型です。 8 | 9 | この言語はまた、`undefined`の値を持つグローバル変数を定義しています。この値もまた`undefined`と呼ばれています。しかし、この変数は **どちらも** 言語のキーワードではなく、定数です。この事はこの*値*は簡単に上書きされてしまうという事になります。 10 | 11 | > **ES5での注意点:** ECMAScript 5での`undefined`は **もはや** strict modeでは *書き変えられない* 12 | > ようになっています。しかし、この名前は`undefined`という名前の関数の例に痕跡が見られるだけです。 13 | 14 | `undefined`が返される時の例をいくつか挙げます。 15 | 16 | - (未定義の)グローバル変数`undefined`にアクセスした時 17 | - `return`文が無い為に、暗黙のうちに関数が返された時 18 | - 何も返されない`return`がある時 19 | - 存在しないプロパティを探索する時 20 | - 関数のパラメーターで明示的な値が何も無い時 21 | - `undefined`が設定された全ての値 22 | 23 | ### `undefined`の値に変更する処理 24 | 25 | グローバル変数`undefined`のみが実際の`undefined`の*値*のコピーを保持するので、これに新しい値を代入しても`undefined`の*型* の値が変更される事は**ありません**。 26 | 27 | まだ、`undefined`の値に対して何かしらの比較をしないといけない場合は、最初に`undefined`の値を取得する必要があります。 28 | 29 | コードの`undefined`の変数の上書きを可能な限りしないよう保護する為には、一般的なテクニックとして[anonymous wrapper](#function.scopes)の引数にパラメーターを追加するというものがあります。 30 | 31 | var undefined = 123; 32 | (function(something, foo, undefined) { 33 | // ローカルスコープではundefined。 34 | // ここで値に対して参照がされる 35 | 36 | })('Hello World', 42); 37 | 38 | 同じ効果を得る事ができる別の方法として、ラッパーの内部での宣言を使うものがあります。 39 | 40 | var undefined = 123; 41 | (function(something, foo) { 42 | var undefined; 43 | ... 44 | 45 | })('Hello World', 42); 46 | 47 | これらの唯一の違いは、こちらのバージョンの方が4バイト余計に短縮できるという物です。また、他に`var`ステートメントは匿名ラッパーの中にはありません。 48 | 49 | ### `null`の使用 50 | 51 | JavaScriptというプログラム言語のコンテキストの中では、`undefined`は主に伝統的な意味での*null*の意味で使用される事が多いです。実際の`null`(リテラルも型も両方)は多かれ少なかれ、単なるデータ型です。 52 | 53 | それはJavaScriptの内部でいくつか使われています(プロトタイプチェーンの終わりに`Foo.prototype = null`という宣言をするようなもの)が、ほとんど全てのケースで、`undefined`に置き替える事が可能です。 54 | -------------------------------------------------------------------------------- /doc/ja/function/closures.md: -------------------------------------------------------------------------------- 1 | ## クロージャと参照 2 | 3 | JavaScriptの一番パワフルな特徴の一つとして*クロージャ*が使える事が挙げられます。これはスコープが自身の定義されている外側のスコープに**いつでも**アクセスできるという事です。JavaScriptの唯一のスコープは[関数スコープ](#function.scopes)ですが、全ての関数は標準でクロージャとして振る舞います。 4 | 5 | ### プライベート変数をエミュレートする 6 | 7 | function Counter(start) { 8 | var count = start; 9 | return { 10 | increment: function() { 11 | count++; 12 | }, 13 | 14 | get: function() { 15 | return count; 16 | } 17 | } 18 | } 19 | 20 | var foo = Counter(4); 21 | foo.increment(); 22 | foo.get(); // 5 23 | 24 | ここで`Counter`は**2つ**のクロージャを返します。関数`increment`と同じく関数`get`です。これら両方の関数は`Counter`のスコープを**参照**し続けます。その為、そのスコープ内に定義されている`count`変数に対していつもアクセスできるようになっています。 25 | 26 | ### なぜプライベート変数が動作するのか? 27 | 28 | JavaScriptでは、スコープ自体を参照・代入する事が出来無い為に、外部から変数`count`にアクセスする手段が**ありません**。唯一の手段は、2つのクロージャを介してアクセスする方法だけです。 29 | 30 | var foo = new Counter(4); 31 | foo.hack = function() { 32 | count = 1337; 33 | }; 34 | 35 | 上記のコードは`Counter`のスコープ中にある変数`count`の値を変更する事は**ありません**。`foo.hack`は**その**スコープで定義されていないからです。これは(`Counter`内の変数`count`の変更)の代わりに*グローバル*変数`count`の作成 -または上書き- する事になります。 36 | 37 | ### ループ中のクロージャ 38 | 39 | 一つ良くある間違いとして、ループのインデックス変数をコピーしようとしてか、ループの中でクロージャを使用してしまうというものがあります。 40 | 41 | for(var i = 0; i < 10; i++) { 42 | setTimeout(function() { 43 | console.log(i); 44 | }, 1000); 45 | } 46 | 47 | 上記の例では`0`から`9`の数値が出力される事は**ありません**。もっと簡単に`10`という数字が10回出力されるだけです。 48 | 49 | **匿名**関数は`i`への**参照**を維持しており、同時に`forループ`は既に`i`の値に`10`をセットし終った`console.log`が呼ばれてしまいます。 50 | 51 | 期待した動作をする為には、`i`の値の**コピー**を作る必要があります。 52 | 53 | ### 参照問題を回避するには 54 | 55 | ループのインデックス変数をコピーする為には、[匿名ラッパー](#function.scopes)を使うのがベストです。 56 | 57 | for(var i = 0; i < 10; i++) { 58 | (function(e) { 59 | setTimeout(function() { 60 | console.log(e); 61 | }, 1000); 62 | })(i); 63 | } 64 | 65 | 外部の匿名関数は`i`を即座に第一引数として呼び出し、引数`e`を`i`の**値**のコピーとして受け取ります。 66 | 67 | `e`を参照している`setTimeout`を受け取った匿名関数はループによって値が変わる事が**ありません。** 68 | 69 | 他にこのような事を実現する方法があります。それは匿名ラッパーから関数を返してあげる事です。これは上記のコードと同じ振る舞いをします。 70 | 71 | for(var i = 0; i < 10; i++) { 72 | setTimeout((function(e) { 73 | return function() { 74 | console.log(e); 75 | } 76 | })(i), 1000) 77 | } 78 | 79 | -------------------------------------------------------------------------------- /doc/ja/function/general.md: -------------------------------------------------------------------------------- 1 | ## 関数の宣言と式 2 | 3 | 関数はJavaScriptの第一級オブジェクトです。この事は、その他の値と同じように渡す事が出来るという事です。この機能で良く使われる一つとして**匿名関数**を他のオブジェクトにコールバックとして渡すというものがあり、これで非同期での実装が可能になります。 4 | 5 | ### `関数`宣言 6 | 7 | function foo() {} 8 | 9 | 上記の関数はプログラムの開始時の前に評価されるように[巻き上げ](#function.scopes)られます。従って*定義*されたスコープ内の*どこでも*使用する事が可能になります。ソース内での実際の定義が呼ばれる前でもです。 10 | 11 | foo(); // このコードが動作する前にfooが作られているので、ちゃんと動作する 12 | function foo() {} 13 | 14 | ### `関数`式 15 | 16 | var foo = function() {}; 17 | 18 | この例では、`foo`という変数に無名で*匿名*の関数が割り当てられています。 19 | 20 | foo; // 'undefined' 21 | foo(); // これはTypeErrorが起こる 22 | var foo = function() {}; 23 | 24 | `var`は宣言である為に、変数名`foo`がコードが開始される実際の評価時より前のタイミングにまで巻き上げられています。`foo`は既にスクリプトが評価される時には定義されているのです。 25 | 26 | しかし、コードの実行時にのみこの割り当てがされるため、`foo`という変数は対応するコードが実行される前にデフォルト値である[undefined](#core.undefined)が代入されるのです。 27 | 28 | ### 名前付き関数式 29 | 30 | 他に特殊なケースとして、名前付き関数があります。 31 | 32 | var foo = function bar() { 33 | bar(); // 動作する 34 | } 35 | bar(); // ReferenceError 36 | 37 | この場合の`bar`は`foo`に対して関数を割り当てるだけなので、外部スコープでは使用できません。しかし、`bar`は内部では使用できます。これはJavaScriptの[名前解決](#function.scopes)の方法によるもので、関数名は*いつも*関数自身のローカルスコープ内で有効になっています。 38 | -------------------------------------------------------------------------------- /doc/ja/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "JavaScript Garden", 3 | "langTitle": "JavaScript Garden in Japanese", 4 | "description": "JavaScriptの奇妙さと欠陥についてのガイドライン", 5 | "sections": [ 6 | { 7 | "title": "前書き", 8 | "dir": "intro", 9 | "articles": ["index"] 10 | }, 11 | { 12 | "title": "オブジェクト", 13 | "dir": "object", 14 | "articles": [ 15 | "general", 16 | "prototype", 17 | "hasownproperty", 18 | "forinloop" 19 | ] 20 | }, 21 | { 22 | "title": "関数", 23 | "dir": "function", 24 | "articles": [ 25 | "general", 26 | "this", 27 | "closures", 28 | "arguments", 29 | "constructors", 30 | "scopes" 31 | ] 32 | }, 33 | { 34 | "title": "配列", 35 | "dir": "array", 36 | "articles": [ 37 | "general", 38 | "constructor" 39 | ] 40 | }, 41 | { 42 | "title": "型", 43 | "dir": "types", 44 | "articles": [ 45 | "equality", 46 | "typeof", 47 | "instanceof", 48 | "casting" 49 | ] 50 | }, 51 | { 52 | "title": "コア", 53 | "dir": "core", 54 | "articles": [ 55 | "eval", 56 | "undefined", 57 | "semicolon", 58 | "delete" 59 | ] 60 | }, 61 | { 62 | "title": "その他", 63 | "dir": "other", 64 | "articles": [ 65 | "timeouts" 66 | ] 67 | } 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /doc/ja/intro/index.md: -------------------------------------------------------------------------------- 1 | ## 前書き 2 | 3 | **JavaScript Garden** はJavaScriptというプログラム言語の一番奇妙な部分についてのドキュメント集です。 4 | このドキュメントはJavaScriptという言語に慣れていないプログラマーがこの言語について深く知ろうとする際に遭遇する、良くある間違い・小さなバグ・パフォーマンスの問題・悪い習慣などを避ける為のアドバイスを与えます。 5 | 6 | JavaScript GardenはJavaScriptを教える事を**目的にしていません**。このガイドの項目を理解する為には、この言語に対する前提知識がある事を推奨します。この言語の基礎部分についてはMozilla Developer Networkの[ガイド][1] がオススメです。 7 | 8 | ## 著者 9 | 10 | このガイドは愛すべき[Stack Overflow][2]の2人のユーザー[Ivo Wetzel][3] 11 | (執筆)と[Zhang Yi Jiang][4] (デザイン)によって作られました。 12 | 13 | ## 貢献者 14 | 15 | - [貢献者](https://github.com/BonsaiDen/JavaScript-Garden/graphs/contributors) 16 | 17 | ## ホスティング 18 | 19 | JavaScript GardenはGitHubでホスティングされていますが、[Cramer Development][7]が[JavaScriptGarden.info][8]というミラーサイトを作ってくれています。 20 | 21 | ## ライセンス 22 | 23 | JavaScript Gardenは[MIT license][9]の下で公開されており、[GitHub][10]でホスティングされています。もしもエラーやtypoを見つけたら[file an issue][11]に登録するかリポジトリにプルリクエストを送ってください。 24 | またStack Overflowチャットの[JavaScript room][12]に私達はいます。 25 | 26 | 27 | [1]: https://developer.mozilla.org/en/JavaScript/Guide 28 | [2]: http://stackoverflow.com/ 29 | [3]: http://stackoverflow.com/users/170224/ivo-wetzel 30 | [4]: http://stackoverflow.com/users/313758/yi-jiang 31 | [5]: https://github.com/caio 32 | [6]: https://github.com/blixt 33 | [7]: http://cramerdev.com/ 34 | [8]: http://javascriptgarden.info/ 35 | [9]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE 36 | [10]: https://github.com/BonsaiDen/JavaScript-Garden 37 | [11]: https://github.com/BonsaiDen/JavaScript-Garden/issues 38 | [12]: http://chat.stackoverflow.com/rooms/17/javascript 39 | -------------------------------------------------------------------------------- /doc/ja/object/forinloop.md: -------------------------------------------------------------------------------- 1 | ## `for in`ループ 2 | 3 | `in`オペレーターは単に、`for in`ループの中でオブジェクトのプロパティをプロトタイプチェーンの中で繰り返し遡る為にあるものです。 4 | 5 | > **注意:** `for in`ループは`enumerable`属性が`false`にセットされているプロパティを反復処理**しません**。; 6 | > 例えば、配列の`length`プロパティなどがそれに当たります。 7 | 8 | // Object.prototype汚染 9 | Object.prototype.bar = 1; 10 | 11 | var foo = {moo: 2}; 12 | for(var i in foo) { 13 | console.log(i); // barとmooが両方とも表示される 14 | } 15 | 16 | `for in`ループそれ自体の動作を変更する事は不可能ですが、ループ内にある要らないプロパティをフィルタリングする必要があります。そんな時は`Object.prototype`の[`hasOwnProperty`](#object.hasownproperty)メソッドを使うと解決します。 17 | 18 | > **注意:** `for in`は常にプロトタイプチェーンを完全に遡ります。これにより 19 | > オブジェクトに追加されている継承が多ければ多い程、速度は遅くなります。 20 | 21 | ### `hasOwnProperty`をフィルタリングに使用する 22 | 23 | // 継承されているfoo 24 | for(var i in foo) { 25 | if (foo.hasOwnProperty(i)) { 26 | console.log(i); 27 | } 28 | } 29 | 30 | このループの唯一正しい使い方がこの方法です。`hasOwnProperty`を使用しているので、 31 | `moo`**のみ**が表示されるようになります。`hasOwnProperty`が省略されている場合は、このコードは 32 | 組み込みのプロトタイプが存在する場合に(特に`Object.prototype`が拡張されている場合)エラーを発生しやすくなります。 33 | 34 | 一般に広く使用されているJavaScriptフレームワークとして[Prototype][1]が挙げられます。このフレームワークには、 35 | `for in` 内で`hasOwnProperty`が使用されプロトタプチェーン内を頭まで遡るのを中断する事が保証されています。 36 | 37 | ### 終わりに 38 | 39 | **常に**`hasOwnProperty`を使用する事を推奨します。コードの実行環境や、組み込みのプロトタイプが拡張されているかどうかを仮定して書くようなコードを絶対書いてはいけません。 40 | 41 | [1]: http://www.prototypejs.org/ 42 | 43 | -------------------------------------------------------------------------------- /doc/ja/object/general.md: -------------------------------------------------------------------------------- 1 | ## オブジェクトの使用法とプロパティ 2 | 3 | JavaScriptの全ての要素は2つの例外を除いて、オブジェクトのように振る舞います。 4 | その2つとは[`null`](#core.undefined)と[`undefined`](#core.undefined)です。 5 | 6 | false.toString(); // 'false' 7 | [1, 2, 3].toString(); // '1,2,3' 8 | 9 | function Foo(){} 10 | Foo.bar = 1; 11 | Foo.bar; // 1 12 | 13 | 良くありがちな誤解として、数値リテラルがオブジェクトとして使用できないというものがあります。この理由としては、JavaScriptパーサーが浮動小数点のドットを*ドット記法*として解釈しようとしてしまうからです。 14 | 15 | 2.toString(); // シンタックスエラーが発生する 16 | 17 | 数値リテラルをオブジェクトとして使用する為の回避策がいくつかあります。 18 | 19 | 2..toString(); // 2つ目のドットが正しく解釈される 20 | 2 .toString(); // ドットの左隣のスペースがポイント 21 | (2).toString(); // 2が一番最初に評価される 22 | 23 | ### オブジェクトはデータタイプ 24 | 25 | JavaScriptのオブジェクトは[*ハッシュマップ*][1]としても使用されます。これは名前付きのプロパティと値として構成されています。 26 | 27 | オブジェクトリテラル(`{}`記法)を使用すると、オブジェクトそのものを作る事ができます。この方法で作られたオブジェクトは`Object.prototype`から[継承](#object.prototype)され、[own properties](#object.hasownproperty)が何も設定されてない状態になります。 28 | 29 | var foo = {}; // 新しい空のオブジェクト 30 | 31 | // 12という値の'test'というプロパティを持った新しいオブジェクト 32 | var bar = {test: 12}; 33 | 34 | ### プロパティへのアクセス 35 | 36 | オブジェクトのプロパティには2通りのアクセス方法があります。1つはドット記法によるアクセス、もう1つはブラケット記法です。 37 | 38 | var foo = {name: 'Kitten'} 39 | foo.name; // kitten 40 | foo['name']; // kitten 41 | 42 | var get = 'name'; 43 | foo[get]; // kitten 44 | 45 | foo.1234; // シンタックスエラー 46 | foo['1234']; // 動作する 47 | 48 | どちらの記法も働きとしての違いは無いですが、唯一の違いとしてブラケット記法は通常のプロパティ名と同様に動的にプロパティを設定する事ができます。これ以外で動的にプロパティを設定しようとするとシンタックスエラーになります。 49 | 50 | ### プロパティの削除 51 | 52 | 実際にオブジェクトからプロパティを削除する唯一の方法は`delete`演算子を使う事です。プロパティに`undefined`や`null`をセットしても、プロパティ自身ではなく、*キー*に設定された*値*を削除するだけです。 53 | 54 | var obj = { 55 | bar: 1, 56 | foo: 2, 57 | baz: 3 58 | }; 59 | obj.bar = undefined; 60 | obj.foo = null; 61 | delete obj.baz; 62 | 63 | for(var i in obj) { 64 | if (obj.hasOwnProperty(i)) { 65 | console.log(i, '' + obj[i]); 66 | } 67 | } 68 | 69 | 上記の例では、`baz`は完全に削除されて出力がされていませんが、それ以外の2つ`bar undefined`と`foo null`はどちらも出力されてしまっています。 70 | 71 | ### キーの記法 72 | 73 | var test = { 74 | 'case': 'I am a keyword so I must be notated as a string', 75 | delete: 'I am a keyword too so me' // シンタックスエラーが起こる 76 | }; 77 | 78 | オブジェクトのプロパティは普通の文字か文字列として記述する事が出来ます。JavaScriptパーサーの設計ミスが原因ですが、ECMAScript5以前では上記のコードは`シンタックスエラー`を表示するでしょう。 79 | 80 | このエラーは`delete`が*予約語*になっているのが原因なので、古いJavaScriptエンジンに正しく解釈させる為には*文字リテラル*を使って記述する事を推奨します。 81 | 82 | [1]: http://en.wikipedia.org/wiki/Hashmap 83 | 84 | -------------------------------------------------------------------------------- /doc/ja/object/hasownproperty.md: -------------------------------------------------------------------------------- 1 | ## `hasOwnProperty` 2 | 3 | オブジェクトは*自分自身*と**自分以外**のどちらで定義されたプロパティかを[prototype chain](#object.prototype)のどこかでチェックしなくてはなりません。これは`Object.prototype`から継承される全てのオブジェクトの`hasOwnProperty`メソッドを使う必要があります。 4 | 5 | > **注意:** この方法はプロパティが`undefined`かどうかを調べるには十分では**無い**方法です。 6 | > プロパティは、ほとんどのオブジェクトで存在しているはずの物ではありますが、`undefined`が 7 | > 値に設定される事態は起こり得ます。 8 | 9 | `hasOwnProperty`はJavaScriptで唯一プロトタイプチェーン内を**遡らず**にプロパティを扱う事が出来ます。 10 | 11 | // Object.prototype汚染 12 | Object.prototype.bar = 1; 13 | var foo = {goo: undefined}; 14 | 15 | foo.bar; // 1 16 | 'bar' in foo; // true 17 | 18 | foo.hasOwnProperty('bar'); // false 19 | foo.hasOwnProperty('goo'); // true 20 | 21 | `hasOwnProperty`だけが、正しく期待した結果を出すでしょう。これはあらゆるオブジェクトのプロパティの繰り返し処理をする時必須の事です。オブジェクト*自身*に定義されておらず、プロトタイプチェーンのどこかには定義されているというプロパティを除外する手段が他に**ありません**。 22 | 23 | ### プロパティとしての`hasOwnProperty` 24 | 25 | JavaScriptはプロパティ名として`hasOwnProperty`を保護して**いません**。;従って、この名前のプロパティを持ったオブジェクトが存在する事がありえます。正しい結果を得る為には*外部*の`hasOwnProperty`を使う必要があります。 26 | 27 | var foo = { 28 | hasOwnProperty: function() { 29 | return false; 30 | }, 31 | bar: 'Here be dragons' 32 | }; 33 | 34 | foo.hasOwnProperty('bar'); // 常にfalseを返す 35 | 36 | // 他のオブジェクトのhasOwnPropertyを使い、fooの'this'にセットして呼び出す 37 | ({}).hasOwnProperty.call(foo, 'bar'); // true 38 | 39 | ### 終わりに 40 | 41 | オブジェクトのプロパティの存在判定をする時は、`hasOwnProperty`が**唯一**のメソッドになります。 42 | また、**全て**の[`for in` ループ](#object.forinloop)内で`hasOwnProperty`を使う事を推奨します。 43 | そうする事により組み込みの[prototypes](#object.prototype)の拡張が原因のエラーを避ける事が出来ます。 44 | 45 | -------------------------------------------------------------------------------- /doc/ja/types/casting.md: -------------------------------------------------------------------------------- 1 | ## 型変換 2 | 3 | JavaScriptは*弱い型付け*の言語なので、可能な**限り**に*型強制*が適用されます。 4 | 5 | // これらはtrueです。 6 | new Number(10) == 10; // Number.toString()が変換される 7 | // numberに戻る 8 | 9 | 10 == '10'; // StringsがNumberに変換される 10 | 10 == '+10 '; // バカみたいに文字列を追加 11 | 10 == '010'; // もっともっと 12 | isNaN(null) == false; // nullが0に変換される 13 | // もちろんNaNではないです 14 | 15 | // これらはfalseです 16 | 10 == 010; 17 | 10 == '-10'; 18 | 19 | > **ES5での注意点:** `0`から始まるNumberリテラルは8進数(基数が8)として解釈されます。 20 | > このような8進数のサポートはECMAScript5のstrict modeでは**削除されました**。 21 | 22 | 上記の自体を避ける為に、[厳密等価演算子](#types.equality)を使用する事を**強く**推奨します。また、これはたくさんある落し穴を避けますが、それでもまだJavaScriptの弱い型付けシステムから発生する色々な課題が残っています。 23 | 24 | ### 組み込み型のコンストラクタ 25 | 26 | `Number`や`String`のような組み込み型のコンストラクタは、`new`キーワードの有無で振る舞いが違ってきます。 27 | 28 | new Number(10) === 10; // False, ObjectとNumber 29 | Number(10) === 10; // True, NumberとNumber 30 | new Number(10) + 0 === 10; // True, 暗黙の型変換によります 31 | 32 | `Number`のような組み込み型をコンストラクタとして使うと、新しい`Number`オブジェクトが作られますが、`new`キーワードを除外すると`Number`関数がコンバーターのように振る舞います。 33 | 34 | 加えて、リテラルかオブジェトではない値を持っていると、さらに型強制が多くなります。 35 | 36 | 最良のオプションは以下の3つの方法の内、1つで型を**明示**してキャストする事になります。 37 | 38 | ### Stringでキャストする 39 | 40 | '' + 10 === '10'; // true 41 | 42 | 空の文字列の付加により値を簡単に文字列にキャストできます。 43 | 44 | ### Numberでキャストする 45 | 46 | +'10' === 10; // true 47 | 48 | **単項**プラスオペレーターを使うと数字にキャストする事が可能です。 49 | 50 | ### Booleanでキャストする 51 | 52 | **not**オペレーターを2回使うと、値はブーリアンに変換できます。 53 | 54 | !!'foo'; // true 55 | !!''; // false 56 | !!'0'; // true 57 | !!'1'; // true 58 | !!'-1' // true 59 | !!{}; // true 60 | !!true; // true 61 | -------------------------------------------------------------------------------- /doc/ja/types/equality.md: -------------------------------------------------------------------------------- 1 | ## 等価と比較 2 | 3 | JavaScriptはオブジェクトの値の等価の比較方法を2種類持っています。 4 | 5 | ### 等価演算子 6 | 7 | 等価演算子は2つのイコール記号: `==`から成っています。 8 | 9 | JavaScriptは*弱い型付け*を特徴としています。これは等価演算子が比較をする際に型付けを**強制**するという意味です。 10 | 11 | "" == "0" // false 12 | 0 == "" // true 13 | 0 == "0" // true 14 | false == "false" // false 15 | false == "0" // true 16 | false == undefined // false 17 | false == null // false 18 | null == undefined // true 19 | " \t\r\n" == 0 // true 20 | 21 | 上記の表では型強制の結果が表示されています。`==`の使用が一般に悪い習慣とみなされる大きな理由として、変換ルールが複雑な為、バグの追跡が困難になる事が挙げられます。 22 | 23 | 加えて、型強制が行なわれるとパフォーマンスにも影響してしまいます。例えば、文字列は他の数字と比較する前に数値に変換されなければなりません。 24 | 25 | ### 厳密等価演算子 26 | 27 | 厳密等価演算子は**3つ**のイコール記号:`===`で成っています。 28 | 29 | これはオペランドの間で強制的な型変換が**実行されない**事を除けば、通常の等価演算子と同じように正確に動作します。 30 | 31 | "" === "0" // false 32 | 0 === "" // false 33 | 0 === "0" // false 34 | false === "false" // false 35 | false === "0" // false 36 | false === undefined // false 37 | false === null // false 38 | null === undefined // false 39 | " \t\r\n" === 0 // false 40 | 41 | 上記の結果は、より明確でコードの早期破損を可能にします。これはある程度までコードを硬化させて、オペランドが別の型の場合にパフォーマンスが向上します。 42 | 43 | ### オブジェクトの比較 44 | 45 | `==`と`===`は両方とも**等価**演算子とされていますが、そのオペランドの少なくとも一つが`Object`の場合は、両者は異なる動きをします。 46 | 47 | {} === {}; // false 48 | new String('foo') === 'foo'; // false 49 | new Number(10) === 10; // false 50 | var foo = {}; 51 | foo === foo; // true 52 | 53 | これら2つの演算子は**同一性**を比較していているのであって、等価を比較しているわけでは**ありません**。これは、これらの演算子はPythonの`is`演算子やCのポインター比較と同じように、同じオブジェクトの**インスタンス**を比較するという事になります。 54 | 55 | ### 終わりに 56 | 57 | **厳密等価**演算子だけを使用することを特に推奨します。型を強制的に型変換する場合は[explicitly](#types.casting)であるべきで、言語自体の複雑な変換ルールが残っているべきではありません。 58 | 59 | -------------------------------------------------------------------------------- /doc/ja/types/instanceof.md: -------------------------------------------------------------------------------- 1 | ## `instanceof`オペレーター 2 | 3 | `instanceof`オペレーターは2つのオペランドのコンストラクタを比較します。これはカスタムで作ったオブジェクトを比較する時にのみ有用です。組み込みの型に使用するのは[typeof operator](#types.typeof)を使用するのと同じくらい意味がありません。 4 | 5 | ### カスタムオブジェクトの比較 6 | 7 | function Foo() {} 8 | function Bar() {} 9 | Bar.prototype = new Foo(); 10 | 11 | new Bar() instanceof Bar; // true 12 | new Bar() instanceof Foo; // true 13 | 14 | // これは単に関数オブジェクトFooにBar.prototypeをセットしただけです。 15 | // しかし、実際のFooのインスタンスではありません。 16 | Bar.prototype = Foo; 17 | new Bar() instanceof Foo; // false 18 | 19 | ### ネイティブ型で`instanceof`を使用する 20 | 21 | new String('foo') instanceof String; // true 22 | new String('foo') instanceof Object; // true 23 | 24 | 'foo' instanceof String; // false 25 | 'foo' instanceof Object; // false 26 | 27 | ここで1つ重要な事は、異なるJavaScriptのコンテキスト(例えば、ブラウザの異なるウィンドウ)を元としたオブジェクトでは、コンストラクタが厳密に同じものでは無い為に`instanceof`は上手く動作しません。 28 | 29 | ### 終わりに 30 | 31 | `instanceof`オペレーターは同じJavaScriptのコンテキストが起源になっているカスタムメイドのオブジェクトを扱う場合**のみ**使うべきです。ちょうど[`typeof`](#types.typeof)オペレーターのように、その他での使用は**避けるべき**です。 32 | -------------------------------------------------------------------------------- /doc/ko/array/constructor.md: -------------------------------------------------------------------------------- 1 | ## `배열` 생성자 2 | 3 | 배열을 만들때 `배열` 생성자에 파라미터를 넣어 만드는 방법은 헷갈릴수있다. 그래서 항상 각 괄호(`[]`) 노테이션을 이용해 배열을 만들 것을 권한다 4 | 5 | [1, 2, 3]; // Result: [1, 2, 3] 6 | new Array(1, 2, 3); // Result: [1, 2, 3] 7 | 8 | [3]; // Result: [3] 9 | new Array(3); // Result: [] 10 | new Array('3') // Result: ['3'] 11 | 12 | `배열` 생성자에 숫자를 인자로 넣으면 그 숫자 크기 만큼의 빈 `배열`을 반환한다. 즉 배열의 `length`는 그 숫자가 된다. 이때 생성자는 **단지** `length` 프로퍼티에 그 숫자를 할당하기만 하고 `배열`은 실제로 초기화 하지도 않는다. 13 | 14 | var arr = new Array(3); 15 | arr[1]; // undefined 16 | 1 in arr; // false, 이 인덱스는 초기화되지 않음. 17 | 18 | `for`문을 사용하지 않고 문자열을 더하는 경우에는 length 프로퍼티에 숫자를 할당해주는 기능이 유용할 때도 있다. 19 | 20 | new Array(count + 1).join(stringToRepeat); 21 | 22 | ### 결론 23 | 24 | `배열` 생성자는 가능하면 사용하지 말고, 각 괄호 (`[]`) 노테이션이을 사용하자. 후자가 더 간략하고 명확할 뿐만 아니라 보기도 좋다. 25 | -------------------------------------------------------------------------------- /doc/ko/array/general.md: -------------------------------------------------------------------------------- 1 | ## 배열 순회와 프로퍼티 2 | 3 | JavaScript에서는 배열(Array)도 객체(Object)지만 객체 순회(Iterate)를 할 때 [`for in`](#object.forinloop)을 사용해서 좋을 게 없다. 실제로 배열을 탐색할때 `for in`문 사용하지 말아야 할 이유가 매우 많다. 4 | 5 | > **Note:** JavaScript의 배열은 *연관 배열(Associative Array)*이 **아니다**. JavaScript는 오직 key/value를 맵핑한 [객체](#object.general)만 있을 뿐이다. 연관 배열은 순서를 보장해주지만 객체는 순서를 보장하지 않는다. 6 | 7 | `for in`은 프로토타입 체인에 있는 프로퍼티를 모두 훑는(enumerate) 데다가 객체 자신의 프로퍼티만 훑으려면 [`hasOwnProperty`](#object.hasownproperty)를 사용해야 하기 때문에 `for`보다 20배 느리다. 8 | 9 | ### 배열 순회 10 | 11 | 배열을 순회 할때는 일반적인 `for`문을 사용하는 것이 가장 빠르다. 12 | 13 | var list = [1, 2, 3, 4, 5, ...... 100000000]; 14 | for(var i = 0, l = list.length; i < l; i++) { 15 | console.log(list[i]); 16 | } 17 | 18 | 이 예제에서 `l = list.length`로 배열의 length 값을 캐시해야 한다는 것을 꼭 기억해야 한다. 19 | 20 | 매번 반복할때마다 배열에 있는 `length` 프로퍼티에 접근하는 것은 좀 부담스럽다. 최신 JavaScript 엔진은 이 일을 알아서 처리해주기도 하지만 코드가 늘 새 엔진에서 실행되도록 보장할 방법이 없다. 21 | 22 | 실제로 캐시 하지 않으면 성능이 반으로 줄어든다. 23 | 24 | ### `length` 프로퍼티 25 | 26 | `length` 프로퍼티의 *getter*는 단순히 Array 안에 있는 엘리먼트의 개수를 반환하고 *setter*는 배열을 할당한 수만큼 잘라 버린다. 27 | 28 | var foo = [1, 2, 3, 4, 5, 6]; 29 | foo.length = 3; 30 | foo; // [1, 2, 3] 31 | 32 | foo.length = 6; 33 | foo; // [1, 2, 3] 34 | 35 | 현재 크기보다 더 작은 값을 할당하면 배열을 자르지만, 현재 크기보다 더 큰 값을 할당한다고 해서 배열을 늘리진 않는다. 36 | 37 | ### 결론 38 | 39 | 최적의 성능을 위해서는 `for`문을 사용하고 `length` 프로퍼티 값을 캐시해야 한다. 배열에 `for in`을 사용하면 성능도 떨어지고 버그 나기도 쉽다. 40 | -------------------------------------------------------------------------------- /doc/ko/core/delete.md: -------------------------------------------------------------------------------- 1 | ## `delete` 연산자 2 | 3 | 간단히 말해서 전역 변수와 전역 함수 그리고 `DontDelete` 속성을 가진 자바스크립트 객체는 삭제할 수 없다. 4 | 5 | ### Global 코드와 Function 코드 6 | 7 | 전역이나 함수 스코프에 정의한 함수나 변수는 모두 Activation 객체나 전역 객체의 프로퍼티다. 이 프로퍼티는 모두 `DontDelete` 속성을 가진다. 전역이나 함수 코드에 정의한 변수와 함수는 항상 `DontDelete` 프로퍼티로 만들어지기 때문에 삭제될 수 없다: 8 | 9 | // Global 변수: 10 | var a = 1; // DontDelete가 설정된다. 11 | delete a; // false 12 | a; // 1 13 | 14 | // Function: 15 | function f() {} // DontDelete가 설정된다. 16 | delete f; // false 17 | typeof f; // "function" 18 | 19 | // 다시 할당해도 삭제할 수 없다: 20 | f = 1; 21 | delete f; // false 22 | f; // 1 23 | 24 | ### 명시적인(Explicit) 프로퍼티 25 | 26 | 다음 예제에서 만드는 프로퍼티는 delete할 수 있다. 이런 걸 명시적인(Explicit) 프로퍼티라고 부른다: 27 | 28 | // Explicit 프로퍼티를 만든다: 29 | var obj = {x: 1}; 30 | obj.y = 2; 31 | delete obj.x; // true 32 | delete obj.y; // true 33 | obj.x; // undefined 34 | obj.y; // undefined 35 | 36 | `obj.x`와 `obj.y`는 `DontDelete` 속성이 아니라서 delete할 수 있다. 하지만 다음과 같은 코드도 잘 동작하기 때문에 헷갈린다: 37 | 38 | // IE를 빼고 잘 동작한다: 39 | var GLOBAL_OBJECT = this; 40 | GLOBAL_OBJECT.a = 1; 41 | a === GLOBAL_OBJECT.a; // true - 진짜 Global 변수인지 확인하는 것 42 | delete GLOBAL_OBJECT.a; // true 43 | GLOBAL_OBJECT.a; // undefined 44 | 45 | [`this`](#function.this)가 전역 객체를 가리키는 것을 이용해서 명시적으로 프로퍼티 `a`를 선언하면 삭제할 수 있다. 이것은 꼼수다. 46 | 47 | IE (적어도 6-8)는 버그가 있어서 안 된다. 48 | 49 | ### Argument들과 Function의 기본 프로퍼티 50 | 51 | Function의 [`arguments` 객체](#function.arguments)와 기본 프로퍼티도 `DontDelete` 속성이다. 52 | 53 | // Function의 arguments와 프로퍼티: 54 | (function (x) { 55 | 56 | delete arguments; // false 57 | typeof arguments; // "object" 58 | 59 | delete x; // false 60 | x; // 1 61 | 62 | function f(){} 63 | delete f.length; // false 64 | typeof f.length; // "number" 65 | 66 | })(1); 67 | 68 | ### Host 객체 69 | 70 | > **역주:** Host 객체는 document같은 DOM 객체를 말한다. 71 | 72 | Host 객체를 delete하면 어떻게 될지 알 수 없다. 표준에는 어떻게 Host 객체를 delete해야 하는지 정의하지 않았다. 73 | 74 | ### 결론 75 | 76 | `delete` 연산자는 엉뚱하게 동작할 때가 많다. 명시적으로 정의한 일반 객체의 프로퍼티만 delete하는 것이 안전하다. 77 | -------------------------------------------------------------------------------- /doc/ko/core/eval.md: -------------------------------------------------------------------------------- 1 | ## 왜 `eval`을 사용하면 안 될까? 2 | 3 | `eval` 함수는 JavaScript 문자열을 지역 스코프에서 실행한다. 4 | 5 | var foo = 1; 6 | function test() { 7 | var foo = 2; 8 | eval('foo = 3'); 9 | return foo; 10 | } 11 | test(); // 3 12 | foo; // 1 13 | 14 | `eval`함수는 `eval`이라는 이름으로 **직접** 실행할 때에만 지역 스코프에서 실행된다. 그리고 `eval`이라는 이름에 걸맞게 악명또한 높다. 15 | 16 | var foo = 1; 17 | function test() { 18 | var foo = 2; 19 | var bar = eval; 20 | bar('foo = 3'); 21 | return foo; 22 | } 23 | test(); // 2 24 | foo; // 3 25 | 26 | 어쨌든 `eval`은 사용하지 말아야 한다. eval을 사용하는 99.9%는 사실 eval 없이도 만들수있다. 27 | 28 | ### 가짜 `eval` 29 | 30 | [`setTimeout`과 `setInterval`](#other.timeouts)은 첫 번째 인자로 스트링을 입력받을 수 있다. 이 경우에는 `eval`을 직접 호출하는 것이 아니라서 항상 Global Scope에서 실행된다. 31 | 32 | ### 보안 이슈 33 | 34 | `eval`은 어떤 코드라도 **무조건** 실행하기 때문에 보안 문제도 있다. 따라서 신뢰하지 못하거나 모르는 코드가 포함되어 있을 경우 **절대로** 사용해서는 안된다. 35 | 36 | ### 결론 37 | 38 | `eval`은 사용하지 않는 게 좋다. `eval`을 사용하는 모든 코드는 성능, 보안, 버그 문제를 일으킬 수 있다. 만약 `eval`이 필요해지면 *설계를 변경*하여 `eval`이 필요 없게 만들어야 한다. 39 | -------------------------------------------------------------------------------- /doc/ko/core/undefined.md: -------------------------------------------------------------------------------- 1 | ## `undefined`와 `null` 2 | 3 | JavaScript는 `nothing`을 표현할때 `null`과 `undefined` 두 가지로 표현할 수 있고 그중 `undefined`가 더 유용하다. 4 | 5 | ### `undefined`도 변수 6 | 7 | `undefined`는 `undefined`라는 값을 가지는 데이터 형식이다. 8 | 9 | `undefined`는 상수도 아니고 JavaScript의 키워드도 아니다. 그냥 `undefined`라는 이름의 Global 변수이고 이 변수에는 `undefined`라고 할당돼 있다. 그래서 이 Global 변수의 값을 쉽게 바꿀 수 있다. 10 | 11 | > **ES5 Note:** ECMAScript 5의 strict 모드에서는 `undefined`를 더는 바꿀 수 없도록 했다. 하지만 `undefined`라는 함수를 만들면 여전히 할당할 수 있다. 12 | 13 | `undefined` 값이 반환될 때: 14 | 15 | - global 변수 `undefined`에 접근할 때. 16 | - 선언은 했지만 아직 초기화하지 않은 변수에 접근할 때. 17 | - `return` 구문이 없는 함수는 암묵적으로 `undefined`를 반환함. 18 | - `return` 구문으로 아무것도 반환하지 않을 때. 19 | - 없는 프로퍼티를 찾을 때. 20 | - 함수 인자가 생략될 때. 21 | - `undefined`가 할당된 모든 것. 22 | - `void(expression)` 형식으로 된 표현 23 | 24 | > **역주:** 예를 들어 CoffeeScript Compliler는 CoffeeScript의 `undefined`를 JavaScript의 `void 0`로 컴파일한다. 25 | 26 | ### `undefined`가 바뀔 때를 대비하기 27 | 28 | global 변수 `undefined`는 `undefined`라는 객체를 가리키는 것뿐이기 때문에 새로운 값을 할당한다고 해도 `undefined`의 값 자체가 바뀌는 것이 아니다. 29 | 30 | 그래서 `undefined`와 비교하려면 먼저 `undefined`의 값을 찾아와야 한다. 31 | 32 | `undefined` 변수가 바뀔 때를 대비해서 `undefined`라는 변수를 인자로 받는 [anonymous wrapper](#function.scopes)로 감싸고 인자를 넘기지 않는 꼼수를 사용한다. 33 | 34 | var undefined = 123; 35 | (function(something, foo, undefined) { 36 | // Local Scope에 undefined를 만들어서 37 | // 원래 값을 가리키도록 했다. 38 | 39 | })('Hello World', 42); 40 | 41 | wrapper 안에 변수를 새로 정의하는 방법으로도 같은 효과를 볼 수 있다. 42 | 43 | var undefined = 123; 44 | (function(something, foo) { 45 | var undefined; 46 | ... 47 | 48 | })('Hello World', 42); 49 | 50 | 이 두 방법의 차이는 minified했을 때 4바이트만큼 차이 난다는 것과 한쪽은 wrapper 안에 var 구문이 없다는 것밖에 없다. 51 | 52 | ### `Null` 객체의 용도 53 | 54 | JavaScript 언어에서는 `undefined`를 다른 언어의 *null* 처럼 쓴다. 진짜 `null`은 그냥 데이터 타입 중 하나일 뿐이지 더도덜도 아니다. 55 | 56 | JavaScript를 깊숙히 건드리는 것이 아니면 null 대신 `undefined`를 사용해도 된다(`Foo.prototype = null`같이 프로토타입 체인을 끊을 때는 null을 사용한다). 57 | -------------------------------------------------------------------------------- /doc/ko/function/closures.md: -------------------------------------------------------------------------------- 1 | ## 클로져(Closure)와 참조(Reference) 2 | 3 | *클로져*는 JavaScript의 특장점 중 하나다. 클로저를 만들면 클로저 스코프 안에서 클로저를 만든 외부 스코프(Scope)에 항상 접근할 있다. JavaScript에서 스코프는 [함수 스코프](#function.scopes)밖에 없기 때문에 기본적으로 모든 함수는 클로저가 될수있다. 4 | 5 | ### private 변수 만들기 6 | 7 | function Counter(start) { 8 | var count = start; 9 | return { 10 | increment: function() { 11 | count++; 12 | }, 13 | 14 | get: function() { 15 | return count; 16 | } 17 | } 18 | } 19 | 20 | var foo = Counter(4); 21 | foo.increment(); 22 | foo.get(); // 5 23 | 24 | 여기서 `Counter`는 `increment` 클로저와 `get` 클로저 두 개를 반환한다. 이 두 클로저는 `Counter` 함수 스코프에 대한 **참조**를 유지하고 있기 때문에 이 함수 스코프에 있는 count 변수에 계속 접근할 수 있다. 25 | 26 | ### Private 변수의 동작 원리 27 | 28 | JavaScript에서는 스코프(Scope)를 어딘가에 할당해두거나 참조할수 없기 때문에 스코프 밖에서는 count 변수에 직접 접근할 수 없다. 접근할수 있는 유일한 방법은 스코프 안에 정의한 두 클로저를 이용하는 방법밖에 없다. 29 | 30 | var foo = new Counter(4); 31 | foo.hack = function() { 32 | count = 1337; 33 | }; 34 | 35 | 위 코드에서 `foo.hack` 함수는 Counter 함수 안에서 정의되지 않았기 때문에 이 함수가 실행되더라도 `Counter` 함수 스코프 안에 있는 count 값은 변하지 않는다. 대신 foo.hack 함수의 `count`는 *Global* 스코프에 생성되거나 이미 만들어진 변수를 덮어쓴다. 36 | 37 | ### 반복문에서 클로저 사용하기 38 | 39 | 사람들이 반복문에서 클로저를 사용할 때 자주 실수를 하는 부분이 있는데 바로 인덱스 변수를 복사할때 발생한다. 40 | 41 | for(var i = 0; i < 10; i++) { 42 | setTimeout(function() { 43 | console.log(i); 44 | }, 1000); 45 | } 46 | 47 | 이 코드는 `0`부터 `9`까지의 수를 출력하지 않고 `10`만 열 번 출력한다. 48 | 49 | 타이머에 설정된 *익명* 함수는 변수 `i`에 대한 참조를 들고 있다가 `console.log`가 호출되는 시점에 `i`의 값을 사용한다. `console.log`가 호출되는 시점에서 `for loop`는 이미 끝난 상태기 때문에 `i` 값은 10이 된다. 50 | 51 | 기대한 결과를 얻으려면 `i` 값을 복사해 두어야 한다. 52 | 53 | ### 앞의 참조 문제 해결하기 54 | 55 | 반복문의 index 값을 복사하는 가장 좋은 방법은 익명함수로 랩핑[Anonymous Wrapper](#function.scopes)하는 방법이다. 56 | 57 | for(var i = 0; i < 10; i++) { 58 | (function(e) { 59 | setTimeout(function() { 60 | console.log(e); 61 | }, 1000); 62 | })(i); 63 | } 64 | 65 | 이 익명 함수에 `i`를 인자로 넘기면 이 함수의 파라미터 e에 i의 **값**이 복사되어 넘어갈 것이다. 66 | 67 | 그리고 `setTimeout`는 익명 함수의 파라미터인 `e`에 대한 참조를 갖게 되고 `e`값은 복사되어 넘어왔으므로 loop의 상태에 따라 변하지 않는다. 68 | 69 | 또다른 방법으로 랩핑한 익명 함수에서 출력 함수를 반환하는 방법도 있다. 아래 코드는 위 코드와 동일하게 동작한다. 70 | 71 | for(var i = 0; i < 10; i++) { 72 | setTimeout((function(e) { 73 | return function() { 74 | console.log(e); 75 | } 76 | })(i), 1000) 77 | } 78 | -------------------------------------------------------------------------------- /doc/ko/function/general.md: -------------------------------------------------------------------------------- 1 | ## 함수 선언과 함수 표현식 2 | 3 | JavaScript에서 함수는 First Class Object다. 즉, 함수 자체가 또 다른 함수의 인자될 수 있다는 말이다. 그래서 익명 함수를 비동기 함수의 콜백으로 넘기는 것도 이런 특징을 이용한 일반적인 사용법이다. 4 | 5 | ### `함수` 선언 6 | 7 | function foo() {} 8 | 9 | 위와 같이 선언한 함수는 프로그램이 실행하기 전에 먼저 [호이스트(Hoist)](#function.scopes) (스코프가 생성)되기 때문에 정의된 스코프(Scope) 안에서는 어디서든 이 함수를 사용할 수 있다. 심지어 함수를 정의하기 전에 호출해도 된다. 10 | 11 | foo(); // 이 코드가 실행되기 전에 foo가 만들어지므로 잘 동작한다. 12 | function foo() {} 13 | 14 | ### `함수` 표현식 15 | 16 | var foo = function() {}; 17 | 18 | 위 예제는 `foo` 변수에 *익명* 함수를 할당한다. 19 | 20 | foo; // 'undefined' 21 | foo(); // TypeError가 난다. 22 | var foo = function() {}; 23 | 24 | 'var'문을 이용해 선언하는 경우, 코드가 실행되기 전에 'foo' 라는 이름의 변수를 스코프의 맨 위로 올리게 된다.(호이스트 된다) 이때 foo 값은 undefiend로 정의된다. 25 | 26 | 하지만 변수에 값을 할당하는 일은 런타임 상황에서 이루어지게 되므로 실제 코드가 실행되는 순간의 `foo`변수는 기본 값인 [undefined](#core.undefined)이 된다. 27 | 28 | ### 이름있는 함수 표현식 29 | 30 | 이름있는 함수를 할당할때도 특이한 경우가 있다. 31 | 32 | var foo = function bar() { 33 | bar(); // 이 경우는 동작 하지만, 34 | } 35 | bar(); // 이 경우는 참조에러를 발생시킨다. 36 | 37 | foo 함수 스코프 밖에서는 foo 변수 외에는 다른 값이 없기 때문에 `bar`는 함수 밖에서 사용할 수 없지만 함수 안에서는 사용할 수 있다. [이와 같은 방법](#function.scopes)으로 자바스크립트에서 어떤 함수의 이름은 항상 그 함수의 지역 스코프 안에서 사용할수있다. -------------------------------------------------------------------------------- /doc/ko/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "JavaScript Garden", 3 | "langTitle": "JavaScript Garden", 4 | "description": "A Guide to JavaScript's Quirks and Flaws.", 5 | "sections": [ 6 | { 7 | "title": "소개", 8 | "dir": "intro", 9 | "articles": ["index"] 10 | }, 11 | { 12 | "title": "객체", 13 | "dir": "object", 14 | "articles": [ 15 | "general", 16 | "prototype", 17 | "hasownproperty", 18 | "forinloop" 19 | ] 20 | }, 21 | { 22 | "title": "함수", 23 | "dir": "function", 24 | "articles": [ 25 | "general", 26 | "this", 27 | "closures", 28 | "arguments", 29 | "constructors", 30 | "scopes" 31 | ] 32 | }, 33 | { 34 | "title": "Array", 35 | "dir": "array", 36 | "articles": [ 37 | "general", 38 | "constructor" 39 | ] 40 | }, 41 | { 42 | "title": "타입", 43 | "dir": "types", 44 | "articles": [ 45 | "equality", 46 | "typeof", 47 | "instanceof", 48 | "casting" 49 | ] 50 | }, 51 | { 52 | "title": "핵심", 53 | "dir": "core", 54 | "articles": [ 55 | "eval", 56 | "undefined", 57 | "semicolon", 58 | "delete" 59 | ] 60 | }, 61 | { 62 | "title": "기타", 63 | "dir": "other", 64 | "articles": [ 65 | "timeouts" 66 | ] 67 | } 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /doc/ko/intro/index.md: -------------------------------------------------------------------------------- 1 | ## Intro 2 | 3 | JavaScript 언어의 핵심에 대한 내용을 모아 **JavaScript Garden**을 만들어 었다. 이 글이 초보자가 JavaScript 익히면서 자주 겪는 실수, 미묘한 버그, 성능 이슈, 나쁜 습관들 줄일 수 있도록 도와줄 것이다. 4 | 5 | JavaScript Garden은 단순히 JavaScript 언어 자체를 설명하려 만들지 않았다. 그래서 이 글에서 설명하는 주제들을 이해하려면 반드시 언어에 대한 기본 지식이 필요하다. 먼저 Mozilla Developer Network에 있는 [문서][1]로 JavaScript 언어를 공부하기 바란다. 6 | 7 | ## 저자들 8 | 9 | 이 글은 [Stack Overflow][2]에서 사랑받는 두 사람 [Ivo Wetzel][3]과 [Zhang Yi Jiang][4]의 작품이다. Ivo Wetzel이 글을 썼고 Zhang Yi jiang이 디자인을 맡았다. 10 | 11 | ## 기여자들 12 | 13 | - [기여자들](https://github.com/BonsaiDen/JavaScript-Garden/graphs/contributors) 14 | 15 | ## 번역 16 | - [박창우][] 17 | - [손병대][] 18 | 19 | [박창우]: https://github.com/pismute 20 | [손병대]: https://github.com/miconblog 21 | 22 | ## 호스팅 23 | 24 | JavaScript Garden은 Github에서 호스팅하고 있고 [Cramer Development][7]가 [JavaScriptGarden.info][8]에서 미러링해주고 있다. 25 | 26 | ## 저작권 27 | 28 | JavaScript Garden은 [MIT license][9]를 따르고 [GitHub][10]에서 호스팅하고 있다. 문제를 발견하면 [이슈를 보고][11]하거나 수정해서 Pull Request를 하라. 아니면 Stack Overflow 채팅 사이트의 [Javascript room][12]에서 우리를 찾으라. 29 | 30 | [1]: https://developer.mozilla.org/en/JavaScript/Guide 31 | [2]: http://stackoverflow.com/ 32 | [3]: http://stackoverflow.com/users/170224/ivo-wetzel 33 | [4]: http://stackoverflow.com/users/313758/yi-jiang 34 | [5]: https://github.com/caio 35 | [6]: https://github.com/blixt 36 | [7]: http://cramerdev.com/ 37 | [8]: http://javascriptgarden.info/ 38 | [9]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE 39 | [10]: https://github.com/BonsaiDen/JavaScript-Garden 40 | [11]: https://github.com/BonsaiDen/JavaScript-Garden/issues 41 | [12]: http://chat.stackoverflow.com/rooms/17/javascript 42 | -------------------------------------------------------------------------------- /doc/ko/object/forinloop.md: -------------------------------------------------------------------------------- 1 | ## `for in` Loop 2 | 3 | 객체의 프로퍼티를 탐색할때 `in` 연산자와 마찬가지로 `for in` 문도 프로토타입 체인까지 탐색한다. 4 | 5 | > **Note:** `for in`문은 배열의 `length`프로퍼티처럼 `enumerable` 속성이 `false`인 프로퍼티는 탐색하지 않는다. 6 | 7 | // Object.prototype을 오염시킨다. 8 | Object.prototype.bar = 1; 9 | 10 | var foo = {moo: 2}; 11 | for(var i in foo) { 12 | console.log(i); // bar와 moo 둘 다 출력한다. 13 | } 14 | 15 | `for in`문에 정의된 기본 동작을 바꿀순 없기 때문에 루프 안에서 불필요한 프로퍼티를 필터링 해야한다. 그래서 `Object.prototype`의 [`hasOwnProperty`](#object.hasownproperty)메소드를 이용해 본래 객체의 프로퍼티만 골라낸다. 16 | 17 | > **Note:** `for in`은 프로토타입 체인을 모두 탐색하기 때문에 상속할 때마다 더 느려진다. 18 | 19 | ### `hasOwnProperty`로 필터링 하기 20 | 21 | // 위의 예제에 이어서 22 | for(var i in foo) { 23 | if (foo.hasOwnProperty(i)) { 24 | console.log(i); 25 | } 26 | } 27 | 28 | 위와 같이 사용해야 올바른 사용법이다. `hasOwnProperty` 때문에 **오직** `moo`만 출력된다. `hasOwnProperty`가 없으면 이 코드는 `Object.prototype`으로 네이티브 객체가 확장될 때 에러가 발생할 수 있다. 29 | 30 | 따라서 [Proptotype 라이브러리][1]처럼 네이티브 객체를 프로토타입으로 확장한 프레임워크를 사용할 경우 `for in` 문에 `hasOwnProperty`를 사용하지 않을 경우 문제가 발생할 수 있다. 31 | 32 | ### 결론 33 | 34 | `hasOwnProperty`를 항상 사용하길 권한다. 실제 코드가 동작하는 환경에서는 절대로 네이티브 객체가 프로토타입으로 확장됐다 혹은 확장되지 않았다를 가정하면 안된다. 35 | 36 | [1]: http://www.prototypejs.org/ 37 | -------------------------------------------------------------------------------- /doc/ko/object/hasownproperty.md: -------------------------------------------------------------------------------- 1 | ## `hasOwnProperty` 2 | 3 | 어떤 객체의 프로퍼티가 자기 자신의 프로퍼티인지 아니면 [프로토타입 체인](#object.prototype)에 있는 것인지 확인하려면 `hasOwnProperty` 메소드를 사용한다. 그리고 이 메소드는 `Object.prototype`으로 부터 상속받아 모든 객체가 가지고 있다. 4 | 5 | > **Note:** hasOwnProperty 메소드로는 어떤 프로퍼티가 존재하는지 확인하는 용도로는 사용할수 있지만, 그 값이 `undefined`일 수 있기 때문에 어떤 프로퍼티의 값이 `undefined`인지 확인하는 용도로 사용하긴 어렵다. 6 | 7 | `hasOwnProperty`메소드는 프로토타입 체인을 탐색하지 않고, 프로퍼티를 다룰수있는 유일한 방법이다. 8 | 9 | // Object.prototype을 오염시킨다. 10 | Object.prototype.bar = 1; 11 | var foo = {goo: undefined}; 12 | 13 | foo.bar; // 1 14 | 'bar' in foo; // true 15 | 16 | foo.hasOwnProperty('bar'); // false 17 | foo.hasOwnProperty('goo'); // true 18 | 19 | `hasOwnProperty` 메소드는 어떤 프로퍼티가 자기 자신의 프로퍼티인지 아닌지 정확하게 알려주기 때문에 객체의 프로퍼티를 순회할때 꼭 필요하다. 그리고 프로토타입 체인 어딘가에 정의된 프로퍼티만을 제외하는 방법은 없다. 20 | 21 | ### `hasOwnProperty` 메소드도 프로퍼티다 22 | 23 | JavaScript는 `hasOwnProperty`라는 이름으로 프로퍼티를 덮어 쓸수도 있다. 그래서 객체 안에 같은 이름으로 정의된 `hasOwnProperty`가 있을 경우, 본래 `hasOwnProperty`의 값을 정확하게 얻고 싶다면 다른 객체의 `hasOwnProperty` 메소드를 빌려써야 한다. 24 | 25 | var foo = { 26 | hasOwnProperty: function() { 27 | return false; 28 | }, 29 | bar: 'Here be dragons' 30 | }; 31 | 32 | foo.hasOwnProperty('bar'); // 항상 false를 반환한다. 33 | 34 | // 다른 객체의 hasOwnProperty를 사용하여 foo 객체의 프로퍼티 유무를 확인한다. 35 | ({}).hasOwnProperty.call(foo, 'bar'); // true 36 | 37 | // Object에 있는 hasOwnProperty를 사용해도 된다. 38 | Object.prototype.hasOwnProperty.call(obj, 'bar'); // true 39 | 40 | 41 | ### 결론 42 | 43 | 어떤 객체에 원하는 프로퍼티가 있는지 확인하는 가장 확실한 방법은 `hasOwnProperty`를 사용하는 것이다. [`for in` loop](#object.forinloop)에서 네이티브 객체에서 확장된 프로퍼티를 제외하고 순회하려면 `hasOwnProperty`와 함께 사용하길 권한다. 44 | -------------------------------------------------------------------------------- /doc/ko/types/casting.md: -------------------------------------------------------------------------------- 1 | ## 타입 캐스팅 2 | 3 | JavaScript는 Weak Typing 언어이기 때문에 필요할 때마다 알아서 타입을 변환한다. 4 | 5 | // 다음은 모두 true 6 | new Number(10) == 10; // Number.toString()이 호출되고 7 | // 다시 Number로 변환된다. 8 | 9 | 10 == '10'; // 스트링은 Number로 변환된다. 10 | 10 == '+10 '; // 이상한 스트링 11 | 10 == '010'; // 엉뚱한 스트링 12 | isNaN(null) == false; // null은 NaN이 아녀서 0으로 변환된다. 13 | 14 | // 다음은 모두 false 15 | 10 == 010; 16 | 10 == '-10'; 17 | 18 | > **ES5 Note:** `0`으로 시작하는 숫자 리터럴은 8진수다. 하지만, ECMAScript 5의 strict 모드에서는 8진수로 더이상 해석하지 않는다. 19 | 20 | 위와 같은 문제들은 ***반드시** [삼중 등호 연산자](#types.equality)를 이용해 해결하길 권한다. 물론 삼중 등호로 많은 결점을 보완할 수 있지만, 여전히 weak typing 시스템 때문에 생기는 많은 문제가 남아있다. 21 | 22 | ### 기본 타입 생성자 23 | 24 | `Number`나 `String` 같은 기본 타입들의 생성자는 `new` 키워드가 있을 때와 없을 때 다르게 동작한다. 25 | 26 | new Number(10) === 10; // False, Object와 Number 27 | Number(10) === 10; // True, Number와 Number 28 | new Number(10) + 0 === 10; // True, 타입을 자동으로 변환해주기 때문에 29 | 30 | `new` 키워드와 함께 `Number` 같은 기본 타입의 생성자를 호출하면 객체를 생성하지만 `new` 없이 호출하면 형 변환만 시킨다. 31 | 32 | 그리고 객체가 아니라 단순히 값이나 리터럴을 사용하면 타입 변환이 더 많이 일어난다. 33 | 34 | 가능한 정확하게 타입을 변환해주는 것이 최선이다. 35 | 36 | ### 스트링으로 변환하기 37 | 38 | '' + 10 === '10'; // true 39 | 40 | 숫자를 빈 스트링과 더하면 쉽게 스트링으로 변환할 수 있다. 41 | 42 | ### 숫자로 변환하기 43 | 44 | +'10' === 10; // true 45 | 46 | `+` 연산자만 앞에 붙여주면 스트링을 쉽게 숫자로 변환할 수 있다. 47 | 48 | ### Boolean으로 변환하기 49 | 50 | '!' 연산자를 두 번 사용하면 쉽게 Boolean으로 변환할 수 있다. 51 | 52 | !!'foo'; // true 53 | !!''; // false 54 | !!'0'; // true 55 | !!'1'; // true 56 | !!'-1' // true 57 | !!{}; // true 58 | !!true; // true 59 | -------------------------------------------------------------------------------- /doc/ko/types/equality.md: -------------------------------------------------------------------------------- 1 | ## 객체 비교하기 2 | 3 | JavaScript에서 객체를 비교하는 방법은 두 가지가 있다. 4 | 5 | ### 이중 등호 연산자 6 | 7 | 이중 등호 연산자는 `==`을 말한다. 8 | 9 | JavaScript는 Weak Typing을 따르기 때문에 이중 등호를 이용해 비교할 때 두 객체의 자료형을 **강제로** 변환한다. 10 | 11 | "" == "0" // false 12 | 0 == "" // true 13 | 0 == "0" // true 14 | false == "false" // false 15 | false == "0" // true 16 | false == undefined // false 17 | false == null // false 18 | null == undefined // true 19 | " \t\r\n" == 0 // true 20 | 21 | 이 표는 이중 등호를 사용하면 왜 안되는지를 보여준다. 이 복잡한 변환 규칙은 실제로 골치 아픈 버그를 만들어 낸다. 22 | 23 | 게다가 강제로 타입을 변환하게 되면 성능에도 영향을 준다. 예를 들어 문자와 숫자를 비교하려면 반드시 먼저 문자를 숫자로 변환해야 한다. 24 | 25 | ### 삼중 등호 연산자 26 | 27 | 삼중 등호 연산자는 `===`을 말한다. 28 | 29 | 삼중 등호는 강제로 타입을 변환하지 않는다는 사실을 제외하면 이중 등호와 동일하다. 30 | 31 | "" === "0" // false 32 | 0 === "" // false 33 | 0 === "0" // false 34 | false === "false" // false 35 | false === "0" // false 36 | false === undefined // false 37 | false === null // false 38 | null === undefined // false 39 | " \t\r\n" === 0 // false 40 | 41 | 위 결과가 훨씬 더 명확하고 문제가 쉽게 드러난다. 삼중 등호를 사용하면 코드를 좀 더 튼튼하게 만들수 있고, 비교하는 두 객체의 타입이 다르면 더 좋은 성능을 얻을 수도 있다. 42 | 43 | ### 객체 비교하기 44 | 45 | 이중 등호와(`==`)와 삼중 등호(`===`)는 둘 다 **값을 비교하는** 연산이지만 피연산자중에 Object 타입이 하나라도 있으면 다르게 동작한다. 46 | 47 | {} === {}; // false 48 | new String('foo') === 'foo'; // false 49 | new Number(10) === 10; // false 50 | var foo = {}; 51 | foo === foo; // true 52 | 53 | 두 연산자 모두 두 객체의 값이 같은지를 비교하지 않고, 두 객체가 **같은 객체(identity)**인지를 비교한다. C에서 포인터를 비교하거나 Python의 is처럼 같은 인스턴스인지 비교하는 것이다. 54 | 55 | ### 결론 56 | 57 | **삼중 등호 연산자**를 사용할 것을 강력하게 권한다. 비교하기 위해서 타입 변환이 필요하면 언어의 복잡한 변환 규칙에 맡기지 말고 꼭 명시적으로 변환한 후에 비교해야 한다. 58 | -------------------------------------------------------------------------------- /doc/ko/types/instanceof.md: -------------------------------------------------------------------------------- 1 | ## `instanceof` 연산자 2 | 3 | `instanceof`연산자는 두 피연산자의 생성자를 비교할때 사용하고 직접 만든 객체를 비교할 때 매우 유용하다. 내장 타입에 쓰는 경우에는 [typeof](#types.typeof)처럼 거의 쓸모가 없다. 4 | 5 | ### 커스텀 객체를 `intanceof`로 비교하기 6 | 7 | function Foo() {} 8 | function Bar() {} 9 | Bar.prototype = new Foo(); 10 | 11 | new Bar() instanceof Bar; // true 12 | new Bar() instanceof Foo; // true 13 | 14 | // Bar.prototype에 함수 객체인 Foo를 할당하면 15 | // Bar의 인스턴스는 Foo의 인스턴스가 아니다. 16 | Bar.prototype = Foo; 17 | new Bar() instanceof Foo; // false 18 | 19 | ### 기본 내장 객체 타입을 `intanceof`로 비교하기 20 | 21 | new String('foo') instanceof String; // true 22 | new String('foo') instanceof Object; // true 23 | 24 | 'foo' instanceof String; // false 25 | 'foo' instanceof Object; // false 26 | 27 | JavaScript 컨텍스트마다(웹 브라우저의 도큐먼트 같은) 객체의 생성자는 다를 수밖에 없어서 `instanceof`는 다른 JavaScript 컨텍스트에 있는(웹 브라우저의 다른 도큐먼트에 있는) 객체와는 비교할 수 없다. 28 | 29 | ### 결론 30 | 31 | `instanceof`는 한 JavaScript 컨텍스트 내에서 사용자가 만든 타입의 객체를 비교할 때에만 유용하다. [`typeof`](#types.typeof)처럼 다른 목적으로는 사용하지 않는 것이 좋다. 32 | -------------------------------------------------------------------------------- /doc/language.json: -------------------------------------------------------------------------------- 1 | { 2 | "default": "en", 3 | "listed": ["en", "fi", "ru", "zhtw", "zh", "tr", "pl", "ko", "ja", "es"] 4 | } 5 | 6 | -------------------------------------------------------------------------------- /doc/pl/array/constructor.md: -------------------------------------------------------------------------------- 1 | ## Konstruktor `Array` 2 | 3 | Zaleca się zawsze korzystać z literału tablicy - notacja `[]` - podczas tworzenia 4 | nowych tablic, ponieważ konstruktor `Array` niejednoznacznie interpretuje 5 | przekazane do niego parametry. 6 | 7 | [1, 2, 3]; // Rezultat: [1, 2, 3] 8 | new Array(1, 2, 3); // Rezultat: [1, 2, 3] 9 | 10 | [3]; // Rezultat: [3] 11 | new Array(3); // Rezultat: [] 12 | new Array('3') // Rezultat: ['3'] 13 | 14 | W przypadku gdy tylko jeden argument zostanie przekazany do kostruktora `Array` i 15 | ten argument jest typu `Number`, konstruktor zwróci nową *dziwną* tablicę 16 | z ustawioną właściwością `length` na wartość przekazaną jako argument. Należy 17 | zauważyć, że **tylko** właściwość `length` zostanie ustawiona w ten sposób. 18 | Rzeczywiste indeksy w tej tablicy nie zostaną zainicjalizowane. 19 | 20 | var arr = new Array(3); 21 | arr[1]; // undefined 22 | 1 in arr; // zwraca false, indeks nie został ustawiony 23 | 24 | Możliwość ustalenia z góry długości tablicy jest użyteczna tylko w kilku 25 | przypadkach, jak np. powtarzanie ciągu znaków, w którym unika się stosowania 26 | pętli `for`. 27 | 28 | // count - ilosc powtorzen 29 | // stringToRepeat - ciąg znaków do powtórzenia 30 | new Array(count + 1).join(stringToRepeat); 31 | 32 | ### Wnioski 33 | 34 | W miarę możliwości należy unikać używania konstruktora `Array`. Literały są 35 | zdecydowanie lepszym rozwiązaniem. Są krótsze i mają bardziej precyzyjną składnię. 36 | Zwiększają również czytelność kodu. 37 | 38 | -------------------------------------------------------------------------------- /doc/pl/core/eval.md: -------------------------------------------------------------------------------- 1 | ## Dlaczego nie należy używać `eval`? 2 | 3 | Funkcja `eval` uruchomi podany string jako kod JavaScript w lokalnym zasięgu (scopie). 4 | 5 | var foo = 1; 6 | function test() { 7 | var foo = 2; 8 | eval('foo = 3'); 9 | return foo; 10 | } 11 | test(); // 3 12 | foo; // 1 13 | 14 | Niestaty, `eval` zostanie wykonana w lokalnym zasięgu tylko wtedy, gdy zostanie wywołana 15 | **bezpośrednio** *i* nazwa wywoływanej funkcji równa sie `eval`. 16 | 17 | var foo = 1; 18 | function test() { 19 | var foo = 2; 20 | var bar = eval; 21 | bar('foo = 3'); 22 | return foo; 23 | } 24 | test(); // 2 25 | foo; // 3 26 | 27 | Należy unikać stosowania `eval` **o ile to tylko możliwe**. W 99.9% przypadków można 28 | osiągnąć ten sam efekt **nie** używając `eval`. 29 | 30 | ### `eval` w przebraniu 31 | 32 | [Funkcje wykonywane po upływie czasu](#other.timeouts) `setTimeout` i `setInterval` 33 | mogą przyjąć string jako pierwszy argument. String ten **zawsze** będzie wykonywany 34 | w globalnym zasięgu, ponieważ funkcja `eval` jest w tym wypadku wywoływana pośrednio. 35 | 36 | ### Problemy z bezpieczeństwem 37 | 38 | Funkcja `eval` jest również problematyczna od strony bezpieczeństwa, ponieważ 39 | wykonuje **każdy** kod, który zostanie do niej przekazany i **nigdy** nie należy 40 | jej używać na stringach nieznanego lub niezaufanego pochodzenia. 41 | 42 | ### Wnioski 43 | 44 | Funkcja `eval` nie powinna być w ogóle używana. Każdy kod, który jej używa 45 | powinien zostać sprawdzony pod względem działania, wydajności i bezpieczeństwa. 46 | W przypadku gdy użycie `eval` jest niezbędne do działania, wówczas taki kod 47 | należy ponownie przemyśleć i *ulepszyć* aby nie wymagał użycia `eval`. 48 | 49 | -------------------------------------------------------------------------------- /doc/pl/function/general.md: -------------------------------------------------------------------------------- 1 | ## Deklaracje funkcji i wyrażenia funkcyjne 2 | 3 | Funcje w języku JavaScript są [typami pierwszoklasowymi][1], co oznacza, że mogą 4 | być przekazywane jak każda inna wartość. Jednym z typowych zastosowań tej cechy 5 | jest przekazywanie *anonimowej funkcji* jako callback do innej, prawdopodobnie 6 | asynchronicznej funkcji. 7 | 8 | ### Deklaracja funkcji 9 | 10 | function foo() {} 11 | 12 | Powyższa funkcja zostaje [wyniesiona](#function.scopes) zanim program wystartuje. Dzięki temu 13 | jest dostępna *wszędzie* w ramach zasięgu, w którym została *zadeklarowana*, 14 | nawet, jeżeli ta funkcja została wywołana przed faktyczną definicją w kodzie źródłowym. 15 | 16 | foo(); // Działa ponieważ definicja funkcji została wyniesiona 17 | // na początek zasięgu przed uruchomieniem kodu 18 | function foo() {} 19 | 20 | ### Wyrażenie funkcyjne 21 | 22 | var foo = function() {}; 23 | 24 | Ten przykład przypisuje nienazwaną i *anonimową* funkcję do zmiennej `foo`. 25 | 26 | foo; // 'undefined' 27 | foo(); // wyrzuca błąd TypeError 28 | var foo = function() {}; 29 | 30 | Ze względu na fakt, że deklaracja `var` wynosi zmienną `foo` na początek zasięgu 31 | zanim kod faktycznie zostanie uruchomiony, `foo` będzie zdefiniowane kiedy skrypt 32 | będzie wykonywany. 33 | 34 | Ale ponieważ przypisania robione są dopiero podczas wykonania, wartość `foo` będzie 35 | ustawiona na domyślną wartość [undefined](#core.undefined) zanim powyższy kod 36 | zostanie uruchomiony. 37 | 38 | ### Nazwane wyrażenia funkcyjne 39 | 40 | Kolejnym specjalnym przypadkiem jest przypisanie nazwanej funkcji. 41 | 42 | var foo = function bar() { 43 | bar(); // Działa 44 | } 45 | bar(); // wyrzuca ReferenceError 46 | 47 | W zewnętrznym zakresie `bar` nie będzie dostępna, ponieważ funkcja zostaje 48 | przypisana do `foo`, jednakże w wewnętrznym zakresie `bar` będzie dostępna. 49 | Jest to spowodowane tym, jak działa [rozwiązywanie nazw](#function.scopes) 50 | w języku JavaScript. Nazwa funkcji jest *zawsze* dostępna w lokalnym 51 | zakresie tej funkcji. 52 | 53 | [1]: http://pl.wikipedia.org/wiki/Typ_pierwszoklasowy 54 | -------------------------------------------------------------------------------- /doc/pl/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "JavaScript Garden", 3 | "langTitle": "JavaScript Garden - ogród JavaScript po polsku", 4 | "description": "Przewodnik po dziwactwach i wadach języka JavaScript.", 5 | "sections": [ 6 | { 7 | "title": "Wstęp", 8 | "dir": "intro", 9 | "articles": [ 10 | "authors", 11 | "contributors", 12 | "translators", 13 | "hosting", 14 | "license" 15 | ] 16 | }, 17 | { 18 | "title": "Obiekty", 19 | "dir": "object", 20 | "articles": [ 21 | "general", 22 | "prototype", 23 | "hasownproperty", 24 | "forinloop" 25 | ] 26 | }, 27 | { 28 | "title": "Funkcje", 29 | "dir": "function", 30 | "articles": [ 31 | "general", 32 | "this", 33 | "closures", 34 | "arguments", 35 | "constructors", 36 | "scopes" 37 | ] 38 | }, 39 | { 40 | "title": "Tablice", 41 | "dir": "array", 42 | "articles": [ 43 | "general", 44 | "constructor" 45 | ] 46 | }, 47 | { 48 | "title": "Typy", 49 | "dir": "types", 50 | "articles": [ 51 | "equality", 52 | "typeof", 53 | "instanceof", 54 | "casting" 55 | ] 56 | }, 57 | { 58 | "title": "Jądro", 59 | "dir": "core", 60 | "articles": [ 61 | "eval", 62 | "undefined", 63 | "semicolon" 64 | ] 65 | }, 66 | { 67 | "title": "Inne", 68 | "dir": "other", 69 | "articles": [ 70 | "timeouts" 71 | ] 72 | } 73 | ] 74 | } 75 | -------------------------------------------------------------------------------- /doc/pl/intro/authors.md: -------------------------------------------------------------------------------- 1 | ## Autorzy 2 | 3 | Ten przewodnik jest dziełem dwóch uroczych użytkowników [Stack Overflow][1], 4 | [Ivo Wetzel][2] (Treść) oraz [Zhang Yi Jiang][3] (Projekt). 5 | 6 | [1]: http://stackoverflow.com/ 7 | [2]: http://stackoverflow.com/users/170224/ivo-wetzel 8 | [3]: http://stackoverflow.com/users/313758/yi-jiang -------------------------------------------------------------------------------- /doc/pl/intro/contributors.md: -------------------------------------------------------------------------------- 1 | ## Współtwórcy 2 | 3 | - [Współtwórcy](https://github.com/BonsaiDen/JavaScript-Garden/graphs/contributors) 4 | 5 | -------------------------------------------------------------------------------- /doc/pl/intro/hosting.md: -------------------------------------------------------------------------------- 1 | ## Hosting 2 | JavaScript Garden znajduje się na serwerach GitHub, ale dzięki wsparciu 3 | [Cramer Development] [1] posiadamy również mirror na serwerze [JavaScriptGarden.info] [2]. 4 | 5 | [1]: http://cramerdev.com/ 6 | [2]: http://javascriptgarden.info/ 7 | -------------------------------------------------------------------------------- /doc/pl/intro/index.md: -------------------------------------------------------------------------------- 1 | ## Wstęp 2 | **JavaScript Garden** jest rosnącą kolekcją dokumentów o najdziwniejszych 3 | częściach języka JavaScript. Dokumentacja pomaga uniknąć najczęściej popełnianych 4 | błędów, sybtelnych bugów, problemów wydajnościowych oraz złych praktyk, na które 5 | niedoświadczeni programiści JavaScript mogą natrafić próbując poznać tajniki tego 6 | języka. 7 | 8 | JavaScript Garden **nie** ma na celu nauczyć Cię języka JavaScript. Podstawowa 9 | wiedza na temat języka jest wymagana do zrozumienia zagadnień poruszanych w tym 10 | przewodniku. Aby nauczyć się podstaw jezyka JavaScript, odwiedź znakomity 11 | [przewodnik][1] na stronach Mozilla Developer Network. 12 | 13 | [1]: https://developer.mozilla.org/en/JavaScript/Guide 14 | -------------------------------------------------------------------------------- /doc/pl/intro/license.md: -------------------------------------------------------------------------------- 1 | ## Licencja 2 | 3 | JavaScript Garden jest publikowany w ramach [licencji MIT] [1] i kod źródłowy znajduje 4 | się na serwerze [GitHub] [2]. Jeśli znajdziesz jakieś błędy lub literówki, zgłoś proszę 5 | [problem] [3] lub rozwiąż go i zgloś pull request ze swojego repozytorium. 6 | Możesz nas także znaleźć w pokoju [JavaScript] [4] na chacie Stack Overflow. 7 | 8 | [1]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE 9 | [2]: https://github.com/BonsaiDen/JavaScript-Garden 10 | [3]: https://github.com/BonsaiDen/JavaScript-Garden/issues 11 | [4]: http://chat.stackoverflow.com/rooms/17/javascript 12 | -------------------------------------------------------------------------------- /doc/pl/intro/translators.md: -------------------------------------------------------------------------------- 1 | ## Tłumaczenie 2 | 3 | - [Łukasz Kufel][1] 4 | - [Maciej Ciemborowicz][2] 5 | 6 | [1]: http://qfel13.pl 7 | [2]: http://blog.ciemborowicz.pl 8 | -------------------------------------------------------------------------------- /doc/pl/object/forinloop.md: -------------------------------------------------------------------------------- 1 | ## Pętla `for in` 2 | 3 | Podobnie jak operator `in`, pętla `for in` przeszukuje łańcuch prototypów 4 | podczas iteracji po właściwościach obiektu. 5 | 6 | > **Uwaga:** pętla `for in` **nie** będzie iterować po właściwościach, które 7 | > mają ustawiony atrybut `enumerable` na `false` (na przykład właściwość 8 | > `length` tablicy). 9 | 10 | // Zatrucie Object.prototype 11 | Object.prototype.bar = 1; 12 | 13 | var foo = {moo: 2}; 14 | for(var i in foo) { 15 | console.log(i); // wyświetla obie właściwości: bar i moo 16 | } 17 | 18 | Ponieważ zmiana zachowania pętli `for in` nie jest możliwa, niezbędne 19 | jest odfiltrowanie niechcianych właściwości wewnątrz ciała pętli, korzystając 20 | z metody [`hasOwnProperty`](#object.hasownproperty) z `Object.prototype`. 21 | 22 | > **Uwaga:** Ponieważ pętla `for in` zawsze przeszukuje cały łańcuch prototypów, 23 | > będzie się ona stawała coraz wolniejsza przy dodaniu każdej kolejnej warstwy 24 | > dziedziczenia do obiektu. 25 | 26 | ### Filtrowania przy użyciu `hasOwnProperty` 27 | 28 | // foo z przykładu powyżej 29 | for(var i in foo) { 30 | if (foo.hasOwnProperty(i)) { 31 | console.log(i); 32 | } 33 | } 34 | 35 | To jest jedyna poprawna wersja, której należy używać. Ze względu na użycie 36 | `hasOwnProperty` zostanie wypisane **jedynie** `moo`. Gdy opuścimy `hasOwnProperty`, 37 | kod będzie podatny na błędy, gdy natywne prototypy (np. `Object.prototype`) 38 | zostaną rozszerzone. 39 | 40 | [Prototype][1] jest jednym z popularniejszych frameworków, które dokonują 41 | takiego rozszerzenia. Używanie tego frameworku oraz nie stosowanie w pętli `for in` 42 | metody `hasOwnProperty` gwarantuje błędy w wykonaniu. 43 | 44 | ### Wnioski 45 | 46 | Zaleca się, aby zawsze używać metody `hasOwnProperty`. Nigdy nie powinno się dokonywać 47 | żadnych założeń na temat środowiska, w którym kod będzie wykonywany ani tego, czy 48 | natywne prototypy zostały rozszerzone, czy nie. 49 | 50 | [1]: http://www.prototypejs.org/ 51 | -------------------------------------------------------------------------------- /doc/pl/object/hasownproperty.md: -------------------------------------------------------------------------------- 1 | ## `hasOwnProperty` 2 | 3 | W celu sprawdzenia, czy dana właściwość została zdefiniowana *w tym* obiekcie, a **nie** 4 | w [łańcuchu prototypów](#object.prototype), niezbędne jest skorzystanie z metody 5 | `hasOwnProperty`, której wszystkie obiekty dziedziczą z `Object.prototype`. 6 | 7 | > **Uwaga:** **Nie** wystarczy sprawdzić, czy właściwość jest `undefined`, 8 | > ponieważ właściwość może istnieć, ale jej wartość być ustawiona na `undefined`. 9 | 10 | `hasOwnProperty` jest jedyną metodą w języku JavaScript, która operuje na właściwościach 11 | i **nie** przegląda całego łańcucha prototypów. 12 | 13 | // Zatrucie Object.prototype 14 | Object.prototype.bar = 1; 15 | var foo = {goo: undefined}; 16 | 17 | foo.bar; // 1 18 | 'bar' in foo; // true 19 | 20 | foo.hasOwnProperty('bar'); // false 21 | foo.hasOwnProperty('goo'); // true 22 | 23 | Tylko `hasOwnProperty` da prawidłowy i oczekiwany rezultat. Jest to istotne podczas 24 | iteracji po właściwościach obiektu. **Nie** ma innego sposobu na ominięcie 25 | właściwości, która nie została zdefiniowana przez ten **konkretny** obiekt, 26 | ale gdzieś indziej w łańcuchu prototypów. 27 | 28 | ### `hasOwnProperty` jako właściwość 29 | 30 | JavaScript **nie** chroni właściwości o nazwie `hasOwnProperty`, zatem istnieje 31 | możliwość, że obiekt będzie posiadać tak nazwaną właściwość. Konieczne jest użycie 32 | *zewnętrznego* `hasOwnProperty`, aby otrzymać poprawne rezultaty. 33 | 34 | var foo = { 35 | hasOwnProperty: function() { 36 | return false; 37 | }, 38 | bar: 'Here be dragons' 39 | }; 40 | 41 | foo.hasOwnProperty('bar'); // zawsze zwraca false 42 | 43 | // Została użyta metoda innego obiektu i wywołana z konkekstem 44 | // `this` ustawionym na foo 45 | ({}).hasOwnProperty.call(foo, 'bar'); // true 46 | 47 | ### Wnioski 48 | 49 | **Jedyną** metodą służącą do sprawdzenia istnienia jakiejś właściwości w konkretnym 50 | obiekcie jest metoda `hasOwnProperty`. Zaleca się korzystać z `hasOwnProperty` w 51 | **każdej** [pętli `for in`](#object.forinloop). Pozwoli to uniknąć błędów pochodzących 52 | z rozszerzonych natywnych [prototypów](#object.prototype). 53 | 54 | -------------------------------------------------------------------------------- /doc/pl/types/instanceof.md: -------------------------------------------------------------------------------- 1 | ## Operator `instanceof` 2 | 3 | Operator `instanceof` porównuje konstruktory obiektów przekazanych jako operendy. 4 | Jest on użyteczny jedynie do porównywania obiektów utworzonych klas. Stosowanie 5 | go na wbudowanych typach jest praktycznie tak samo bezużyteczne, jak operatora 6 | [typeof](#types.typeof). 7 | 8 | ### Porównywanie obiektów utworzonych klas 9 | 10 | function Foo() {} 11 | function Bar() {} 12 | Bar.prototype = new Foo(); 13 | 14 | new Bar() instanceof Bar; // true 15 | new Bar() instanceof Foo; // true 16 | 17 | // poniżej kod który przypisuje do Bar.prototype obiekt funkcji Foo 18 | // a nie faktyczną instancję Foo 19 | Bar.prototype = Foo; 20 | new Bar() instanceof Foo; // false 21 | 22 | ### Stosowanie `instanceof` na natywnych typach 23 | 24 | new String('foo') instanceof String; // true 25 | new String('foo') instanceof Object; // true 26 | 27 | 'foo' instanceof String; // false 28 | 'foo' instanceof Object; // false 29 | 30 | Jedną ważną rzeczą, którą należy zauważyć jest to, że `instanceof` nie zadziała 31 | na obiektach, które pochodzą z różnych kontekstów JavaScript (np. z różnych 32 | dokumentów wewnątrz przeglądarki), ponieważ ich konstruktory nie będą tymi 33 | samymi obiektami. 34 | 35 | ### Wnioski 36 | 37 | Operator `instanceof` powinien być używany **wyłącznie** podczas korzystania z obiektów 38 | klas utworzonych, które były zdefiniowane w tym samym kontekscie JavaScriptowym. 39 | Podobnie jak operator [`typeof`](#types.typeof), należy **unikać** korzystania 40 | z tego operatora w innych sytuacjach. 41 | 42 | -------------------------------------------------------------------------------- /doc/ru/array/constructor.md: -------------------------------------------------------------------------------- 1 | ## Конструктор `Array` 2 | 3 | Так как в конструкторе `Array` есть некоторая двусмысленность касающаяся его параметров, настоятельно рекомендуется при создании массивов всегда использовать синтаксис литеральной нотации — `[]`. 4 | 5 | [1, 2, 3]; // Результат: [1, 2, 3] 6 | new Array(1, 2, 3); // Результат: [1, 2, 3] 7 | 8 | [3]; // Результат: [3] 9 | new Array(3); // Результат: [] 10 | new Array('3') // Результат: ['3'] 11 | 12 | В случае, когда в конструктор `Array` передаётся один аргумент и этот аргумент имеет тип `Number`, конструктор возвращает новый, *заполненный случайными значениями*, массив, имеющий длину равную значению переданного аргумента. Стоит заметить, что в этом случае будет установлено только свойство `length` нового массива, индексы массива фактически не будут проинициализированы. 13 | 14 | var arr = new Array(3); 15 | arr[1]; // не определён, undefined 16 | 1 in arr; // false, индекс не был установлен 17 | 18 | Поведение, которое позволяет изначально установить только размер массива может пригодиться лишь в нескольких случаях, таких как повторение строк, за счёт чего избегается использование цикла `for loop`. 19 | 20 | new Array(count + 1).join(stringToRepeat); 21 | 22 | ### Заключение 23 | 24 | Использование конструктора `Array` нужно избегать, насколько это возможно. Литералы определённо предпочтительнее — это краткая запись и она имеет более понятный синтаксис, так что при этом даже улучшается читабельность кода. 25 | 26 | -------------------------------------------------------------------------------- /doc/ru/array/general.md: -------------------------------------------------------------------------------- 1 | ##  Итерации по массивам и свойства 2 | 3 | Несмотря на то, что массивы в JavaScript являются объектами, нет достаточных оснований для использования [цикла `for in`](#object.forinloop) для итерации по элементам массива. Фактически, существует несколько весомых причин **против** использования `for in` в массивах. 4 | 5 | > **Замечание:** Массивы в JavaScript **не** являются *ассоциативными массивами*. Для связывания ключей и значений в JavaScript есть только [объекты](#object.general). И при том, что ассоциативные массивы **сохраняют** заданный порядок, объекты **не** делают этого. 6 | 7 | Во время выполнения `for in` циклически перебираются все свойства объекта, находящиеся в цепочке прототипов. Единственный способ исключить ненужные свойства — использовать [`hasOwnProperty`](#object.hasownproperty), а это **в 20 раз** медленнее обычного цикла `for`. 8 | 9 | ### Итерирование 10 | 11 | Для достижения лучшей производительности при итерации по массивам, лучше всего использовать обычный цикл `for`. 12 | 13 | var list = [1, 2, 3, 4, 5, ...... 100000000]; 14 | for(var i = 0, l = list.length; i < l; i++) { 15 | console.log(list[i]); 16 | } 17 | 18 | В примере выше есть один дополнительный приём, с помощью которого кэшируется величина длины массива: `l = list.length`. 19 | 20 | Несмотря на то, что свойство `length` определено в самом массиве, поиск этого свойства накладывает дополнительные расходы на каждой итерации цикла. Пусть в этом случае новые движки JavaScript теоретически **могут** применить оптимизацию, но нет никакого способа узнать, будет оптимизирован код на новом движке или нет. 21 | 22 | Фактически, отсутствие кэширования может привести к выполнению цикла в **два раза медленнее**, чем при кэшировании длины 23 | 24 | ### Свойство `length` 25 | 26 | Хотя *геттер* свойства `length` просто возвращает количество элементов содежащихся в массиве, *сеттер* можно использовать для **обрезания** массива. 27 | 28 | var foo = [1, 2, 3, 4, 5, 6]; 29 | foo.length = 3; 30 | foo; // [1, 2, 3] 31 | 32 | foo.length = 6; 33 | foo; // [1, 2, 3] 34 | 35 | Присвоение свойству `length` меньшей величины урезает массив, однако присвоение большего значения не даст никакого эффекта. 36 | 37 | ### Заключение 38 | 39 | Для оптимальной работы кода рекомендуется всегда использовать простой цикл `for` и кэшировать свойство `length`. Использование `for in` с массивами является признаком плохого кода, обладающего предпосылками к ошибкам и может привести к низкой скорости его выполнения. 40 | 41 | -------------------------------------------------------------------------------- /doc/ru/core/eval.md: -------------------------------------------------------------------------------- 1 | ## Почему нельзя использовать `eval` 2 | 3 | Функция `eval` выполняет строку кода JavaScript в локальной области видимости. 4 | 5 | var foo = 1; 6 | function test() { 7 | var foo = 2; 8 | eval('foo = 3'); 9 | return foo; 10 | } 11 | test(); // 3 12 | foo; // 1 13 | 14 | Но `eval` исполняется в локальной области видимости только тогда, когда он вызывается **напрямую** *и при этом* имя вызываемой функции именно `eval`. 15 | 16 | var foo = 1; 17 | function test() { 18 | var foo = 2; 19 | var bar = eval; 20 | bar('foo = 3'); 21 | return foo; 22 | } 23 | test(); // 2 24 | foo; // 3 25 | 26 | **Любой ценой** избегайте использования функции `eval`. 99.9% случаев её "использования" могут достигаться **без её участия**. 27 | 28 | ### `eval` под прикрытием 29 | 30 | Обе [функции работы с интервалами времени](#other.timeouts) `setTimeout` и `setInterval` могут принимать строку в качестве первого аргумента. Эта строка **всегда** будет выполняться в глобальной области видимости, поскольку `eval` в этом случае вызывается *не напрямую*. 31 | 32 | ### Проблемы с безопасностью 33 | 34 | Кроме всего прочего, функция `eval` — это проблема в безопасности, поскольку исполняется **любой** переданный в неё код; **никогда** не следует использовать её со строками из неизвестных или недоверительных источников. 35 | 36 | ### Заключение 37 | 38 | Никогда не стоит использовать `eval`: любое применение такого кода поднимает вопросы о качестве его работы, производительности и безопасности. Если вдруг для работы вам необходим `eval`, эта часть должна тут же ставиться под сомнение и **не** должна использоваться в первую очередь — необходимо найти *лучший способ* , которому не требуются вызовы `eval`. 39 | 40 | -------------------------------------------------------------------------------- /doc/ru/function/general.md: -------------------------------------------------------------------------------- 1 | ## Выражения и объявление функций 2 | 3 | Функции в JavaScript тоже являются объектами (шок, сенсация) — следовательно, их можно передавать и присваивать точно так же, как и любой другой объект. Одним из вариантов использования такой возможности является передача *анонимной функции* как функции обратного вызова в другую функцию — к примеру, для асинхронных вызовов. 4 | 5 | ### Объявление `function` 6 | 7 | // всё просто и привычно 8 | function foo() {} 9 | 10 | В следующем примере описанная функция [резервируется](#function.scopes) перед запуском всего скрипта; за счёт этого она доступна *в любом месте* кода, вне зависимости от того где она *определена* — даже если функция вызывается до её фактического объявления в коде. 11 | 12 | 13 | foo(); // сработает, т.к. функция будет создана до выполнения кода 14 | function foo() {} 15 | 16 | ### `function` как выражение 17 | 18 | var foo = function() {}; 19 | 20 | В этом примере безымянная и *анонимная* функция присваивается переменной `foo`. 21 | 22 | foo; // 'undefined' 23 | foo(); // вызовет TypeError 24 | var foo = function() {}; 25 | 26 | Так как в данном примере выражение `var` — это определение функции, переменная с именем `foo` будет заранее зарезервирована перед запуском скрипта (таким образом, `foo` уже будет определена во время его работы). 27 | 28 | Но поскольку присвоения исполняются непосредственно во время работы кода, `foo` по умолчанию будет присвоено значение [`undefined`](#core.undefined) (до обработки строки с определением функции): 29 | 30 | var foo; // переменная неявно резервируется 31 | foo; // 'undefined' 32 | foo(); // вызовет TypeError 33 | foo = function() {}; 34 | 35 | ### Выражения с именованными фунциями 36 | 37 | Существует еще ньюанс, касающийся именованных функций создающихся через присваивание: 38 | 39 | var foo = function bar() { 40 | bar(); // работает 41 | } 42 | bar(); // получим ReferenceError 43 | 44 | Здесь объект `bar` не доступен во внешней области, так как имя `bar` используется только для присвоения переменной `foo`; однако `bar` можно вызвать внутри функции. Такое поведение связано с особенностью работы JavaScript с [пространствами имен](#function.scopes) - имя функции *всегда* доступно в локальной области видимости самой функции. 45 | 46 | -------------------------------------------------------------------------------- /doc/ru/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "JavaScript Гарден", 3 | "langTitle": "JavaScript Гарден по-русски", 4 | "description": "Руководство по хитростям и трюкам JavaScript.", 5 | "sections": [ 6 | { 7 | "title": "Вступление", 8 | "dir": "intro", 9 | "articles": [ 10 | "authors", 11 | "contributors", 12 | "translators", 13 | "license" 14 | ] 15 | }, 16 | { 17 | "title": "Объекты", 18 | "dir": "object", 19 | "articles": [ 20 | "general", 21 | "prototype", 22 | "hasownproperty", 23 | "forinloop" 24 | ] 25 | }, 26 | { 27 | "title": "Функции", 28 | "dir": "function", 29 | "articles": [ 30 | "general", 31 | "this", 32 | "closures", 33 | "arguments", 34 | "constructors", 35 | "scopes" 36 | ] 37 | }, 38 | { 39 | "title": "Массивы", 40 | "dir": "array", 41 | "articles": [ 42 | "general", 43 | "constructor" 44 | ] 45 | }, 46 | { 47 | "title": "Типы", 48 | "dir": "types", 49 | "articles": [ 50 | "equality", 51 | "typeof", 52 | "instanceof", 53 | "casting" 54 | ] 55 | }, 56 | { 57 | "title": "Нативности", 58 | "dir": "core", 59 | "articles": [ 60 | "eval", 61 | "undefined", 62 | "semicolon" 63 | ] 64 | }, 65 | { 66 | "title": "Другое", 67 | "dir": "other", 68 | "articles": [ 69 | "timeouts" 70 | ] 71 | }, 72 | { 73 | "title": "Пояснения", 74 | "dir": "appendix", 75 | "articles": [ 76 | "fromtranslators" 77 | ] 78 | } 79 | 80 | ] 81 | } 82 | 83 | -------------------------------------------------------------------------------- /doc/ru/intro/authors.md: -------------------------------------------------------------------------------- 1 | ## Авторы 2 | 3 | Это руководство является результатом работы двух заядлых пользователей Stack Overflow: [Иво Ветцель /Ivo Wetzel/][1] (автора текста) и [Чжан И Цзян /Zhang Yi Jiang/][2] (дизайнера). 4 | 5 | [1]: http://stackoverflow.com/users/170224/ivo-wetzel 6 | [2]: http://stackoverflow.com/users/313758/yi-jiang 7 | 8 | -------------------------------------------------------------------------------- /doc/ru/intro/contributors.md: -------------------------------------------------------------------------------- 1 | ## Участники 2 | 3 | - [Участники](https://github.com/BonsaiDen/JavaScript-Garden/graphs/contributors) 4 | 5 | -------------------------------------------------------------------------------- /doc/ru/intro/index.md: -------------------------------------------------------------------------------- 1 | ## Вступление 2 | 3 | **JavaScript Гарден** — это постоянно обновляющаяся и растущая документация по самым заковыристым темам языка JavaScript. В ней вы найдёте советы о том, как избежать распространённых ошибок и предсказать появление тех или иных багов. В документации подробно освещены проблемы оптимизации и нерекомендуемые практики с которыми, продираясь к глубинам языка, могут столкнуться даже просвещённые JavaScript-программисты. 4 | 5 | JavaScript Гарден **не** имеет цели научить вас языку JavaScript. Вам понадобится реальный опыт работы с языком чтобы понимать темы, рассматриваемые в этом руководстве. Если вам требуется изучить основы языка, пожалуйста внимательно ознакомьтесь с замечательным [руководством][1] на сайте Mozilla Developer Network. 6 | 7 | [1]: https://developer.mozilla.org/en/JavaScript/Guide 8 | 9 | -------------------------------------------------------------------------------- /doc/ru/intro/license.md: -------------------------------------------------------------------------------- 1 | ## Лицензия 2 | 3 | JavaScript Гарден распространяется под [лицензией MIT][1] и располагается на [GitHub][2]. Если вы найдёте ошибку или опечатку, пожалуйста [сообщите нам о ней][3] или запросите права на загрузку в репозиторий. Кроме того, вы можете найти нас в [комнате JavaScript][4] среди чатов Stack Overflow. 4 | 5 | [1]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE 6 | [2]: https://github.com/BonsaiDen/JavaScript-Garden 7 | [3]: https://github.com/BonsaiDen/JavaScript-Garden/issues 8 | [4]: http://chat.stackoverflow.com/rooms/17/javascript 9 | 10 | -------------------------------------------------------------------------------- /doc/ru/intro/translators.md: -------------------------------------------------------------------------------- 1 | ## Переводчики 2 | 3 | - ['shaman.sir'][1] 4 | - [Антон Шевчук][2] 5 | - [Максим Лозовой][3] 6 | - [Елена Пашкова][4] 7 | 8 | [1]: http://shamansir.madfire.net/ 9 | [2]: http://anton.shevchuk.name/ 10 | [3]: http://nixsolutions.com/ 11 | [4]: http://nixsolutions.com/ 12 | 13 | -------------------------------------------------------------------------------- /doc/ru/object/forinloop.md: -------------------------------------------------------------------------------- 1 | ## Цикл `for in` 2 | 3 | Как и оператор `in`, цикл `for in` проходит по всей цепочке прототипов обходя свойства объекта. 4 | 5 | > **Примечание:** Цикл `for in` **не** обходит те свойства объекта, у которых атрибут `enumerable` установлен в `false`; как пример - свойство `length` у массивов 6 | 7 | // Испортим Object.prototype 8 | Object.prototype.bar = 1; 9 | 10 | var foo = {moo: 2}; 11 | for(var i in foo) { 12 | console.log(i); // печатает и bar и moo 13 | } 14 | 15 | Так как изменить поведение цикла `for in` как такового не представляется возможным, то для фильтрации нежелательных свойств объекта внутри этого цикла используют метод [`hasOwnProperty`](#object.hasownproperty) из `Object.prototype`. 16 | 17 | > **Примечание:** Цикл `for in` всегда обходит всю цепочку прототипов полностью: таким образом, чем больше прототипов (слоёв наследования) в цепочке, тем медленнее работает цикл. 18 | 19 | ### Использование `hasOwnProperty` в качестве фильтра 20 | 21 | // возьмём foo из примера выше 22 | for(var i in foo) { 23 | if (foo.hasOwnProperty(i)) { 24 | console.log(i); 25 | } 26 | } 27 | 28 | Это единственная версия правильного использования цикла. Благодаря использованию `hasOwnPropery` будет выведено **только** свойство `moo`. Если же убрать `hasOwnProperty`, код становится нестабилен и могут возникнуть ошибки, особенно если кто-то изменил встроенные прототипы, такие как `Object.prototype`. 29 | 30 | Один из самых популярных фреймворков [Prototype][1] как раз этим и славится, и если вы его подключаете, то не забудьте использовать `hasOwnProperty` внутри цикла `for in`, иначе у вас гарантированно возникнут проблемы. 31 | 32 | ### Рекомендации 33 | 34 | Рекомендация одна — **всегда** используйте `hasOwnProperty`. Пишите код, который будет в наименьшей мере зависеть от окружения, в котором он будет запущен — не стоит гадать, расширял кто-то прототипы или нет и используется ли в ней та или иная библиотека. 35 | 36 | [1]: http://www.prototypejs.org/ 37 | 38 | -------------------------------------------------------------------------------- /doc/ru/object/hasownproperty.md: -------------------------------------------------------------------------------- 1 | ## Функция `hasOwnProperty` 2 | 3 | Если вам необходимо проверить, определено ли свойство у *самого объекта*, а **не** в его [цепочке прототипов](#object.prototype), вы можете использовать метод `hasOwnProperty`, который все объекты наследуют от `Object.prototype`. 4 | 5 | > **Примечание:** Для проверки наличия свойства **недостаточно** проверять, эквивалентно ли оно `undefined`. Свойство может вполне себе существовать, но при этом ему может быть присвоено значение `undefined`. 6 | 7 | `hasOwnProperty` — единственная функция в JavaScript, которая позволяет получить свойства объекта **без обращения** к цепочке его прототипов. 8 | 9 | // испортим Object.prototype 10 | Object.prototype.bar = 1; 11 | var foo = {goo: undefined}; 12 | 13 | foo.bar; // 1 14 | 'bar' in foo; // true 15 | 16 | foo.hasOwnProperty('bar'); // false 17 | foo.hasOwnProperty('goo'); // true 18 | 19 | Только используя `hasOwnProperty` можно гарантировать правильный результат при переборе свойств объекта. И **нет** иного способа для определения свойств, которые определены в *самом* объекте, а не где-то в цепочке его прототипов. 20 | 21 | ### `hasOwnProperty` как свойство 22 | 23 | JavaScript **не** резервирует свойство с именем `hasOwnProperty`. Так что, если есть потенциальная возможность, что объект может содержать свойство с таким именем, требуется использовать *внешний* вариант функции `hasOwnProperty` чтобы получить корректные результаты. 24 | 25 | var foo = { 26 | hasOwnProperty: function() { 27 | return false; 28 | }, 29 | bar: 'Да прилетят драконы' 30 | }; 31 | 32 | foo.hasOwnProperty('bar'); // всегда возвращает false 33 | 34 | // Используем метод hasOwnProperty пустого объекта 35 | // и передаём foo в качестве this 36 | ({}).hasOwnProperty.call(foo, 'bar'); // true 37 | 38 | ### Заключение 39 | 40 | **Единственным** способом проверить существование свойства у объекта является использование метода `hasOwnProperty`. При этом, рекомендуется использовать этот метод в **каждом** [цикле `for in`](#object.forinloop) вашего проекта, чтобы избежать возможных ошибок с ошибочным заимствованием свойств из [прототипов](#object.prototype) родительских объектов. Также вы можете использовать конструкцию `{}.hasOwnProperty.call(...)` на случай, если кто-то вздумает расширить [прототипы](#object.prototype) встроенных объектов. 41 | 42 | -------------------------------------------------------------------------------- /doc/ru/types/instanceof.md: -------------------------------------------------------------------------------- 1 | ## Оператор `instanceof` 2 | 3 | Оператор `instanceof` сравнивает конструкторы двух операндов. Это полезно только когда сравниваются пользовательские объекты. Использование на встроенных типах почти так же бесполезно, как и [оператор typeof](#types.typeof). 4 | 5 | ### Сравнение пользовательских объектов 6 | 7 | function Foo() {} 8 | function Bar() {} 9 | Bar.prototype = new Foo(); 10 | 11 | new Bar() instanceof Bar; // true 12 | new Bar() instanceof Foo; // true 13 | 14 | // Всего лишь присваиваем Bar.prototype объект функции Foo, 15 | // но не экземпляра Foo 16 | Bar.prototype = Foo; 17 | new Bar() instanceof Foo; // false 18 | 19 | ### Использование `instanceof` со встроенными типами 20 | 21 | new String('foo') instanceof String; // true 22 | new String('foo') instanceof Object; // true 23 | 24 | 'foo' instanceof String; // false 25 | 'foo' instanceof Object; // false 26 | 27 | Здесь надо отметить одну важную вещь: `instanceof` не работает на объектах, которые происходят из разных контекстов JavaScript (например, из различных документов в web-браузере), так как их конструкторы и правда не будут конструкторами *тех самых* объектов. 28 | 29 | ### Заключение 30 | 31 | Оператор `instanceof` должен использоваться **только** при обращении к пользовательским объектам, происходящим из одного контекста JavaScript. Так же, как и в случае оператора `typeof`, любое другое использование необходимо **избегать**. 32 | 33 | -------------------------------------------------------------------------------- /doc/tr/array/constructor.md: -------------------------------------------------------------------------------- 1 | ## `Array` Oluşturucusu 2 | 3 | `Array` oluşturucusunun parametrelerini nasıl değerlendirdiği belirsiz olduğu 4 | için, yeni diziler oluşturulurken her zaman dizi sabitlerinin (`[]` 5 | notasyonu) kullanılması tavsiye olunur. 6 | 7 | [1, 2, 3]; // Sonuç: [1, 2, 3] 8 | new Array(1, 2, 3); // Sonuç: [1, 2, 3] 9 | 10 | [3]; // Sonuç: [3] 11 | new Array(3); // Sonuç: [] 12 | new Array('3') // Sonuç: ['3'] 13 | 14 | `Array` oluşturucusuna tek bir argüman verildiğinde, ve bu argümanın türü 15 | `Number` ise, oluşacak *boş* dizinin `length` özelliği argümanın 16 | değerine eşit olacaktır. Bu şekilde oluşturulan bir dizinin **sadece** 17 | `length` özelliği belirlenmiş olup dizi indisleri tanımsız olacaktır. 18 | 19 | var arr = new Array(3); 20 | arr[1]; // undefined 21 | 1 in arr; // false, indisler atanmadı 22 | 23 | Dizinin uzunluğunu bu şekilde önceden belirlemek sadece bir iki durumda 24 | kullanışlıdır. Bunlardan birisi bir döngüye gerek olmadan bir karakter 25 | katarını tekrarlamaktır. 26 | 27 | new Array(count + 1).join(stringToRepeat); 28 | 29 | ### Sonuç 30 | 31 | `Array` oluşturucusunun kullanılmasından mümkün olduğu kadar kaçınılmalıdır. 32 | Bunun yerine her zaman dizi sabitleri tercih edilmelidir. Hem daha kısadırlar 33 | hem de daha anlaşılır bir sentaksa sahiptirler; bu nedenle programın 34 | okunabilirliğini de artırırlar. 35 | 36 | -------------------------------------------------------------------------------- /doc/tr/array/general.md: -------------------------------------------------------------------------------- 1 | ## Dizi İterasyonu ve Özellikleri 2 | 3 | Diziler JavaScript nesneleri olmalarına rağmen, iterasyon yapmak için 4 | [`for in`](#object.forinloop) döngüsü kullanmak için bir neden yoktur. 5 | Aslında dizilerde `for in` kullanılmasına **karşı** bazı iyi nedenler 6 | vardır. 7 | 8 | > **Not:** JavaScript dizileri *associative* **değildir**. JavaScript ile sadece 9 | > [nesneler](#object.general) ile anahtar-değer ilişkilendirmesi mümkündür. 10 | > Ve *associative* diziler eleman sıralamasını **korurlar** ama, nesneler 11 | > **korumazlar**. 12 | 13 | `for in` döngüsü prototip zincirindeki tüm özellikleri dolaştığı için ve bunu 14 | engellemenin tek yolu [`hasOwnProperty`](#object.hasownproperty) kullanmak 15 | olduğu için `for in` döngüsü sıradan bir `for` döngüsünden **yirmi kata kadar** 16 | daha yavaştır. 17 | 18 | ### İterasyon 19 | 20 | Dizilerde iterasyon yaparken en iyi performansı elde etmenin en iyi yolu klasik 21 | `for` döngüsünü kullanmaktır. 22 | 23 | var list = [1, 2, 3, 4, 5, ...... 100000000]; 24 | for(var i = 0, l = list.length; i < l; i++) { 25 | console.log(list[i]); 26 | } 27 | 28 | Yukarıdaki örnekte bir optimizasyon var, o da dizinin uzunluğun iterasyonun 29 | başında `l = list.length` ile saklanmış olması. 30 | 31 | `length` özelliği dizinin kendisinde tariflenmiş olmasına rağmen, her adımda 32 | bu özelliği okumanın yine de bir maliyeti vardır. Modern JavaScript motorları 33 | bu tür durumlar için **muhtemelen** optimizasyon yapıyor olsa bile, programın 34 | her zaman modern bir motorda çalışacağından emin olmak mümkün değildir. 35 | 36 | Aslında, yukarıdaki örnekteki optimizasyonu uygulamamak döngünün 37 | **iki kat daha** yavaş çalışmasına neden olabilir. 38 | 39 | ### `length` özelliği 40 | 41 | `length` özelliğine değer atanarak diziyi **kısaltmak** için kullanılabilir. 42 | 43 | var foo = [1, 2, 3, 4, 5, 6]; 44 | foo.length = 3; 45 | foo; // [1, 2, 3] 46 | 47 | foo.length = 6; 48 | foo; // [1, 2, 3] 49 | 50 | Daha küçük bir uzunluk atanması diziyi kısaltır, fakat daha büyük bir uzunluk 51 | atanmasının dizi üzerinde bir etkisi yoktur. 52 | 53 | ### Sonuç 54 | 55 | En iyi performans için her zaman sıradan `for` döngüsü kullanılmalı ve 56 | `length` özelliği saklanmalıdır. Dizilerde `for in` döngüsünün kullanılmış 57 | olması hatalara meyilli kötü yazılmış bir programa işaret eder. 58 | 59 | -------------------------------------------------------------------------------- /doc/tr/core/eval.md: -------------------------------------------------------------------------------- 1 | ## Neden `eval` Kullanılmamalı 2 | 3 | `eval` fonksiyonu bir JavaScript kodunu lokal kapsamda yürütür. 4 | 5 | var foo = 1; 6 | function test() { 7 | var foo = 2; 8 | eval('foo = 3'); 9 | return foo; 10 | } 11 | test(); // 3 12 | foo; // 1 13 | 14 | Fakat `eval` sadece **direkt olarak** çağrıldığında *ve* çağrılan fonksiyonun 15 | adı `eval` ise lokal kapsamda çalışır. 16 | 17 | var foo = 1; 18 | function test() { 19 | var foo = 2; 20 | var bar = eval; 21 | bar('foo = 3'); 22 | return foo; 23 | } 24 | test(); // 2 25 | foo; // 3 26 | 27 | `eval` fonksiyonu **asla** kullanılmamalıdır. Kullanıldığı durumların %99.9'unda 28 | `eval` **kullanılmadan** da istenen sonuç elde edilebilir. 29 | 30 | ### Gizli `eval` 31 | 32 | [Zamanlama fonksiyonları](#other.timeouts) `setTimeout` ve `setInterval`'ın her 33 | ikisinin de ilk argümanları bir karakter katarıdır. Bu durumda `eval` dolaylı 34 | olarak çağrıldığı için bu argüman **her zaman** genel kapsamda yürütülecektir. 35 | 36 | ### Güvenlik sorunları 37 | 38 | `eval` kendisine verilen **her** kodu işlettiği için aynı zamanda bir güvenlik 39 | sorunudur ve **asla** kaynağı bilinmeyen yada güvenilir olmayan karakter 40 | katarları ile kullanılmamalıdır. 41 | 42 | ### Sonuç 43 | 44 | `eval` asla kullanılmamalıdır, kullanan programlar ise doğruluk, performans ve 45 | güvenlik açılarından sorgulanmalıdır. `eval` kullanımı gerekli görülmüşse, 46 | programın tasarımı sorgulanmalı ve **kullanılmamalı**, bunun yerine `eval` 47 | gerektirmeyen *daha iyi bir tasarım* kullanılmalıdır. 48 | 49 | -------------------------------------------------------------------------------- /doc/tr/function/general.md: -------------------------------------------------------------------------------- 1 | ## Fonksiyon Tanımlaması ve Fonksiyon İfadesi 2 | 3 | Fonksiyonlar JavaScript'te birinci sınıf nesnelerdir, yani sıradan bir değer 4 | gibi kullanılabilirler. Bu özellik sıklıkla bir *isimsiz fonksiyonu* başka bir 5 | fonksiyona - ki bu muhtemelen asenkron bir fonksiyondur - `callback` olarak 6 | geçirmekte kullanılır. 7 | 8 | ### `function` tanımlaması 9 | 10 | function foo() {} 11 | 12 | Yukarıdaki fonksiyon tanımlaması program çalışmadan önce 13 | [yukarı taşınır](#function.scopes) ve böylece *tanımlandığı* kapsam içinde 14 | *her yerde* (hatta tanımlanmadan önce bile) kullanılabilir. 15 | 16 | foo(); // foo bu satır çalışmadan önce oluşturuldu 17 | function foo() {} 18 | 19 | ### `function` ifadesi 20 | 21 | var foo = function() {}; 22 | 23 | Bu örnekte *isimsiz fonksiyon* `foo` değişkenine atanır. 24 | 25 | foo; // 'undefined' 26 | foo(); // Bu satır bir TypeError hatasına neden olur 27 | var foo = function() {}; 28 | 29 | Yukarıdaki `var` anahtar kelimesi bir bildirim olduğu için `foo` değişkeni 30 | program çalışmadan önce yukarı alınır, program çalıştığında `foo` tanımlanmştır. 31 | 32 | Fakat değer atamaları sadece program çalışırken gerçekleşeceği için, ilgili 33 | satır çalıştığında, `foo` değişkeninin değeri varsayılan olarak 34 | [undefined](#core.undefined) olacaktır. 35 | 36 | ### İsimli fonksiyon ifadesi 37 | 38 | Bir başka özel durum isimli fonksiyon ifadesidir. 39 | 40 | var foo = function bar() { 41 | bar(); // Çalışır 42 | } 43 | bar(); // ReferenceError hatası verir 44 | 45 | Burada `bar` fonksiyonuna dış kapsamdan ulaşılamaz, çünkü sadece `foo` 46 | değişkenine atanmıştır; fakat iç kapsamda `bar` fonksiyonuna erişilebilir. 47 | Bunun nedeni JavaScript'te [isim çözümlemenin](#function.scopes) çalışma 48 | şeklidir, fonksiyonun adına fonksiyonun içinden *her zaman* erişilebilir. 49 | 50 | -------------------------------------------------------------------------------- /doc/tr/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "JavaScript Garden", 3 | "langTitle": "JavaScript Garden Türkçe", 4 | "description": "JavaScript'in Acayiplikleri ve Kusurları için bir Rehber.", 5 | "sections": [ 6 | { 7 | "title": "Giriş", 8 | "dir": "intro", 9 | "articles": ["index"] 10 | }, 11 | { 12 | "title": "Nesneler", 13 | "dir": "object", 14 | "articles": [ 15 | "general", 16 | "prototype", 17 | "hasownproperty", 18 | "forinloop" 19 | ] 20 | }, 21 | { 22 | "title": "Fonksiyonlar", 23 | "dir": "function", 24 | "articles": [ 25 | "general", 26 | "this", 27 | "closures", 28 | "arguments", 29 | "constructors", 30 | "scopes" 31 | ] 32 | }, 33 | { 34 | "title": "Diziler", 35 | "dir": "array", 36 | "articles": [ 37 | "general", 38 | "constructor" 39 | ] 40 | }, 41 | { 42 | "title": "Nesne Tipleri", 43 | "dir": "types", 44 | "articles": [ 45 | "equality", 46 | "typeof", 47 | "instanceof", 48 | "casting" 49 | ] 50 | }, 51 | { 52 | "title": "Temel", 53 | "dir": "core", 54 | "articles": [ 55 | "eval", 56 | "undefined", 57 | "semicolon", 58 | "delete" 59 | ] 60 | }, 61 | { 62 | "title": "Diğer", 63 | "dir": "other", 64 | "articles": [ 65 | "timeouts" 66 | ] 67 | } 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /doc/tr/intro/index.md: -------------------------------------------------------------------------------- 1 | ## Giriş 2 | 3 | **JavaScript Garden** JavaScript programlama dilinin acayiplikleri üzerine 4 | derlenmiş bir döküman koleksiyonudur. Henüz ustalaşmamış JavaScript 5 | programcılarının sıkça yaptığı yanlışlar, dile has incelikler ve performans 6 | sorunlarına karşı tavsiyeler içerir. 7 | 8 | JavaScript Garden'ın amacı size JavaScript öğretmek **değildir**. Bu rehberde 9 | anlatılan konuları anlamak için JavaScript dilini önceden biliyor olmanız 10 | gerekir. Eğer JavaScript dilinin temellerini öğrenmek istiyorsanız, lütfen 11 | Mozilla Programcı Ağı'nda bulunan mükemmel [rehbere][1] başvurun. 12 | 13 | ## Yazarlar 14 | 15 | Bu rehber, sevimli birer [Stack Overflow][2] kullanıcısı olan [Ivo Wetzel][3] (Yazım) 16 | ve [Zhang Yi Jiang][4] (Tasarım) tarafından hazırlanmıştır. 17 | 18 | ## Katkıda Bulunanlar 19 | 20 | - [Katkıda Bulunanlar](https://github.com/BonsaiDen/JavaScript-Garden/graphs/contributors) 21 | 22 | ## Sunum 23 | 24 | JavaScript Garden GitHub üzerinden, ve ayrıca [Cramer Development][7] 25 | tarafından desteklenen [JavaScriptGarden.info][8] adresinden sunulmaktadır. 26 | 27 | ## Lisans 28 | 29 | JavaScript Garden [MIT lisansı][9] altında yayınlanmıştır ve [GitHub][10] 30 | üzerinde bulunmaktadır. Eğer rehberde yanlışlıklar veya yazım hatalarına 31 | rastlarsanız lütfen [sorunu bize bildirin][11] veya bir `pull request` gönderin. 32 | Bizi ayrıca Stack Overflow'da [JavaScript sohbet odasında][12] da 33 | bulabilirsiniz. 34 | 35 | [1]: https://developer.mozilla.org/en/JavaScript/Guide 36 | [2]: http://stackoverflow.com/ 37 | [3]: http://stackoverflow.com/users/170224/ivo-wetzel 38 | [4]: http://stackoverflow.com/users/313758/yi-jiang 39 | [5]: https://github.com/caio 40 | [6]: https://github.com/blixt 41 | [7]: http://cramerdev.com/ 42 | [8]: http://javascriptgarden.info/ 43 | [9]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE 44 | [10]: https://github.com/BonsaiDen/JavaScript-Garden 45 | [11]: https://github.com/BonsaiDen/JavaScript-Garden/issues 46 | [12]: http://chat.stackoverflow.com/rooms/17/javascript 47 | 48 | -------------------------------------------------------------------------------- /doc/tr/object/forinloop.md: -------------------------------------------------------------------------------- 1 | ## `for in` Döngüsü 2 | 3 | Tıpkı `in` operatörü gibi `for in` döngüsü de bir nesnenin özellikleri üzerinde 4 | iterasyon yaparken prototip zincirini dolaşır. 5 | 6 | > **Not:** `for in` döngüsü iterasyon yaparken `enumerable` niteliği `false` 7 | > olan özelliklere uğramaz; mesela, bir dizinin `length` özelliğini atlar. 8 | 9 | // Object.prototype'a bar özelliğini ekle 10 | Object.prototype.bar = 1; 11 | 12 | var foo = {moo: 2}; 13 | for(var i in foo) { 14 | console.log(i); // hem bar hem de moo yazar 15 | } 16 | 17 | `for in` döngüsünün davranışını değiştirmek mümkün olmadığı için, istenmeyen 18 | özelliklerin döngünün içinde filtrelenmesi gerekir, bu da `Object.prototype` 19 | nesnesinin [`hasOwnProperty`](#object.hasownproperty) metodu ile yapılır. 20 | 21 | > **Not:** `for in` döngüsü tüm prototip zincirini dolaştığı için bir nesneye 22 | > eklenen her yeni kalıtım katmanı döngüyü biraz daha yavaşlatacaktır. 23 | 24 | ### `hasOwnProperty` kullanarak filtrelemek 25 | 26 | // yukarıdaki örnekteki foo nesnesi 27 | for(var i in foo) { 28 | if (foo.hasOwnProperty(i)) { 29 | console.log(i); 30 | } 31 | } 32 | 33 | Doğru kullanım bu yeni versiyonda gösterildiği gibidir. `hasOwnProperty` kontrol 34 | edildiği için **sadece** `moo` yazacaktır. `hasOwnProperty` kullanılmaz ise ve 35 | `Object.protype` 'ın baz özellikleri değiştirilmişse, program bazı hatalara 36 | yatkın olabilir. 37 | 38 | Bunu yapan ve yaygın olarak kullanılan bir JavaScript sistemi [Prototype][1] 39 | 'dır. Bu sistemde `hasOwnProperty` kullanmayan `for in` döngüleri kesinlikle 40 | hatalı sonuç verecektir. 41 | 42 | ### Sonuç 43 | 44 | `hasOwnProperty` **her zaman** kontrol edilmelidir. Programın içinde çalıştığı 45 | ortam için, nesnelerin baz özelliklerinin değiştirilip değiştirilmediğine dair 46 | hiçbir kabul yapılmamalıdır. 47 | 48 | [1]: http://www.prototypejs.org/ 49 | 50 | -------------------------------------------------------------------------------- /doc/tr/object/hasownproperty.md: -------------------------------------------------------------------------------- 1 | ## `hasOwnProperty` 2 | 3 | Bir özelliğin nesnenin [prototip zinciri](#object.prototype) üzerinde bir yerde 4 | **değil**, *kendisi* üzerinde tanımlandığını belirlemek için, `Object.prototype` 5 | kalıtımı ile tüm nesnelerin sahip olduğu `hasOwnProperty` metodunun kullanılması 6 | gerekir. 7 | 8 | > **Not:** Bir özelliğin `undefined` olduğunu kontrol etmek yeterli **değildir**. 9 | > Bir özelliğin değeri `undefined` olarak atandığı halde özelliğin kendisi 10 | > pekala mevcut olabilir. 11 | 12 | `hasOwnProperty` JavaScript'te nesne özellikleri üzerinde çalışıp prototip 13 | zincirinin tümünü **dolaşmayan** tek şeydir. 14 | 15 | // Object.prototype'a bar özelliğini ekle 16 | Object.prototype.bar = 1; 17 | var foo = {goo: undefined}; 18 | 19 | foo.bar; // 1 20 | 'bar' in foo; // true 21 | 22 | foo.hasOwnProperty('bar'); // false 23 | foo.hasOwnProperty('goo'); // true 24 | 25 | Sadece `hasOwnProperty` beklenen doğru sonucu verecektir, nesne özellikleri 26 | üzerinde iterasyon yaparken bu çok önemlidir. Bir nesnenin *kendisi* üzerinde 27 | değil de protip zinciri üzerinde bir yerde tanımlanmış olan özelliklerini 28 | çıkarmanın başka hiçbir yolu **yoktur**. 29 | 30 | ### `hasOwnProperty` özelliği 31 | 32 | JavaScript `hasOwnProperty` adının bir özellik olarak kullanılmasını engellemez; 33 | bu nedenle bir nesnenin bu isimde bir özelliğe sahip olması ihtimali varsa, 34 | doğru sonuç alabilmek için `hasOwnProperty `*haricen* kullanılmalıdır. 35 | 36 | var foo = { 37 | hasOwnProperty: function() { 38 | return false; 39 | }, 40 | bar: 'Here be dragons' 41 | }; 42 | 43 | foo.hasOwnProperty('bar'); // her zaman false verir 44 | 45 | // hasOwnProperty başka bir nesne üzerinde 46 | // kullanıldığında 'this' foo olur 47 | ({}).hasOwnProperty.call(foo, 'bar'); // true 48 | 49 | ### Sonuç 50 | 51 | Bir nesnenin bir özelliği sahip olup olmadığını kontrol etmek için 52 | kullanılabilecek **tek** yöntem `hasOwnProperty` 'dir. Aynı zamanda, nesne 53 | [prototiplerinin](#object.prototype) genişletilmesinden kaynaklanabilecek 54 | hataların önüne geçmek için, **tüm** [`for in` döngüleri](#object.forinloop) ile 55 | `hasOwnProperty` kullanılması tavsiye olunur. 56 | 57 | -------------------------------------------------------------------------------- /doc/tr/types/instanceof.md: -------------------------------------------------------------------------------- 1 | ## `instanceof` Operatörü 2 | 3 | `instanceof` operatörü verilen iki terimin nesne oluşturucularını karşılaştırır. 4 | Kullanışlı olduğu tek durum özel nesnelerin karşılaştırılmasıdır. Temel nesneler 5 | üzerinde kullanıldığında neredeyse [typeof operatörü](#types.typeof) kadar 6 | yararsızdır. 7 | 8 | ### Özel nesneleri karşılaştırmak 9 | 10 | function Foo() {} 11 | function Bar() {} 12 | Bar.prototype = new Foo(); 13 | 14 | new Bar() instanceof Bar; // true 15 | new Bar() instanceof Foo; // true 16 | 17 | // Bu satır sadece Bar.prototype'a Foo fonksiyon nesnesinin atar 18 | // Bir Foo sınıfı nesnesine değil 19 | Bar.prototype = Foo; 20 | new Bar() instanceof Foo; // false 21 | 22 | ### Temel nesnelerle `instanceof` kullanımı 23 | 24 | new String('foo') instanceof String; // true 25 | new String('foo') instanceof Object; // true 26 | 27 | 'foo' instanceof String; // false 28 | 'foo' instanceof Object; // false 29 | 30 | Dikkat edilmesi gereken ilginç bir nokta, `instanceof` operatörünün farklı 31 | JavaScript kaynaklarından gelen nesneler üzerinde çalışmamasıdır (mesela bir 32 | internet tarayıcısının farklı dökümanları), çünkü bu durumda nesne 33 | oluşturucuları aynı olmayacaktır. 34 | 35 | ### Sonuç 36 | 37 | `instanceof` operatörü **sadece** aynı JavaScript kaynağından gelen özel 38 | nesneler ile kullanılmalıdır. Tıpkı [`typeof`](#types.typeof) operatöründe 39 | olduğu gibi, bunun dışındaki tüm kullanımlarından **kaçınılmalıdır**. 40 | 41 | -------------------------------------------------------------------------------- /doc/zh/array/constructor.md: -------------------------------------------------------------------------------- 1 | ##`Array` 构造函数 2 | 3 | 由于 `Array` 的构造函数在如何处理参数时有点模棱两可,因此总是推荐使用数组的字面语法 - `[]` - 来创建数组。 4 | 5 | [1, 2, 3]; // 结果: [1, 2, 3] 6 | new Array(1, 2, 3); // 结果: [1, 2, 3] 7 | 8 | [3]; // 结果: [3] 9 | new Array(3); // 结果: [] 10 | new Array('3') // 结果: ['3'] 11 | 12 | // 译者注:因此下面的代码将会使人很迷惑 13 | new Array(3, 4, 5); // 结果: [3, 4, 5] 14 | new Array(3) // 结果: [],此数组长度为 3 15 | 16 | > **译者注:**这里的模棱两可指的是数组的[两种构造函数语法][1] 17 | 18 | 由于只有一个参数传递到构造函数中(译者注:指的是 `new Array(3);` 这种调用方式),并且这个参数是数字,构造函数会返回一个 `length` 属性被设置为此参数的空数组。 19 | 需要特别注意的是,此时只有 `length` 属性被设置,真正的数组并没有生成。 20 | 21 | > **译者注:**在 Firebug 中,你会看到 `[undefined, undefined, undefined]`,这其实是不对的。在上一节有详细的分析。 22 | 23 | var arr = new Array(3); 24 | arr[1]; // undefined 25 | 1 in arr; // false, 数组还没有生成 26 | 27 | 这种优先于设置数组长度属性的做法只在少数几种情况下有用,比如需要循环字符串,可以避免 `for` 循环的麻烦。 28 | 29 | new Array(count + 1).join(stringToRepeat); 30 | 31 | > **译者注:** `new Array(3).join('#')` 将会返回 `##` 32 | 33 | ###结论 34 | 35 | 应该尽量避免使用数组构造函数创建新数组。推荐使用数组的字面语法。它们更加短小和简洁,因此增加了代码的可读性。 36 | 37 | [1]: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array 38 | 39 | -------------------------------------------------------------------------------- /doc/zh/array/general.md: -------------------------------------------------------------------------------- 1 | ##数组遍历与属性 2 | 3 | 虽然在 JavaScript 中数组是是对象,但是没有好的理由去使用 [`for in` 循环](#object.forinloop) 遍历数组。 4 | 相反,有一些好的理由**不去**使用 `for in` 遍历数组。 5 | 6 | > **注意:** JavaScript 中数组**不是** *关联数组*。 7 | > JavaScript 中只有[对象](#object.general) 来管理键值的对应关系。但是关联数组是**保持**顺序的,而对象**不是**。 8 | 9 | 由于 `for in` 循环会枚举原型链上的所有属性,唯一过滤这些属性的方式是使用 [`hasOwnProperty`](#object.hasownproperty) 函数, 10 | 因此会比普通的 `for` 循环慢上好多倍。 11 | 12 | ###遍历 13 | 14 | 为了达到遍历数组的最佳性能,推荐使用经典的 `for` 循环。 15 | 16 | var list = [1, 2, 3, 4, 5, ...... 100000000]; 17 | for(var i = 0, l = list.length; i < l; i++) { 18 | console.log(list[i]); 19 | } 20 | 21 | 上面代码有一个处理,就是通过 `l = list.length` 来缓存数组的长度。 22 | 23 | 虽然 `length` 是数组的一个属性,但是在每次循环中访问它还是有性能开销。 24 | **可能**最新的 JavaScript 引擎在这点上做了优化,但是我们没法保证自己的代码是否运行在这些最近的引擎之上。 25 | 26 | 实际上,不使用缓存数组长度的方式比缓存版本要慢很多。 27 | 28 | ###`length` 属性 29 | 30 | `length` 属性的 *getter* 方式会简单的返回数组的长度,而 *setter* 方式会**截断**数组。 31 | 32 | var foo = [1, 2, 3, 4, 5, 6]; 33 | foo.length = 3; 34 | foo; // [1, 2, 3] 35 | 36 | foo.length = 6; 37 | foo; // [1, 2, 3] 38 | 39 | **译者注:** 40 | 在 Firebug 中查看此时 `foo` 的值是: `[1, 2, 3, undefined, undefined, undefined]` 41 | 但是这个结果并不准确,如果你在 Chrome 的控制台查看 `foo` 的结果,你会发现是这样的: `[1, 2, 3]` 42 | 因为在 JavaScript 中 `undefined` 是一个变量,注意是变量不是关键字,因此上面两个结果的意义是完全不相同的。 43 | 44 | // 译者注:为了验证,我们来执行下面代码,看序号 5 是否存在于 foo 中。 45 | 5 in foo; // 不管在 Firebug 或者 Chrome 都返回 false 46 | foo[5] = undefined; 47 | 5 in foo; // 不管在 Firebug 或者 Chrome 都返回 true 48 | 49 | 为 `length` 设置一个更小的值会截断数组,但是增大 `length` 属性值不会对数组产生影响。 50 | 51 | ###结论 52 | 53 | 为了更好的性能,推荐使用普通的 `for` 循环并缓存数组的 `length` 属性。 54 | 使用 `for in` 遍历数组被认为是不好的代码习惯并倾向于产生错误和导致性能问题。 55 | 56 | -------------------------------------------------------------------------------- /doc/zh/core/eval.md: -------------------------------------------------------------------------------- 1 | ##为什么不要使用 `eval` 2 | 3 | `eval` 函数会在当前作用域中执行一段 JavaScript 代码字符串。 4 | 5 | var foo = 1; 6 | function test() { 7 | var foo = 2; 8 | eval('foo = 3'); 9 | return foo; 10 | } 11 | test(); // 3 12 | foo; // 1 13 | 14 | 但是 `eval` 只在被**直接**调用并且调用函数就是 `eval` 本身时,才在当前作用域中执行。 15 | 16 | var foo = 1; 17 | function test() { 18 | var foo = 2; 19 | var bar = eval; 20 | bar('foo = 3'); 21 | return foo; 22 | } 23 | test(); // 2 24 | foo; // 3 25 | 26 | **[译者注][30]:**上面的代码等价于在全局作用域中调用 `eval`,和下面两种写法效果一样: 27 | 28 | // 写法一:直接调用全局作用域下的 foo 变量 29 | var foo = 1; 30 | function test() { 31 | var foo = 2; 32 | window.foo = 3; 33 | return foo; 34 | } 35 | test(); // 2 36 | foo; // 3 37 | 38 | // 写法二:使用 call 函数修改 eval 执行的上下文为全局作用域 39 | var foo = 1; 40 | function test() { 41 | var foo = 2; 42 | eval.call(window, 'foo = 3'); 43 | return foo; 44 | } 45 | test(); // 2 46 | foo; // 3 47 | 48 | 在**任何情况下**我们都应该避免使用 `eval` 函数。99.9% 使用 `eval` 的场景都有**不使用** `eval` 的解决方案。 49 | 50 | ###伪装的 `eval` 51 | 52 | [定时函数](#other.timeouts) `setTimeout` 和 `setInterval` 都可以接受字符串作为它们的第一个参数。 53 | 这个字符串**总是**在全局作用域中执行,因此 `eval` 在这种情况下没有被直接调用。 54 | 55 | 56 | ###安全问题 57 | 58 | `eval` 也存在安全问题,因为它会执行**任意**传给它的代码, 59 | 在代码字符串未知或者是来自一个不信任的源时,绝对不要使用 `eval` 函数。 60 | 61 | ###结论 62 | 63 | 绝对不要使用 `eval`,任何使用它的代码都会在它的工作方式,性能和安全性方面受到质疑。 64 | 如果一些情况必须使用到 `eval` 才能正常工作,首先它的设计会受到质疑,这**不应该**是首选的解决方案, 65 | 一个更好的不使用 `eval` 的解决方案应该得到充分考虑并优先采用。 66 | 67 | [30]: http://cnblogs.com/sanshi/ 68 | -------------------------------------------------------------------------------- /doc/zh/core/undefined.md: -------------------------------------------------------------------------------- 1 | ##`undefined` 和 `null` 2 | 3 | JavaScript 有两个表示‘空’的值,其中比较有用的是 `undefined`。 4 | 5 | ###`undefined` 的值 6 | 7 | `undefined` 是一个值为 `undefined` 的类型。 8 | 9 | 这个语言也定义了一个全局变量,它的值是 `undefined`,这个变量也被称为 `undefined`。 10 | 但是这个变量**不是**一个常量,也不是一个关键字。这意味着它的*值*可以轻易被覆盖。 11 | 12 | > **ES5 提示:** 在 ECMAScript 5 的严格模式下,`undefined` **不再是** *可写*的了。 13 | > 但是它的名称仍然可以被隐藏,比如定义一个函数名为 `undefined`。 14 | 15 | 下面的情况会返回 `undefined` 值: 16 | 17 | - 访问未修改的全局变量 `undefined`。 18 | - 由于没有定义 `return` 表达式的函数隐式返回。 19 | - `return` 表达式没有显式的返回任何内容。 20 | - 访问不存在的属性。 21 | - 函数参数没有被显式的传递值。 22 | - 任何被设置为 `undefined` 值的变量。 23 | 24 | ###处理 `undefined` 值的改变 25 | 26 | 由于全局变量 `undefined` 只是保存了 `undefined` 类型实际*值*的副本, 27 | 因此对它赋新值**不会**改变类型 `undefined` 的值。 28 | 29 | 然而,为了方便其它变量和 `undefined` 做比较,我们需要事先获取类型 `undefined` 的值。 30 | 31 | 为了避免可能对 `undefined` 值的改变,一个常用的技巧是使用一个传递到[匿名包装器](#function.scopes)的额外参数。 32 | 在调用时,这个参数不会获取任何值。 33 | 34 | var undefined = 123; 35 | (function(something, foo, undefined) { 36 | // 局部作用域里的 undefined 变量重新获得了 `undefined` 值 37 | 38 | })('Hello World', 42); 39 | 40 | 另外一种达到相同目的方法是在函数内使用变量声明。 41 | 42 | var undefined = 123; 43 | (function(something, foo) { 44 | var undefined; 45 | ... 46 | 47 | })('Hello World', 42); 48 | 49 | 这里唯一的区别是,在压缩后并且函数内没有其它需要使用 `var` 声明变量的情况下,这个版本的代码会多出 4 个字节的代码。 50 | 51 | > **[译者注][30]:**这里有点绕口,其实很简单。如果此函数内没有其它需要声明的变量,那么 `var` 总共 4 个字符(包含一个空白字符) 52 | 就是专门为 `undefined` 变量准备的,相比上个例子多出了 4 个字节。 53 | 54 | ###`null` 的用处 55 | 56 | JavaScript 中的 `undefined` 的使用场景类似于其它语言中的 *null*,实际上 JavaScript 中的 `null` 是另外一种数据类型。 57 | 58 | 它在 JavaScript 内部有一些使用场景(比如声明原型链的终结 `Foo.prototype = null`),但是大多数情况下都可以使用 `undefined` 来代替。 59 | 60 | [30]: http://cnblogs.com/sanshi/ 61 | -------------------------------------------------------------------------------- /doc/zh/function/closures.md: -------------------------------------------------------------------------------- 1 | ##闭包和引用 2 | 3 | 闭包是 JavaScript 一个非常重要的特性,这意味着当前作用域**总是**能够访问外部作用域中的变量。 4 | 因为 [函数](#function.scopes) 是 JavaScript 中唯一拥有自身作用域的结构,因此闭包的创建依赖于函数。 5 | 6 | ###模拟私有变量 7 | 8 | function Counter(start) { 9 | var count = start; 10 | return { 11 | increment: function() { 12 | count++; 13 | }, 14 | 15 | get: function() { 16 | return count; 17 | } 18 | } 19 | } 20 | 21 | var foo = Counter(4); 22 | foo.increment(); 23 | foo.get(); // 5 24 | 25 | 这里,`Counter` 函数返回两个闭包,函数 `increment` 和函数 `get`。 这两个函数都维持着 26 | 对外部作用域 `Counter` 的引用,因此总可以访问此作用域内定义的变量 `count`. 27 | 28 | ###为什么不可以在外部访问私有变量 29 | 30 | 因为 JavaScript 中不可以对作用域进行引用或赋值,因此没有办法在外部访问 `count` 变量。 31 | 唯一的途径就是通过那两个闭包。 32 | 33 | var foo = new Counter(4); 34 | foo.hack = function() { 35 | count = 1337; 36 | }; 37 | 38 | 上面的代码**不会**改变定义在 `Counter` 作用域中的 `count` 变量的值,因为 `foo.hack` 没有 39 | 定义在那个**作用域**内。它将会创建或者覆盖*全局*变量 `count`。 40 | 41 | ###循环中的闭包 42 | 43 | 一个常见的错误出现在循环中使用闭包,假设我们需要在每次循环中调用循环序号 44 | 45 | for(var i = 0; i < 10; i++) { 46 | setTimeout(function() { 47 | console.log(i); 48 | }, 1000); 49 | } 50 | 51 | 上面的代码不会输出数字 `0` 到 `9`,而是会输出数字 `10` 十次。 52 | 53 | 当 `console.log` 被调用的时候,*匿名*函数保持对外部变量 `i` 的引用,此时 `for`循环已经结束, `i` 的值被修改成了 `10`. 54 | 55 | 为了得到想要的结果,需要在每次循环中创建变量 `i` 的**拷贝**。 56 | 57 | ###避免引用错误 58 | 59 | 为了正确的获得循环序号,最好使用 [匿名包裹器](#function.scopes)(**[译者注][30]:**其实就是我们通常说的自执行匿名函数)。 60 | 61 | for(var i = 0; i < 10; i++) { 62 | (function(e) { 63 | setTimeout(function() { 64 | console.log(e); 65 | }, 1000); 66 | })(i); 67 | } 68 | 69 | 外部的匿名函数会立即执行,并把 `i` 作为它的参数,此时函数内 `e` 变量就拥有了 `i` 的一个拷贝。 70 | 71 | 当传递给 `setTimeout` 的匿名函数执行时,它就拥有了对 `e` 的引用,而这个值是**不会**被循环改变的。 72 | 73 | 有另一个方法完成同样的工作;那就是从匿名包装器中返回一个函数。这和上面的代码效果一样。 74 | 75 | for(var i = 0; i < 10; i++) { 76 | setTimeout((function(e) { 77 | return function() { 78 | console.log(e); 79 | } 80 | })(i), 1000) 81 | } 82 | 83 | 84 | [30]: http://cnblogs.com/sanshi/ 85 | -------------------------------------------------------------------------------- /doc/zh/function/general.md: -------------------------------------------------------------------------------- 1 | ##函数声明与表达式 2 | 3 | 函数是JavaScript中的一等对象,这意味着可以把函数像其它值一样传递。 4 | 一个常见的用法是把*匿名函数*作为回调函数传递到异步函数中。 5 | 6 | ###函数声明 7 | 8 | function foo() {} 9 | 10 | 上面的方法会在执行前被 [解析(hoisted)](#function.scopes),因此它存在于当前上下文的*任意*一个地方, 11 | 即使在函数定义体的上面被调用也是对的。 12 | 13 | foo(); // 正常运行,因为foo在代码运行前已经被创建 14 | function foo() {} 15 | 16 | ### 函数赋值表达式 17 | 18 | var foo = function() {}; 19 | 20 | 这个例子把一个*匿名*的函数赋值给变量 `foo`。 21 | 22 | foo; // 'undefined' 23 | foo(); // 出错:TypeError 24 | var foo = function() {}; 25 | 26 | 由于 `var` 定义了一个声明语句,对变量 `foo` 的解析是在代码运行之前,因此 `foo` 变量在代码运行时已经被定义过了。 27 | 28 | 但是由于赋值语句只在运行时执行,因此在相应代码执行之前, `foo` 的值缺省为 [undefined](#core.undefined)。 29 | 30 | ###命名函数的赋值表达式 31 | 32 | 另外一个特殊的情况是将命名函数赋值给一个变量。 33 | 34 | var foo = function bar() { 35 | bar(); // 正常运行 36 | } 37 | bar(); // 出错:ReferenceError 38 | 39 | `bar` 函数声明外是不可见的,这是因为我们已经把函数赋值给了 `foo`; 40 | 然而在 `bar` 内部依然可见。这是由于 JavaScript 的 [命名处理](#function.scopes) 所致, 41 | 函数名在函数内*总是*可见的。 42 | 43 | [30]: http://cnblogs.com/sanshi/ 44 | -------------------------------------------------------------------------------- /doc/zh/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "JavaScript 秘密花园", 3 | "langTitle": "JavaScript Garden 中文翻译", 4 | "description": "JavaScript 语言最古怪用法的文档集合", 5 | "sections": [ 6 | { 7 | "title": "简介", 8 | "dir": "intro", 9 | "articles": [ 10 | "authors", 11 | "contributors", 12 | "license" 13 | ] 14 | }, 15 | { 16 | "title": "对象", 17 | "dir": "object", 18 | "articles": [ 19 | "general", 20 | "prototype", 21 | "hasownproperty", 22 | "forinloop" 23 | ] 24 | }, 25 | { 26 | "title": "函数", 27 | "dir": "function", 28 | "articles": [ 29 | "general", 30 | "this", 31 | "closures", 32 | "arguments", 33 | "constructors", 34 | "scopes" 35 | ] 36 | }, 37 | { 38 | "title": "数组", 39 | "dir": "array", 40 | "articles": [ 41 | "general", 42 | "constructor" 43 | ] 44 | }, 45 | { 46 | "title": "类型", 47 | "dir": "types", 48 | "articles": [ 49 | "equality", 50 | "typeof", 51 | "instanceof", 52 | "casting" 53 | ] 54 | }, 55 | { 56 | "title": "核心", 57 | "dir": "core", 58 | "articles": [ 59 | "eval", 60 | "undefined", 61 | "semicolon" 62 | ] 63 | }, 64 | { 65 | "title": "其它", 66 | "dir": "other", 67 | "articles": [ 68 | "timeouts" 69 | ] 70 | } 71 | ] 72 | } 73 | -------------------------------------------------------------------------------- /doc/zh/intro/authors.md: -------------------------------------------------------------------------------- 1 | ##关于作者 2 | 3 | 这篇文章的作者是两位 [Stack Overflow][1] 用户, [伊沃·韦特泽尔 Ivo Wetzel][2](写作) 和 [张易江 Zhang Yi Jiang][3](设计)。 4 | 5 | [1]: http://stackoverflow.com/ 6 | [2]: http://stackoverflow.com/users/170224/ivo-wetzel 7 | [3]: http://stackoverflow.com/users/313758/yi-jiang 8 | -------------------------------------------------------------------------------- /doc/zh/intro/contributors.md: -------------------------------------------------------------------------------- 1 | ##贡献者 2 | 3 | - [贡献者](https://github.com/BonsaiDen/JavaScript-Garden/graphs/contributors) 4 | 5 | ##中文翻译 6 | - [三生石上][29] 7 | 8 | 此中文翻译由[三生石上][29]独立完成,[博客园][30]首发,转载请注明出处。 9 | 10 | [1]: https://github.com/caio 11 | [2]: https://github.com/blixt 12 | [29]: http://sanshi.me/ 13 | [30]: http://cnblogs.com/sanshi/ 14 | -------------------------------------------------------------------------------- /doc/zh/intro/index.md: -------------------------------------------------------------------------------- 1 | ##简介 2 | 3 | **JavaScript 秘密花园**是一个不断更新,主要关心 JavaScript 一些古怪用法的文档。 4 | 对于如何避免常见的错误,难以发现的问题,以及性能问题和不好的实践给出建议, 5 | 初学者可以籍此深入了解 JavaScript 的语言特性。 6 | 7 | JavaScript 秘密花园**不是**用来教你 JavaScript。为了更好的理解这篇文章的内容, 8 | 你需要事先学习 JavaScript 的基础知识。在 Mozilla 开发者网络中有一系列非常棒的 JavaScript 学习[向导][1]。 9 | 10 | > **译者注:** 文中提到的 ES5 是 ECMAScript 5 的简写,是 ECMAScript 标准语言的下一版本,正在开发中。 11 | JavaScript 是此标准语言的一个方言。 12 | 13 | [1]: https://developer.mozilla.org/en/JavaScript/Guide 14 | 15 | -------------------------------------------------------------------------------- /doc/zh/intro/license.md: -------------------------------------------------------------------------------- 1 | ##许可 2 | 3 | JavaScript 秘密花园在 [MIT license][1] 许可协议下发布,并存放在 [GitHub][2] 开源社区。 4 | 如果你发现错误或者打字错误,请[新建一个任务单][3]或者发一个抓取请求。 5 | 你也可以在 Stack Overflow 的 [JavaScript 聊天室][4]找到我们。 6 | 7 | [1]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE 8 | [2]: https://github.com/BonsaiDen/JavaScript-Garden 9 | [3]: https://github.com/BonsaiDen/JavaScript-Garden/issues 10 | [4]: http://chat.stackoverflow.com/rooms/17/javascript 11 | 12 | -------------------------------------------------------------------------------- /doc/zh/object/forinloop.md: -------------------------------------------------------------------------------- 1 | ##`for in` 循环 2 | 3 | 和 `in` 操作符一样,`for in` 循环同样在查找对象属性时遍历原型链上的所有属性。 4 | 5 | > **注意:** `for in` 循环**不会**遍历那些 `enumerable` 设置为 `false` 的属性;比如数组的 `length` 属性。 6 | 7 | // 修改 Object.prototype 8 | Object.prototype.bar = 1; 9 | 10 | var foo = {moo: 2}; 11 | for(var i in foo) { 12 | console.log(i); // 输出两个属性:bar 和 moo 13 | } 14 | 15 | 由于不可能改变 `for in` 自身的行为,因此有必要过滤出那些不希望出现在循环体中的属性, 16 | 这可以通过 `Object.prototype` 原型上的 [`hasOwnProperty`](#object.hasownproperty) 函数来完成。 17 | 18 | > **注意:** 由于 `for in` 总是要遍历整个原型链,因此如果一个对象的继承层次太深的话会影响性能。 19 | 20 | ###使用 `hasOwnProperty` 过滤 21 | 22 | // foo 变量是上例中的 23 | for(var i in foo) { 24 | if (foo.hasOwnProperty(i)) { 25 | console.log(i); 26 | } 27 | } 28 | 29 | 这个版本的代码是唯一正确的写法。由于我们使用了 `hasOwnProperty`,所以这次**只**输出 `moo`。 30 | 如果不使用 `hasOwnProperty`,则这段代码在原生对象原型(比如 `Object.prototype`)被扩展时可能会出错。 31 | 32 | 一个广泛使用的类库 [Prototype][1] 就扩展了原生的 JavaScript 对象。 33 | 因此,当这个类库被包含在页面中时,不使用 `hasOwnProperty` 过滤的 `for in` 循环难免会出问题。 34 | 35 | ###总结 36 | 37 | 推荐**总是**使用 `hasOwnProperty`。不要对代码运行的环境做任何假设,不要假设原生对象是否已经被扩展了。 38 | 39 | [1]: http://www.prototypejs.org/ 40 | [30]: http://cnblogs.com/sanshi/ 41 | 42 | -------------------------------------------------------------------------------- /doc/zh/object/general.md: -------------------------------------------------------------------------------- 1 | ##对象使用和属性 2 | 3 | JavaScript 中所有变量都是对象,除了两个例外 [`null`](#core.undefined) 和 [`undefined`](#core.undefined)。 4 | 5 | false.toString(); // 'false' 6 | [1, 2, 3].toString(); // '1,2,3' 7 | 8 | function Foo(){} 9 | Foo.bar = 1; 10 | Foo.bar; // 1 11 | 12 | 一个常见的误解是数字的字面值(literal)不是对象。这是因为 JavaScript 解析器的一个错误, 13 | 它试图将*点操作符*解析为浮点数字面值的一部分。 14 | 15 | 2.toString(); // 出错:SyntaxError 16 | 17 | 有很多变通方法可以让数字的字面值看起来像对象。 18 | 19 | 2..toString(); // 第二个点号可以正常解析 20 | 2 .toString(); // 注意点号前面的空格 21 | (2).toString(); // 2先被计算 22 | 23 | ###对象作为数据类型 24 | 25 | JavaScript 的对象可以作为[*哈希表*][1]使用,主要用来保存命名的键与值的对应关系。 26 | 27 | 使用对象的字面语法 - `{}` - 可以创建一个简单对象。这个新创建的对象从 `Object.prototype` 28 | [继承](#object.prototype)下面,没有任何[自定义属性](#object.hasownproperty)。 29 | 30 | var foo = {}; // 一个空对象 31 | 32 | // 一个新对象,拥有一个值为12的自定义属性'test' 33 | var bar = {test: 12}; 34 | 35 | ### 访问属性 36 | 37 | 有两种方式来访问对象的属性,点操作符或者中括号操作符。 38 | 39 | var foo = {name: 'Kitten'} 40 | foo.name; // kitten 41 | foo['name']; // kitten 42 | 43 | var get = 'name'; 44 | foo[get]; // kitten 45 | 46 | foo.1234; // SyntaxError 47 | foo['1234']; // works 48 | 49 | 两种语法是等价的,但是中括号操作符在下面两种情况下依然有效 50 | - 动态设置属性 51 | - 属性名不是一个有效的变量名(**[译者注][30]:**比如属性名中包含空格,或者属性名是 JS 的关键词) 52 | 53 | > **[译者注][30]:**在 [JSLint][2] 语法检测工具中,点操作符是推荐做法。 54 | 55 | ###删除属性 56 | 57 | 删除属性的唯一方法是使用 `delete` 操作符;设置属性为 `undefined` 或者 `null` 并不能真正的删除属性, 58 | 而**仅仅**是移除了属性和值的关联。 59 | 60 | var obj = { 61 | bar: 1, 62 | foo: 2, 63 | baz: 3 64 | }; 65 | obj.bar = undefined; 66 | obj.foo = null; 67 | delete obj.baz; 68 | 69 | for(var i in obj) { 70 | if (obj.hasOwnProperty(i)) { 71 | console.log(i, '' + obj[i]); 72 | } 73 | } 74 | 75 | 上面的输出结果有 `bar undefined` 和 `foo null` - 只有 `baz` 被真正的删除了,所以从输出结果中消失。 76 | 77 | ###属性名的语法 78 | 79 | var test = { 80 | 'case': 'I am a keyword so I must be notated as a string', 81 | delete: 'I am a keyword too so me' // 出错:SyntaxError 82 | }; 83 | 84 | 对象的属性名可以使用字符串或者普通字符声明。但是由于 JavaScript 解析器的另一个错误设计, 85 | 上面的第二种声明方式在 ECMAScript 5 之前会抛出 `SyntaxError` 的错误。 86 | 87 | 这个错误的原因是 `delete` 是 JavaScript 语言的一个*关键词*;因此为了在更低版本的 JavaScript 引擎下也能正常运行, 88 | 必须使用*字符串字面值*声明方式。 89 | 90 | [1]: http://en.wikipedia.org/wiki/Hashmap 91 | [2]: http://www.jslint.com/ 92 | [30]: http://cnblogs.com/sanshi/ 93 | 94 | -------------------------------------------------------------------------------- /doc/zh/object/hasownproperty.md: -------------------------------------------------------------------------------- 1 | ##`hasOwnProperty` 函数 2 | 3 | 为了判断一个对象是否包含*自定义*属性而*不是*[原型链](#object.prototype)上的属性, 4 | 我们需要使用继承自 `Object.prototype` 的 `hasOwnProperty` 方法。 5 | 6 | > **注意:** 通过判断一个属性是否 `undefined` 是**不够**的。 7 | > 因为一个属性可能确实存在,只不过它的值被设置为 `undefined`。 8 | 9 | `hasOwnProperty` 是 JavaScript 中唯一一个处理属性但是**不**查找原型链的函数。 10 | 11 | // 修改Object.prototype 12 | Object.prototype.bar = 1; 13 | var foo = {goo: undefined}; 14 | 15 | foo.bar; // 1 16 | 'bar' in foo; // true 17 | 18 | foo.hasOwnProperty('bar'); // false 19 | foo.hasOwnProperty('goo'); // true 20 | 21 | 只有 `hasOwnProperty` 可以给出正确和期望的结果,这在遍历对象的属性时会很有用。 22 | **没有**其它方法可以用来排除原型链上的属性,而不是定义在对象*自身*上的属性。 23 | 24 | ###`hasOwnProperty` 作为属性 25 | 26 | JavaScript **不会**保护 `hasOwnProperty` 被非法占用,因此如果一个对象碰巧存在这个属性, 27 | 就需要使用*外部*的 `hasOwnProperty` 函数来获取正确的结果。 28 | 29 | var foo = { 30 | hasOwnProperty: function() { 31 | return false; 32 | }, 33 | bar: 'Here be dragons' 34 | }; 35 | 36 | foo.hasOwnProperty('bar'); // 总是返回 false 37 | 38 | // 使用其它对象的 hasOwnProperty,并将其上下文设置为foo 39 | ({}).hasOwnProperty.call(foo, 'bar'); // true 40 | 41 | ###结论 42 | 43 | 当检查对象上某个属性是否存在时,`hasOwnProperty` 是**唯一**可用的方法。 44 | 同时在使用 [`for in` loop](#object.forinloop) 遍历对象时,推荐**总是**使用 `hasOwnProperty` 方法, 45 | 这将会避免[原型](#object.prototype)对象扩展带来的干扰。 46 | 47 | [30]: http://cnblogs.com/sanshi/ 48 | -------------------------------------------------------------------------------- /doc/zh/types/casting.md: -------------------------------------------------------------------------------- 1 | ##类型转换 2 | 3 | JavaScript 是*弱类型*语言,所以会在**任何**可能的情况下应用*强制类型转换*。 4 | 5 | // 下面的比较结果是:true 6 | new Number(10) == 10; // Number.toString() 返回的字符串被再次转换为数字 7 | 8 | 10 == '10'; // 字符串被转换为数字 9 | 10 == '+10 '; // 同上 10 | 10 == '010'; // 同上 11 | isNaN(null) == false; // null 被转换为数字 0 12 | // 0 当然不是一个 NaN(译者注:否定之否定) 13 | 14 | // 下面的比较结果是:false 15 | 10 == 010; 16 | 10 == '-10'; 17 | 18 | > **ES5 提示:** 以 `0` 开头的数字字面值会被作为八进制数字解析。 19 | > 而在 ECMAScript 5 严格模式下,这个特性被**移除**了。 20 | 21 | 为了避免上面复杂的强制类型转换,**强烈**推荐使用[严格的等于操作符](#types.equality)。 22 | 虽然这可以避免大部分的问题,但 JavaScript 的弱类型系统仍然会导致一些其它问题。 23 | 24 | ###内置类型的构造函数 25 | 26 | 内置类型(比如 `Number` 和 `String`)的构造函数在被调用时,使用或者不使用 `new` 的结果完全不同。 27 | 28 | new Number(10) === 10; // False, 对象与数字的比较 29 | Number(10) === 10; // True, 数字与数字的比较 30 | new Number(10) + 0 === 10; // True, 由于隐式的类型转换 31 | 32 | 使用内置类型 `Number` 作为构造函数将会创建一个新的 `Number` 对象, 33 | 而在不使用 `new` 关键字的 `Number` 函数更像是一个数字转换器。 34 | 35 | 另外,在比较中引入对象的字面值将会导致更加复杂的强制类型转换。 36 | 37 | 最好的选择是把要比较的值**显式**的转换为三种可能的类型之一。 38 | 39 | ###转换为字符串 40 | 41 | '' + 10 === '10'; // true 42 | 43 | 将一个值加上空字符串可以轻松转换为字符串类型。 44 | 45 | ###转换为数字 46 | 47 | +'10' === 10; // true 48 | 49 | 使用**一元**的加号操作符,可以把字符串转换为数字。 50 | 51 | **[译者注][30]:**字符串转换为数字的常用方法: 52 | 53 | +'010' === 10 54 | Number('010') === 10 55 | parseInt('010', 10) === 10 // 用来转换为整数 56 | 57 | +'010.2' === 10.2 58 | Number('010.2') === 10.2 59 | parseInt('010.2', 10) === 10 60 | 61 | 62 | ###转换为布尔型 63 | 64 | 通过使用 **否** 操作符两次,可以把一个值转换为布尔型。 65 | 66 | !!'foo'; // true 67 | !!''; // false 68 | !!'0'; // true 69 | !!'1'; // true 70 | !!'-1' // true 71 | !!{}; // true 72 | !!true; // true 73 | 74 | [30]: http://cnblogs.com/sanshi/ 75 | -------------------------------------------------------------------------------- /doc/zh/types/equality.md: -------------------------------------------------------------------------------- 1 | ##相等与比较 2 | 3 | JavaScript 有两种方式判断两个值是否相等。 4 | 5 | ###等于操作符 6 | 7 | 等于操作符由两个等号组成:`==` 8 | 9 | JavaScript 是*弱类型*语言,这就意味着,等于操作符会为了比较两个值而进行**强制类型转换**。 10 | 11 | "" == "0" // false 12 | 0 == "" // true 13 | 0 == "0" // true 14 | false == "false" // false 15 | false == "0" // true 16 | false == undefined // false 17 | false == null // false 18 | null == undefined // true 19 | " \t\r\n" == 0 // true 20 | 21 | 上面的表格展示了强制类型转换,这也是使用 `==` 被广泛认为是不好编程习惯的主要原因, 22 | 由于它的复杂转换规则,会导致难以跟踪的问题。 23 | 24 | 此外,强制类型转换也会带来性能消耗,比如一个字符串为了和一个数字进行比较,必须事先被强制转换为数字。 25 | 26 | ###严格等于操作符 27 | 28 | 严格等于操作符由**三**个等号组成:`===` 29 | 30 | 不像普通的等于操作符,严格等于操作符**不会**进行强制类型转换。 31 | 32 | "" === "0" // false 33 | 0 === "" // false 34 | 0 === "0" // false 35 | false === "false" // false 36 | false === "0" // false 37 | false === undefined // false 38 | false === null // false 39 | null === undefined // false 40 | " \t\r\n" === 0 // false 41 | 42 | 上面的结果更加清晰并有利于代码的分析。如果两个操作数类型不同就肯定不相等也有助于性能的提升。 43 | 44 | ###比较对象 45 | 46 | 虽然 `==` 和 `===` 操作符都是等于操作符,但是当其中有一个操作数为对象时,行为就不同了。 47 | 48 | {} === {}; // false 49 | new String('foo') === 'foo'; // false 50 | new Number(10) === 10; // false 51 | var foo = {}; 52 | foo === foo; // true 53 | 54 | 这里等于操作符比较的**不是**值是否相等,而是是否属于同一个**身份**;也就是说,只有对象的同一个实例才被认为是相等的。 55 | 这有点像 Python 中的 `is` 和 C 中的指针比较。 56 | 57 | ###结论 58 | 59 | 强烈推荐使用**严格等于操作符**。如果类型需要转换,应该在比较之前[显式](#types.casting)的转换, 60 | 而不是使用语言本身复杂的强制转换规则。 61 | 62 | [30]: http://cnblogs.com/sanshi/ 63 | -------------------------------------------------------------------------------- /doc/zh/types/instanceof.md: -------------------------------------------------------------------------------- 1 | ##`instanceof` 操作符 2 | 3 | `instanceof` 操作符用来比较两个操作数的构造函数。只有在比较自定义的对象时才有意义。 4 | 如果用来比较内置类型,将会和 [`typeof` 操作符](#types.typeof) 一样用处不大。 5 | 6 | ###比较自定义对象 7 | 8 | function Foo() {} 9 | function Bar() {} 10 | Bar.prototype = new Foo(); 11 | 12 | new Bar() instanceof Bar; // true 13 | new Bar() instanceof Foo; // true 14 | 15 | // 如果仅仅设置 Bar.prototype 为函数 Foo 本身,而不是 Foo 构造函数的一个实例 16 | Bar.prototype = Foo; 17 | new Bar() instanceof Foo; // false 18 | 19 | ###`instanceof` 比较内置类型 20 | 21 | new String('foo') instanceof String; // true 22 | new String('foo') instanceof Object; // true 23 | 24 | 'foo' instanceof String; // false 25 | 'foo' instanceof Object; // false 26 | 27 | 有一点需要注意,`instanceof` 用来比较属于不同 JavaScript 上下文的对象(比如,浏览器中不同的文档结构)时将会出错, 28 | 因为它们的构造函数不会是同一个对象。 29 | 30 | ### 结论 31 | 32 | `instanceof` 操作符应该**仅仅**用来比较来自同一个 JavaScript 上下文的自定义对象。 33 | 正如 [`typeof`](#types.typeof) 操作符一样,任何其它的用法都应该是避免的。 34 | 35 | [30]: http://cnblogs.com/sanshi/ 36 | -------------------------------------------------------------------------------- /doc/zhtw/array/constructor.md: -------------------------------------------------------------------------------- 1 | ## `Array` 的建構函式 2 | 3 | `Array` 的建構函式在處理參數上一直有模糊的地帶,所以建議使用 `array`的字面語法來使用 - `[]` - 來新增一個的Array 4 | 5 | [1, 2, 3]; // 結果: [1, 2, 3] 6 | new Array(1, 2, 3); // 結果: [1, 2, 3] 7 | 8 | [3]; // 結果: [3] 9 | new Array(3); // 結果: [] 10 | new Array('3') // 結果: ['3'] 11 | 12 | 在上面的範例 `new Array(3)` 當只有一個參數傳入到 `Array` 的建構函數 13 | 且那個參數事宜個數字,建構函數會回傳空值 14 | 但是 `Array` 長度的屬性會變成跟那個參數一樣(以此範例來看他回傳的長度為 3) 15 | **注意** 只有他長度的屬性會被設定,整個 Array裡面的數值都不會初始化 16 | 17 | var arr = new Array(3); 18 | arr[1]; // undefined 19 | 1 in arr; // false, 數值沒有被設定進去 20 | 21 | 被設定用來當做 `Array` 的長度只有少數情況使用 22 | 先設定 `Array` 的長度可以用一下的範例來避免使用 `for loop` 的麻煩 23 | 24 | new Array(count + 1).join(stringToRepeat); 25 | 26 | ### 結語 27 | 28 | `Array` 的建構函式需要避免,建議使用字面語法。因為他們比較簡短、也更增加閱讀性 29 | -------------------------------------------------------------------------------- /doc/zhtw/array/general.md: -------------------------------------------------------------------------------- 1 | ## Array 迴圈和屬性 2 | 3 | 雖然在 Javascript 中 Array 都是 Objects,但是沒有好的理由要使用他 4 | 在 [`for in`](#object.forinloop) 的迴圈中。事實上有很多原因要避免使用 `for in` 在 Array 之中 5 | 6 | > **注意:** Javascript Arrays **不是** *關連性 Arrays* 7 | > 只有 [objects](#object.general) 來管理建值的相對應關係 8 | > Arrays 是**保持** 順序的,Objects **則沒有** 9 | 10 | 因為 `for in` 迴圈會列舉所有在原型 Array 上的屬性因為他會使用[`hasOwnProperty`](#object.hasownproperty), 這會使得 Array 比原本的 `for` 迴圈慢上二十幾倍 11 | 12 | ### 迴圈 13 | 14 | 為了要達到最好的性能所以最好使用 `for` 迴圈來讀取一個 Array 裡面的數值。 15 | 16 | var list = [1, 2, 3, 4, 5, ...... 100000000]; 17 | for(var i = 0, l = list.length; i < l; i++) { 18 | console.log(list[i]); 19 | } 20 | 21 | 在上面的例子中利用 `l = list.length` 來處理 Array 的長度問題。 22 | 23 | 雖然 `length` 屬性是屬於 Array 中其中一個屬性,但是他還使有一定的性能消耗在每次循環的訪問。 24 | 近期 Javascript 使用 **may** 來解決在這上面的效率問題,但是在現在的引擎上還不一定有支援。 25 | 26 | 實際上,不使用暫存 Array 長度的方式比使用暫存的版本還要慢很多。 27 | 28 | ### `length` 的屬性 29 | 30 | `length` 屬性中的 *getter* 直接回傳在 Array 之中的程度,而 *setter* 可以用來 **刪除** Array。 31 | 32 | var foo = [1, 2, 3, 4, 5, 6]; 33 | foo.length = 3; 34 | foo; // [1, 2, 3] 35 | 36 | foo.length = 6; 37 | foo.push(4); 38 | foo; // [1, 2, 3, undefined, undefined, undefined, 4] 39 | 40 | 在上面的例子可以看到,如果給的長度比較小他就會去刪除 Array 中的數值。如果比較大的話,他就會自己增加一些 `undefined` 的數值進去 41 | 42 | ### 結語 43 | 44 | 為了達到更好的效率,建議使用 `for` 迴圈還有暫存 `length` 的屬性。 45 | 而 `for in` 迴圈則是會讓程式中有更多的錯誤和性能問題。 46 | 47 | -------------------------------------------------------------------------------- /doc/zhtw/core/delete.md: -------------------------------------------------------------------------------- 1 | ## `delete` 控制符 2 | 3 | 簡單來說,那是 *不可能* 去刪除一個全域變數,函式和其他東西在 JavaScript 中有一個 `DontDelete` 的屬性 4 | 5 | ### 全域和函式 6 | 7 | 當一個變數或是一個函式在一個全域範圍被定義或是在一個 [funciton scope](#function.scopes) ,這些屬性可能是動態的物件或是全域的物件。這些特性有一系列的屬性。其中一個就是 `DontDelete`。 8 | 在這些變數和函式的宣告都會有一個屬性叫 `DontDelete`,這會使得它無法被刪除。 9 | 10 | // 全域變數 11 | var a = 1; // DontDelete 屬性被建立 12 | delete a; // false 13 | a; // 1 14 | 15 | // normal function: 16 | function f() {} // DontDelete 屬性被建立 17 | delete f; // false 18 | typeof f; // "function" 19 | 20 | // reassigning doesn't help: 21 | f = 1; 22 | delete f; // false 23 | f; // 1 24 | 25 | ### 明確的屬性 26 | 27 | 明確的屬性可以被簡單的刪除。 28 | 29 | // explicitly set property: 30 | var obj = {x: 1}; 31 | obj.y = 2; 32 | delete obj.x; // true 33 | delete obj.y; // true 34 | obj.x; // undefined 35 | obj.y; // undefined 36 | 37 | 在上面的例子中, `obj.x` 和 `obj.y` 可以被刪除是因為他們沒有 `DontDelete` 的屬性。 38 | 所以下面的例子也可以這樣用。 39 | 40 | // 可以運作,除了 IE: 41 | var GLOBAL_OBJECT = this; 42 | GLOBAL_OBJECT.a = 1; 43 | a === GLOBAL_OBJECT.a; // true - just a global var 44 | delete GLOBAL_OBJECT.a; // true 45 | GLOBAL_OBJECT.a; // undefined 46 | 47 | 這裡我們想要去刪除 `a`。 [`this`](#funciton.this) 這裡指向一個全域的物件,和我們明確了地定義 `a` 是它的屬性,所以可以刪除它。 48 | 49 | IE 有些臭蟲,所以上面的程式碼無法使用(至少 6~8) 50 | 51 | ### 函式的參數和內建 52 | 53 | 函式的普通參數,[`arguments` object](#function.arguments) 還有一些內建的屬性都有 `DontDelete` 的建立 54 | 55 | // function 參數和屬性 56 | (function (x) { 57 | 58 | delete arguments; // false 59 | typeof arguments; // "object" 60 | 61 | delete x; // false 62 | x; // 1 63 | 64 | function f(){} 65 | delete f.length; // false 66 | typeof f.length; // "number" 67 | 68 | })(1); 69 | 70 | ### 接受物件 71 | 72 | 控制符可以接受無法預測的物件。由於一些特別的情況,會允許它能夠 `delete` 73 | 74 | ### 結語 75 | 76 | `delete` 控制符通常都有難以預料的行為,所以我們只可以安全的刪除顯著的屬性在普通的物件上。 77 | 78 | 79 | -------------------------------------------------------------------------------- /doc/zhtw/core/eval.md: -------------------------------------------------------------------------------- 1 | ## 為什麼不要使用 `eval` 2 | 3 | 因為 `eval` 函數會在 Javascript 的區域性的區間執行那段程式碼。 4 | 5 | var foo = 1; 6 | function test() { 7 | var foo = 2; 8 | eval('foo = 3'); 9 | return foo; 10 | } 11 | test(); // 3 12 | foo; // 1 13 | 14 | 但是, `eval` 只接受直接的呼叫而且那個函數只能叫做 `eval`,才能在一個區段中執行。 15 | 16 | var foo = 1; 17 | function test() { 18 | var foo = 2; 19 | var bar = eval; 20 | bar('foo = 3'); 21 | return foo; 22 | } 23 | test(); // 2 24 | foo; // 3 25 | 26 | 所有的 `eval` 都應該去比免試用。有 99.9% 的使用情況都可以 **不必** 使用到而達到同等效果。 27 | 28 | ### 偽裝的 `eval` 29 | 30 | [定時函數](#other.timeouts) `setTimeout` 和 `setInterval` 都可以接受一個字串當做他們第一個參數。這些字串 **永遠** 都會在全域範圍內執行,因此在這種情況下 `eval` 沒有被直接的使用。 31 | 32 | ### 安全上的顧慮 33 | 34 | `eval` 同樣有安全上的問題,因為所有的程式碼都可以被直接執行。 35 | 而他不應去執行一串未知的字串或是來自不幸任的來源。 36 | 37 | ### 結語 38 | 39 | `eval` 應該永遠不要去只用它,任何的程式在被他執行後都有性能和安全上的考慮。如果有情況需要去使用他,他都不應該列為第一順位的解決方法。 40 | 41 | 應該有更好的方法能夠去使用,但是最好都不要去使用 `eval`。 42 | 43 | -------------------------------------------------------------------------------- /doc/zhtw/core/undefined.md: -------------------------------------------------------------------------------- 1 | ## `undefined` 和 `null` 2 | 3 | JavaScript 中有兩個表示空值的方式, `null` 和 `undefined` , `undefined`式比較常用的一種。 4 | 5 | ### `undefined` 的值 6 | 7 | `undefined` 是一個值為 `undefined` 的類型。 8 | 9 | 語言中也定義了一個全域變數,它的值為 `undefined`,這個變數的被稱作 `undefined` 。 10 | 這個變數 **不是** 一個常數,也不是一個關鍵字。這表示它的值可以被輕易的覆蓋。 11 | 12 | > **ES5 提示: ** `undefined` 在 ECMAScript 5 裡 **不再是** *可寫* 的 13 | > 但是它的名稱還是可以被隱藏,比如說定義一個函數為 `undefined`。 14 | 15 | 這裡有一些例子會回傳 `undefined` 的值: 16 | 17 | - 進入尚未修改的全域變數 `undefined`。 18 | - 進入一個宣告但 **尚未** 初始化的變數。 19 | - `return` 表示式中沒有返回任何內容。 20 | - 呼叫不存在的屬性。 21 | - 函式參數沒有被傳遞數值。 22 | - 任何被被設定為 `undefined` 的變數。 23 | - 任何表達式中形式為 `void(expression)` 24 | 25 | ### 處理 `undefined` 值的改變 26 | 27 | 由於全域變數 `undefined` 只有保存 `undefined` 類型實際值的一個副本,指定了一個新的值並 **不會** 改變 `undefined`類型裡面的值。 28 | 29 | 為了避免去改變 `undefined` 的值,常用的技巧就是加上一個新的變數到 [匿名包裝器](#function.scopes)。在使用的時候,這個參數不會接受任何的值。 30 | 31 | var undefined = 123; 32 | (function(something, foo, undefined) { 33 | // undefined 在區域區間內得到了 `undefined` 的值 34 | 35 | })('Hello World', 42); 36 | 37 | 另外一個可以得到同樣的效果就是在內部宣告一個變數 38 | 39 | var undefined = 123; 40 | (function(something, foo) { 41 | var undefined; 42 | ... 43 | 44 | })('Hello World', 42); 45 | 46 | 唯一的不同就是在下者會多 4 個多 bytes 用來壓縮檔案,而且函數內野沒有其他需要使用 `var` 47 | 48 | ### 使用 `null` 49 | 50 | JavaScript 中所使用的 `undefined` 類似別的語言中的 *null* , 但實際上在 JavaScript 中的 `null` 算是另外一個類型。 51 | 52 | 它在 JavaScript 有些可以使用的地方 (例如說宣告一個原型的終結,例如 `Foo.prototype = null` )。 53 | 但是在大部分的時候可以用 `undefined`,來取代。 54 | 55 | 56 | -------------------------------------------------------------------------------- /doc/zhtw/function/closures.md: -------------------------------------------------------------------------------- 1 | ## Closures 和 References 2 | 3 | JavaScript 有一個很重要的特徵就是 **closures** 4 | 因為有 Closures,所以作用域 **永遠** 能夠去訪問作用區間外面的變數。 5 | [函數區間](#function.scopes) 是JavaScript 中唯一擁有自生作用域的結構,因此 Closures 的創立需要依賴函數 6 | 7 | ### 模仿私有變數 8 | 9 | function Counter(start) { 10 | var count = start; 11 | return { 12 | increment: function() { 13 | count++; 14 | }, 15 | 16 | get: function() { 17 | return count; 18 | } 19 | } 20 | } 21 | 22 | var foo = Counter(4); 23 | foo.increment(); 24 | foo.get(); // 5 25 | 26 | 這裡,`Counter` 返回兩個 Closures,函數 `increment` 還有 `get`。這兩個函數都維持著對外部作用域 `Counter` 的引用,因此總可以訪問作用域的變數 `count`。 27 | 28 | 29 | ### 為什麼不可以在外部訪問私有變數 30 | 31 | 因為 Javascript **不可以** 對作用域進行引用或賦值。因此外部的地方沒有辦法訪問 `count` 變數。 32 | 唯一的途徑就是經過那兩個 Closures 33 | 34 | var foo = new Counter(4); 35 | foo.hack = function() { 36 | count = 1337; 37 | }; 38 | 39 | 在上面的例子中 `count` **不會** 改變到 `Counter` 裡面的 `count` 的值。因為 `foo.hack` 沒有在 **那個** 作用域內被宣告。它只有會覆蓋或者建立在一個 **全域** 的變數 `count` 40 | 41 | ### 在循環內的 Closures 42 | 43 | 一個常見的錯誤就是在 Closures 中使用迴圈,假設我們要使用每次迴圈中所使用的進入變數 44 | 45 | for(var i = 0; i < 10; i++) { 46 | setTimeout(function() { 47 | console.log(i); 48 | }, 1000); 49 | } 50 | 51 | 在上面的例子中它 **不會** 輸出數字從 `0` 到 `9`,但只會出現數字 `10` 十次。 52 | 在 `console.log` 被呼叫的時候,這個 *匿名* 函數中保持一個 **參考** 到 i ,此時 `for`迴圈已經結束, `i` 的值被修改成了 `10`。 53 | 為了要達到想要的結果,需要在每次創造 **副本** 來儲存 `i` 的變數。 54 | 55 | ### 避免引用錯誤 56 | 57 | 為了要有達到正確的效果,最好是把它包在一個 58 | [匿名函數](#function.scopes). 59 | 60 | for(var i = 0; i < 10; i++) { 61 | (function(e) { 62 | setTimeout(function() { 63 | console.log(e); 64 | }, 1000); 65 | })(i); 66 | } 67 | 68 | 匿名外部的函數被呼叫,並把 `i` 作為它第一個參數,此時函數內 `e` 變數就擁有了一個 `i` 的拷貝。 69 | 當傳遞給 `setTimeout` 這個匿名函數執行時,它就擁有了對 `e` 的引用,而這個值 **不會** 被循環改變。 70 | 另外有一個方法也可以完成這樣的工作,那就是在匿名函數中返回一個函數,這和上面的程式碼有同樣的效果。 71 | 72 | for(var i = 0; i < 10; i++) { 73 | setTimeout((function(e) { 74 | return function() { 75 | console.log(e); 76 | } 77 | })(i), 1000) 78 | } 79 | 80 | -------------------------------------------------------------------------------- /doc/zhtw/function/general.md: -------------------------------------------------------------------------------- 1 | ## 函式的宣告和表達方式 2 | 3 | 函式在 JavaScript 是第一等物件。這表示他們可以把函式當做值一樣傳遞。 4 | 一個常見的用法是用 *匿名函式* 當做一個回傳去呼叫另一個函式,這是一種非同步函式 5 | 6 | ### 函式的宣告 7 | 8 | function foo() {} 9 | 10 | 上面的函式在被執行之前會被 [解析(hoisted)](#function.scopes),因此它可以在 **任意** 的地方都是 *有宣告的* ,就算是在比這個函式還早呼叫。 11 | 12 | 13 | foo(); // 可以執行,因為 foo 已經在運行前就被建立 14 | function foo() {} 15 | 16 | ### `function` 的表達式 17 | 18 | var foo = function() {}; 19 | 20 | 這個例子把一個 *匿名* 函式賦值給變數 `foo`。 21 | 22 | foo; // 'undefined' 23 | foo(); // 錯誤: TypeError 24 | var foo = function() {}; 25 | 26 | 由於 `var` 已經宣告變數 `foo` 在所有的程式碼執行之前。 27 | 所以 `foo`已經在程式運行前就已經被定義過了。 28 | 但是因為賦值只會在運行時去職情,所以在程式碼執行前,`foo` 的值還沒被宣告所以為 [undefined](#core.undefined)。 29 | 30 | 31 | ### 命名函式的賦值表達式 32 | 33 | 另一個特殊狀況就勢將一個命名函式賦值給一個變數。 34 | 35 | var foo = function bar() { 36 | bar(); // 可以運行 37 | } 38 | bar(); // 錯誤:ReferenceError 39 | 40 | `bar` 不可以在外部的區域被執行,因為它只有在 `foo` 的函式內才可以去執行。 41 | 然而在 `bar` 內部還是可以看見。這是由於 JavaScript的 [命名處理](#function.scopes)所致。 42 | 函式名在函式內 *都* 可以去使用。 43 | 44 | -------------------------------------------------------------------------------- /doc/zhtw/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "JavaScript 庭院", 3 | "langTitle": "JavaScript Garden 繁體中文翻譯", 4 | "description": "JavaScript 語言中古怪用法及缺點的文件總集", 5 | "sections": [ 6 | { 7 | "title": "簡介", 8 | "dir": "intro", 9 | "articles": ["index"] 10 | }, 11 | { 12 | "title": "物件", 13 | "dir": "object", 14 | "articles": [ 15 | "general", 16 | "prototype", 17 | "hasownproperty", 18 | "forinloop" 19 | ] 20 | }, 21 | { 22 | "title": "函式", 23 | "dir": "function", 24 | "articles": [ 25 | "general", 26 | "this", 27 | "closures", 28 | "arguments", 29 | "constructors", 30 | "scopes" 31 | ] 32 | }, 33 | { 34 | "title": "陣列", 35 | "dir": "array", 36 | "articles": [ 37 | "general", 38 | "constructor" 39 | ] 40 | }, 41 | { 42 | "title": "類型", 43 | "dir": "types", 44 | "articles": [ 45 | "equality", 46 | "typeof", 47 | "instanceof", 48 | "casting" 49 | ] 50 | }, 51 | { 52 | "title": "核心", 53 | "dir": "core", 54 | "articles": [ 55 | "eval", 56 | "undefined", 57 | "semicolon", 58 | "delete" 59 | ] 60 | }, 61 | { 62 | "title": "其他", 63 | "dir": "other", 64 | "articles": [ 65 | "timeouts" 66 | ] 67 | } 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /doc/zhtw/intro/index.md: -------------------------------------------------------------------------------- 1 | ## 簡介 2 | 3 | JavaScript 庭院 是一個不斷更新的文件,最主要是要去了解一些 Javascript 比較古怪的部份。 4 | 給一些意見來防止遇到一些常見的錯誤和一些難以發現的問題,以及性能問題和不好的習慣。 5 | 初學者也可以藉此去了解 Javascript 這項語言的特性。 6 | 7 | JavaScript 庭院 並 **不是** 要教導你 Javascript 的語言。 8 | 如果要能夠理解這篇文章的內容,你需要事先學習 JavaScript 的基礎知識。 9 | 在 Mozilla 開發者網路中有一系列非常棒的學習[guide][1]。 10 | 11 | 12 | ## 作者 13 | 14 | 這個使用手冊是來自於 [Stack Overflow][2] 的使用者, [Ivo Wetzel][3] 15 | (寫作) 和 [Zhang Yi Jiang][4] (設計). 16 | 17 | ## 貢獻者 18 | 19 | - [貢獻者](https://github.com/BonsaiDen/JavaScript-Garden/graphs/contributors) 20 | 21 | ## 繁體中文翻譯 22 | 23 | - [紀力榮][29] 24 | - [張仲威][30] 25 | 26 | ## 存在 27 | 28 | JavaScript 庭院 存在於 GitHub, 但是 [Cramer Development][7] 讓我們有一個存放地 [JavaScriptGarden.info][8]. 29 | 30 | ## 許可 31 | 32 | JavaScript 庭院是在 [MIT license][9] 許可協議下發佈,並存在於 33 | [GitHub][10]. 如果你有發現錯誤或是打字上的錯誤 [新增一個任務][11] 或者發一個請求。 你也可以在 StackOverflow 的 [JavaScript room][12] 上面找到我們。 34 | 35 | [1]: https://developer.mozilla.org/en/JavaScript/Guide 36 | [2]: http://stackoverflow.com/ 37 | [3]: http://stackoverflow.com/users/170224/ivo-wetzel 38 | [4]: http://stackoverflow.com/users/313758/yi-jiang 39 | [5]: https://github.com/caio 40 | [6]: https://github.com/blixt 41 | [7]: http://cramerdev.com/ 42 | [8]: http://javascriptgarden.info/ 43 | [9]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE 44 | [10]: https://github.com/BonsaiDen/JavaScript-Garden 45 | [11]: https://github.com/BonsaiDen/JavaScript-Garden/issues 46 | [12]: http://chat.stackoverflow.com/rooms/17/javascript 47 | [29]: http://github.com/chilijung 48 | [30]: http://github.com/wwwy3y3 49 | -------------------------------------------------------------------------------- /doc/zhtw/object/forinloop.md: -------------------------------------------------------------------------------- 1 | ## `for in` 迴圈 2 | 3 | 就像其他的 `in` 操作符一樣, `for in` 循環也進入所有在物件中的屬性 4 | 5 | > **注意: ** `for in` 迴圈 **不會** 進入那些 `enumerable` 屬性是 `false`,舉例來說, 陣列中 `length` 的屬性 6 | 7 | // 修改 Object.prototype 8 | Object.prototype.bar = 1; 9 | 10 | var foo = {moo: 2}; 11 | for(var i in foo) { 12 | console.log(i); // 輸出兩個屬性:bar 和 moo 13 | } 14 | 15 | 由於不可能改變 `for in` 本身的行為,因為有必要過濾出那些不希望在迴圈出現的屬性,這可以用 `Object.prototype` 原型上的 [`hasOwnProperty`](#object.hasownproperty) 的函數來完成。 16 | 17 | > **注意: ** 由於 `for in` 總是要到所有原型鏈裡,因此如果物件的繼承層次太深的話會影響性能。 18 | 19 | 20 | ### 用 `hasOwnProperty` 來過濾 21 | 22 | // foo 變數是上面範例中的 23 | for(var i in foo) { 24 | if (foo.hasOwnProperty(i)) { 25 | console.log(i); 26 | } 27 | } 28 | 29 | 這個版本的程式碼是唯一正確的寫法。由於我們使用了 `hasOwnProperty`,這次 **只** 輸出 `moo`。 30 | 如果不只用這個程式碼在原型物件中(比如 `Object.prototype`)被擴展可能會出錯。 31 | 32 | 一個廣泛的模組 [Prototype][1]就礦展了圓型的 JavaScript 物件。 33 | 因此,但這模組包含在頁面中時,不使用 `hasOwnProperty` 過濾的 `for in` 尋難免會出問題。 34 | 35 | ### 總結 36 | 37 | 推薦 **總是** 使用 `hasOwnProperty`。不要對程式碼的環境做任何假設,不要假設原生的對象是否被擴張 38 | 39 | [1]: http://www.prototypejs.org/ 40 | 41 | -------------------------------------------------------------------------------- /doc/zhtw/object/general.md: -------------------------------------------------------------------------------- 1 | ## 物件的使用和屬性 2 | 3 | 每個變數可以表現像 JavaScript 物件,除了 [`null`](#core.undefined) 和 [`undefined`](#core.undefined)。 4 | 5 | false.toString(); // 'false' 6 | [1, 2, 3].toString(); // '1,2,3' 7 | 8 | function Foo(){} 9 | Foo.bar = 1; 10 | Foo.bar; // 1 11 | 12 | 一個常見的誤解就是字面值(literal)不是物件。這是因為 JavaScript 編譯器的一個錯誤,它試圖把 *點操作符* 解析為浮點數的字面值的一部分。 13 | 14 | 2.toString(); // 出錯: SyntaxError 15 | 16 | 有很多變通方法可以讓數字的字面值看起來像物件。 17 | 18 | 2..toString(); // 第二個點號可以正常解析 19 | 2 .toString(); // 注意點號前面的空格 20 | (2).toString(); // 2 先被計算 21 | 22 | ### 物件做為數據類型 23 | 24 | JavaScript 的物件可以作為 [*Hashmaps*][1]使用,主要用來保存命名的鍵與值的對應關係。 25 | 26 | 使用物件的字面語法 - `{}` - 可以創建一個簡單的物件。 這個新創建的物件從 `Object.prototype` [繼承](#object.prototype),下面,沒有任何 [自定義屬性](#object.hasownproperty)。 27 | 28 | var foo = {}; // 一個空的物件 29 | 30 | // 一個新的物件,有值為 12 的自定義屬性 'test' 31 | var bar = {test: 12}; 32 | 33 | ### 訪問屬性 34 | 35 | 有兩種訪問物件的屬性,點操作或是中括號操作。 36 | 37 | var foo = {name: 'kitten'} 38 | foo.name; // kitten 39 | foo['name']; // kitten 40 | 41 | var get = 'name'; 42 | foo[get]; // kitten 43 | 44 | foo.1234; // SyntaxError 45 | foo['1234']; // works 46 | 47 | 兩種語法是相等的,唯一的差別是,使用中括號允許你動態的設定屬性,使用點操作不允許屬性為變數,否則會造成語法錯誤 48 | 49 | ### 刪除屬性 50 | 51 | 唯一刪除屬性的方式就是用 `delete` 操作符。設置屬性為 `undefined` 或是 `null` 只有刪除的屬性和值的關聯,沒有真的刪掉屬性 52 | 53 | var obj = { 54 | bar: 1, 55 | foo: 2, 56 | baz: 3 57 | }; 58 | obj.bar = undefined; 59 | obj.foo = null; 60 | delete obj.baz; 61 | 62 | for(var i in obj) { 63 | if (obj.hasOwnProperty(i)) { 64 | console.log(i, '' + obj[i]); 65 | } 66 | } 67 | 68 | 上面的輸出結果有 `bar undefined` 和 `foo null` 69 | 只有 `baz` 真正被刪除而已,所以從輸出結果中消失。 70 | 71 | 72 | ### 屬姓名的語法 73 | 74 | var test = { 75 | 'case': 'I am a keyword, so I must be notated as a string', 76 | delete: 'I am a keyword, so me too' // raises SyntaxError 77 | }; 78 | 79 | 物件的屬性名可以使用字符串或是普通的宣告。但是由於 JavaScript 編譯器有個另外一個錯誤設計。 80 | 上面的兩種方式在 ECMAScript 5之前都會拋出 `SyntaxError` 的錯誤。 81 | 82 | 這個錯誤的原因是 `delete` 是 JavaScript 語言的一個 *關鍵字* 因此為了在更低的版本能執行最好用 *string literal* 83 | 84 | [1]: http://en.wikipedia.org/wiki/Hashmap 85 | 86 | -------------------------------------------------------------------------------- /doc/zhtw/object/hasownproperty.md: -------------------------------------------------------------------------------- 1 | ## `hasOwnProperty` 2 | 3 | 為了判斷一個物件是否包含 *自定義* 屬性而 *不是* [原形](#object.prototype)上的屬性,我們需要使用繼承 `Object.prototype` 的 `hasOwnProperty` 方法。 4 | 5 | > **注意:** 判斷一個屬性是否 `undefined` 是 **不夠的**。 6 | > 因為一個屬性可能存在,但是它的值被設成 `undefined`。 7 | 8 | `hasOwnProperty` 是 JavaScript 中唯一一個處理屬性但是 **不** 找原型鏈的函式。 9 | 10 | // 修改 Object.prototype 11 | Object.prototype.bar = 1; 12 | var foo = {goo: undefined}; 13 | 14 | foo.bar; // 1 15 | 'bar' in foo; // true 16 | 17 | foo.hasOwnProperty('bar'); // false 18 | foo.hasOwnProperty('goo'); // true 19 | 20 | 只有 `hasOwnProperty` 給予正確的結果,這對進入物件的屬性很有效果,**沒有** 其他方法可以用來排除原型上的屬性,而不是定義在物件 *自己* 上的屬性。 21 | 22 | ### `hasOwnProperty` 作為屬性 23 | 24 | JavaScript **不會** 保護 `hasOwnProperty`被占用,因此如果碰到存在這個屬性,就需要使用 *外部* 的 `hasOwnProperty` 來獲取正確的結果。 25 | 26 | var foo = { 27 | hasOwnProperty: function() { 28 | return false; 29 | }, 30 | bar: 'Here be dragons' 31 | }; 32 | 33 | foo.hasOwnProperty('bar'); // 永遠返回 false 34 | 35 | // 使用其他對象的 hasOwnProperty,並將其上下設置為 foo 36 | ({}).hasOwnProperty.call(foo, 'bar'); // true 37 | 38 | 39 | ### 結論 40 | 41 | 當檢查一個物件是否存在的時候, `hasOwnProperty` 是 **唯一** 可用的方法。 42 | 同時在使用 [`for in loop`](#object.forinloop) 43 | 建議使用 `hasOwnProperty` 避免 [原型](#object.prototype)所帶來的干擾。 -------------------------------------------------------------------------------- /doc/zhtw/types/casting.md: -------------------------------------------------------------------------------- 1 | ## 類型轉換 2 | 3 | JavaScript 是一個 *弱類型* 的程式語言,所以在 **任何** 情況下都可以 *強制類型轉換*。 4 | 5 | // 這些都是真 6 | new Number(10) == 10; // Number.toString() is converted 7 | // back to a number 8 | 9 | 10 == '10'; // Strings gets converted to Number 10 | 10 == '+10 '; // More string madness 11 | 10 == '010'; // And more 12 | isNaN(null) == false; // null converts to 0 13 | // which of course is not NaN 14 | 15 | // 下面都假 16 | 10 == 010; 17 | 10 == '-10'; 18 | 19 | > **ES5 注意:** 如果數字字面值的開頭是 `0` 它會強制轉為八進位數字解析。 20 | > 而在 ES5 嚴格模式下,它已經被刪除了。 21 | 22 | 為了去避免上驗的事件發生,我們會用 [嚴格等於操作符](#types.equality) 這是強烈建議。 23 | 因為它可以避免很多常見的問題,但 JavaScript 的弱類型系同仍然會導致一些其他問題。 24 | 25 | ### 內置類型的建構函式 26 | 27 | 內置類型(比如 `Number` 和 `String`)在被調用時,使用或不使用 `new` 的結果完全不同。 28 | 29 | new Number(10) === 10; // False, Object and Number 30 | Number(10) === 10; // True, Number and Number 31 | new Number(10) + 0 === 10; // True, due to implicit conversion 32 | 33 | 使用內置類型 `Number` 作為建構函式會建造一個新的 `Number` 物件,而在不使用 `new` 關鍵字的 `Number` 函式更像是一個數字轉換器。 34 | 35 | 另外,在比較中引入物件的字面值會導致更加複雜的強制類型轉換。 36 | 37 | 最好的方式是比較值的 **顯示** 的轉換成最有可能的三種形態 38 | 39 | ### 轉換成字符串 40 | 41 | '' + 10 === '10'; // true 42 | 43 | 將一個值加上空字符串可以輕鬆轉為字符串類型。 44 | 45 | ### 轉換成一個數字 46 | 47 | +'10' === 10; // true 48 | 49 | 使用 **一元** 的加號操作符,可以把字符串轉為數字。 50 | 51 | ### 轉換成一個 Bool 52 | 通過使用 **否** 操作符兩字,可以把一個值轉換為 Bool。 53 | 54 | !!'foo'; // true 55 | !!''; // false 56 | !!'0'; // true 57 | !!'1'; // true 58 | !!'-1' // true 59 | !!{}; // true 60 | !!true; // true 61 | 62 | 63 | -------------------------------------------------------------------------------- /doc/zhtw/types/equality.md: -------------------------------------------------------------------------------- 1 | ## 相等與比較 2 | 3 | JavaScript 有兩個不同的方式來比較兩個物件是否相等。 4 | 5 | ### 等於操作符 6 | 7 | 等於操作符是由兩個等號組成: `==` 8 | 9 | JavaScript 是一個 *弱類型* 語言。這代表它會為了比較兩個值而做 **強制類型轉換**。 10 | 11 | "" == "0" // false 12 | 0 == "" // true 13 | 0 == "0" // true 14 | false == "false" // false 15 | false == "0" // true 16 | false == undefined // false 17 | false == null // false 18 | null == undefined // true 19 | " \t\r\n" == 0 // true 20 | 21 | 上面的表格可以看出來這些結果強制轉換類型,這也代表說用 `==` 是一個不好的習慣,因為它會很難追蹤問題由於它複雜的規則。 22 | 23 | 此外,也有效率上面的問題在強制轉換類型。 24 | 例如說一個字串會被轉成數字來和別的數字做比較。 25 | 26 | ### 嚴格等於操作符 27 | 28 | 不像普通的等於操作符 `===` 不會做強制類型轉換。 29 | 30 | "" === "0" // false 31 | 0 === "" // false 32 | 0 === "0" // false 33 | false === "false" // false 34 | false === "0" // false 35 | false === undefined // false 36 | false === null // false 37 | null === undefined // false 38 | " \t\r\n" === 0 // false 39 | 40 | 上面的結果比較清楚,也有利於程式碼的分析。如果這兩個操作數的類型不一樣都就不會相等,有助於它性能的提昇。 41 | 42 | ### 比較物件 43 | 44 | 雖然 `==` 和 `===` 都是等於操作符,但其中有一個操作數為物件時,它的行為就會不同。 45 | 46 | {} === {}; // false 47 | new String('foo') === 'foo'; // false 48 | new Number(10) === 10; // false 49 | var foo = {}; 50 | foo === foo; // true 51 | 52 | 在這裡等於操作符比較 **不是** 值的相等,而是否是 **相同** 的身分。 53 | 有點像 Python 的 `is` 和 C 中的指標。 54 | 55 | ### 結論 56 | 57 | 強烈建議使用 **嚴格等於** 58 | 如果要轉換類型,應該要在 [explicitly](#types.casting)的時候轉換,而不是在語言本身用複雜的轉換規則。 59 | 60 | 61 | -------------------------------------------------------------------------------- /doc/zhtw/types/instanceof.md: -------------------------------------------------------------------------------- 1 | ## `instanceof` 操作符 2 | 3 | `instanceof` 操作符用來比較兩個建構函數的操作數。只有在比較字定義的物件時才有意義。這和 [typeof operator](#types.typeof)一樣用處不大。 4 | 5 | ### 比較定意義物件 6 | 7 | function Foo() {} 8 | function Bar() {} 9 | Bar.prototype = new Foo(); 10 | 11 | new Bar() instanceof Bar; // true 12 | new Bar() instanceof Foo; // true 13 | 14 | // This just sets Bar.prototype to the function object Foo, 15 | // but not to an actual instance of Foo 16 | Bar.prototype = Foo; 17 | new Bar() instanceof Foo; // false 18 | 19 | ### `instanceof` 比較內置類型 20 | 21 | new String('foo') instanceof String; // true 22 | new String('foo') instanceof Object; // true 23 | 24 | 'foo' instanceof String; // false 25 | 'foo' instanceof Object; // false 26 | 27 | 有一點需要注意的, `instanceof` 不能用來物件來自上下文不同的屬性(例如:瀏覽器中不同的文檔結構),因為它的建構函數不一樣。 28 | 29 | ### In Conclusion 30 | 31 | `instanceof` 操作符應該 **只** 用來比較同一個 JavaScript 上下文定意義的物件。 32 | 正如 [`typeof`](#types.typeof)操作符一樣,任何其他用法都要避免。 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "javascript-garden", 3 | "description": "A collection of documentation about the most quirky parts of the JavaScript language.", 4 | "version": "0.0.0", 5 | "dependencies": { 6 | "fomatto": "0.5.0", 7 | "forever": "0.10.8", 8 | "jade": "0.35.0", 9 | "neko": "1.1.2", 10 | "marked": "~0.2.9", 11 | "lodash": "~2.2.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /site/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layzie/JavaScript-Garden/04e401fbc66539b451f6083e14500f0f6c337c17/site/favicon.ico -------------------------------------------------------------------------------- /site/image/sidebar-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layzie/JavaScript-Garden/04e401fbc66539b451f6083e14500f0f6c337c17/site/image/sidebar-icon.png -------------------------------------------------------------------------------- /site/javascript/html5.js: -------------------------------------------------------------------------------- 1 | // html5shiv MIT @rem remysharp.com/html5-enabling-script 2 | // iepp v1.6.2 MIT @jon_neal iecss.com/print-protector 3 | /*@cc_on(function(m,c){var z="abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video";function n(d){for(var a=-1;++ai";if(g.childNodes.length!==1){var i=z.split("|"),o=i.length,s=RegExp("(^|\\s)("+z+")", 4 | "gi"),t=RegExp("<(/*)("+z+")","gi"),u=RegExp("(^|[^\\n]*?\\s)("+z+")([^\\n]*)({[\\n\\w\\W]*?})","gi"),r=c.createDocumentFragment(),k=c.documentElement;g=k.firstChild;var h=c.createElement("body"),l=c.createElement("style"),f;n(c);n(r);g.insertBefore(l, 5 | g.firstChild);l.media="print";m.attachEvent("onbeforeprint",function(){var d=-1,a=p(c.styleSheets,"all"),e=[],b;for(f=f||c.body;(b=u.exec(a))!=null;)e.push((b[1]+b[2]+b[3]).replace(s,"$1.iepp_$2")+b[4]);for(l.styleSheet.cssText=e.join("\n");++d code, article h3 > code { 49 | text-transform: none; 50 | font-size: 0.9em; 51 | } 52 | 53 | article h2 a { 54 | display: none; 55 | } 56 | 57 | article { 58 | font-size: 11px; 59 | width: 78%; 60 | padding-bottom: 0; 61 | border-bottom-width: 2px; 62 | } 63 | 64 | header article { 65 | 66 | } 67 | 68 | aside { 69 | width: 26%; 70 | right: -28%; 71 | padding-bottom: 6px; 72 | opacity: 1; 73 | } 74 | 75 | aside.es5:after { 76 | display: none; 77 | } 78 | 79 | a { 80 | color: inherit; 81 | } 82 | 83 | p, ul, ol { 84 | orphans: 3; 85 | line-height: 1.3em; 86 | } 87 | 88 | pre { 89 | background: #eee; 90 | padding: 6px 0 6px 20px; 91 | } 92 | 93 | aside p { 94 | font-size: 10px; 95 | color: #666; 96 | } 97 | 98 | article code, article pre code { 99 | background: #eee; 100 | } 101 | 102 | article code { 103 | padding: 1px 3px; 104 | } 105 | 106 | article pre code { 107 | padding: 0px; 108 | } 109 | 110 | article li { 111 | margin-top: 6px; 112 | } 113 | 114 | article ul, article ol { 115 | list-style-position: inside; 116 | margin-left: 8px; 117 | } 118 | 119 | .com { 120 | color: #600; 121 | font-style: italic; 122 | } 123 | 124 | .typ { 125 | color: #404; 126 | font-weight: bold; 127 | } 128 | 129 | .lit { 130 | color: #044; 131 | } 132 | 133 | .pun { 134 | color: #440; 135 | } 136 | 137 | .pln { 138 | color: #444; 139 | } 140 | 141 | .atn { 142 | color: #404; 143 | } 144 | 145 | .str, .atv { 146 | color: #060; 147 | } 148 | 149 | .kwd, .tag { 150 | color: #006; 151 | font-weight: bold; 152 | } 153 | --------------------------------------------------------------------------------