diff --git a/doc/bg/index.json b/doc/bg/index.json new file mode 100644 index 00000000..89c56d2a --- /dev/null +++ b/doc/bg/index.json @@ -0,0 +1,22 @@ +{ + "title": "Градината на JavaScript", + "langTitle": "Градината на JavaScript на български", + "description": "Ръководство за особеностите и пропуските в JavaScript.", + "sections": [ + { + "title": "Увод", + "dir": "intro", + "articles": ["index"] + }, + { + "title": "Обекти", + "dir": "object", + "articles": [ + "general", + "prototype", + "hasownproperty", + "forinloop" + ] + } + ] +} diff --git a/doc/bg/intro/index.md b/doc/bg/intro/index.md new file mode 100644 index 00000000..4041d26a --- /dev/null +++ b/doc/bg/intro/index.md @@ -0,0 +1,52 @@ +## Увод + +**Градината на JavaScript** е нарастваш набор от документи, засягащ най-странните +части на езика за програмиране ДжаваСкрипт (по-нататък JavaScript, +бел. пр.). Наръчникът дава съвети за избягване на обичайни и трудно-откриваеми +грешки, преодоляване на затруднения, свързани с производителността както и +лоши практики, с които начинаещите програмисти на JavaScript могат да се +сблъскат, опитвайки се да овладеят езика в дълбочина. + +Градината на JavaScript **няма за цел** да ви научи да програмирате на JavaScript. За да можете да разберете засегнатите въпроси, познаването на езика до някаква степен е силно препоръчително. За да научите основните положения в езика, прочетете [ръководството][1] в Мрежата за Разработчици на Мозила (Mozilla Developer Network). + +## Авторите + +Това ръководство е резултат от работата на двама възхитителни потребители на +[Stack Overflow][2] -- [Ivo Wetzel][3] (писане) и [Zhang Yi Jiang][4] (външен вид). + +По време на превода се поддържа от [Tim Ruffles](http://truffles.me.uk). + +## Участници + +Твърде много са, за да бъдат изредени тук. [Вижте всички +участници](https://github.com/BonsaiDen/JavaScript-Garden/graphs/contributors). + +## Преводачи + +Преводът на български бе започнат от [Красимир Беров](https://github.com/kberov). + + +## Хостинг + +"Градината на JavaScript" се намира на GitHub, но [Cramer Development][7] ни помага с огледално копие на [JavaScriptGarden.info][8]. + +## License + +"Градината на JavaScript" е публикуван под [лиценза MIT][9] и се намира на +[GitHub][10]. Ако намерите грешки, моля [пишете][11] или отстранете грешката +и създайте заявка за добавяне (pull request) на промяната в нашето хранилище. +Също така можете да ни намерите в стаята, посветена на [JavaScript][12] в чата +на Stack Overflow. + +[1]: https://developer.mozilla.org/en/JavaScript/Guide +[2]: http://stackoverflow.com/ +[3]: http://stackoverflow.com/users/170224/ivo-wetzel +[4]: http://stackoverflow.com/users/313758/yi-jiang +[5]: https://github.com/caio +[6]: https://github.com/blixt +[7]: http://cramerdev.com/ +[8]: http://javascriptgarden.info/ +[9]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE +[10]: https://github.com/BonsaiDen/JavaScript-Garden +[11]: https://github.com/BonsaiDen/JavaScript-Garden/issues +[12]: http://chat.stackoverflow.com/rooms/17/javascript diff --git a/doc/bg/object/forinloop.md b/doc/bg/object/forinloop.md new file mode 100644 index 00000000..28d586c4 --- /dev/null +++ b/doc/bg/object/forinloop.md @@ -0,0 +1,66 @@ +## The `for in` Loop + +Just like the `in` operator, the `for in` loop traverses the prototype +chain when iterating over the properties of an object. + +> **Note:** The `for in` loop will **not** iterate over any properties that +> have their `enumerable` attribute set to `false`; for example, the `length` +> property of an array. + + // Poisoning Object.prototype + Object.prototype.bar = 1; + + var foo = {moo: 2}; + for(var i in foo) { + console.log(i); // prints both bar and moo + } + +Since it is not possible to change the behavior of the `for in` loop itself, it +is necessary to filter out the unwanted properties inside the loop body. In +ECMAScript 3 and older, this is done using the [`hasOwnProperty`](#object.hasownproperty) +method of `Object.prototype`. + +Since ECMAScript 5, `Object.defineProperty` can be used with +`enumerable` set to `false` to add properties to objects (including `Object`) +without these properties being enumerated. In this case it is reasonable +to assume in application code that any enumerable properties have been added +for a reason and to omit `hasOwnProperty`, since it makes code more verbose and less +readable. In library code `hasOwnProperty` should still be used since +assumptions cannot be made about which enumerable properties might reside +on the prototype chain. + +> **Note:** Since `for in` always traverses the complete prototype chain, it +> will get slower with each additional layer of inheritance added to an object. + +### Using `hasOwnProperty` for Filtering + + // still the foo from above + for(var i in foo) { + if (foo.hasOwnProperty(i)) { + console.log(i); + } + } + +This version is the only correct one to use with older versions of ECMAScript. +Due to the use of `hasOwnProperty`, it will **only** print out `moo`. +When `hasOwnProperty` is left out, the code is prone to errors in cases where +the native prototypes - e.g. `Object.prototype` - +have been extended. + +In newer versions of ECMAScript, non-enumerable properties can be defined with +`Object.defineProperty`, reducing the risk of iterating over properties without +using `hasOwnProperty`. Nonetheless, care must be taken when using older +libraries like [Prototype][1], which does not yet take advantage of new ECMAScript features. +When this framework is included, `for in` loops that do not use +`hasOwnProperty` are guaranteed to break. + +### In Conclusion + +It is recommended to **always** use `hasOwnProperty` in ECMAScript 3 or lower, as well as +in library code. Assumptions should never be made in these environments about whether +the native prototypes have been extended or not. Since ECMAScript 5, `Object.defineProperty` +makes it possible to define non-enumerable properties and to omit `hasOwnProperty` in +application code. + +[1]: http://www.prototypejs.org/ + diff --git a/doc/bg/object/general.md b/doc/bg/object/general.md new file mode 100644 index 00000000..cb43da73 --- /dev/null +++ b/doc/bg/object/general.md @@ -0,0 +1,99 @@ +## Използване на обектите и свойствата им + +Всичко в JavaScript действа като обект. Има само две изключения: +[`null`](#core.undefined) и [`undefined`](#core.undefined). + + false.toString(); // 'false' + [1, 2, 3].toString(); // '1,2,3' + + function Foo(){} + Foo.bar = 1; + Foo.bar; // 1 + +Често срещано погрешно схващане е, че числата не могат да бъдат използвани +като обекти. Това се случва поради пропуск в синтактичния анализатор на +JavaScript, който разбира точката като десетична запетая. + + 2.toString(); // в браузър хвърля синтактична грешка (SyntaxError) + +Има три начина да се накарат буквално изписаните числа в програмния код също +да действат като обекти. + + 2..toString(); // втората точка е разпозната правилно + 2 .toString(); // забележете оставеното място пред точката + (2).toString(); // първо се изчислява изразът между скобите + +### Обектите като тип данни + +Обектите в JavaScript могат също да бъдат използвани като [*Хеш-таблици*][1]. +Те се състоят от именувани полета, сочещи към някакви стойности. + +Обект може да се създаде като се използва буквално представяне. Новият обект +[наследява](#object.prototype) от `Object.prototype` и няма [собствени +полета](#object.hasownproperty). + + var foo = {}; // нов празен обект + + // нов обект с поле 'test', което има стойност 12 + var bar = {test: 12}; + +### Достъп до полета + +Полетата (свойства) на даден обект могат да се ползват, като се използва точка +(обект.именаполе) или чрез използване на квадратни скоби (обект['именаполе']). + + var foo = {name: 'kitten'} + foo.name; // kitten + foo['name']; // kitten + + var get = 'name'; + foo[get]; // kitten + + foo.1234; // SyntaxError + foo['1234']; // работи + +Двата вида изписване работят по един и същи начин с единствената разлика, че +когато използваме квадратни скоби, можем динамично да създаваме нови полета и +да ползваме идентификатори, които иначе биха довели до синтактична грешка. + +### Изтриване на полета + +Единственият начин да се изтрие поле е като се използва операторът `delete`. +Задаване на стойност `undefined` или `null` само премахва *стойността* на +полето, но не и самото него -- *ключа*. + + var obj = { + bar: 1, + foo: 2, + baz: 3 + }; + obj.bar = undefined; + obj.foo = null; + delete obj.baz; + + for(var i in obj) { + if (obj.hasOwnProperty(i)) { + console.log(i, '' + obj[i]); + } + } + +Кодът горе показва `bar undefined` и `foo null` - само полето `baz` е +изтрито и го няма в изхода на скрипта. + +### Изписване на ключове + + var test = { + 'case': '"case" е ключова дума, затова трябва да бъде оградена с кавички', + delete: '"delete" също' // хвърля SyntaxError + }; + +Свойствата (полетата) на обектите може да се изписват като обикновени низове в +кавички или направо (без кавички). Поради друг пропуск в анализатора на +JavaScript, горният код хвърля `SyntaxError` преди ECMAScript 5. + +Тази грешка се получава, тъй като `delete` е *ключова дума*. В такива случаи +полетата трябва да се изписват в кавички при ползване на по-стар JavaScript +двигател. + +[1]: https://bg.wikipedia.org/wiki/Хеш-таблица + diff --git a/doc/bg/object/hasownproperty.md b/doc/bg/object/hasownproperty.md new file mode 100644 index 00000000..10423b00 --- /dev/null +++ b/doc/bg/object/hasownproperty.md @@ -0,0 +1,58 @@ +## `hasOwnProperty` + +To check whether an object has a property defined on *itself* and not somewhere +on its [prototype chain](#object.prototype), it is necessary to use the +`hasOwnProperty` method which all objects inherit from `Object.prototype`. + +> **Note:** It is **not** enough to check whether a property is `undefined`. The +> property might very well exist, but its value just happens to be set to +> `undefined`. + +`hasOwnProperty` is the only thing in JavaScript which deals with properties and +does **not** traverse the prototype chain. + + // Poisoning Object.prototype + Object.prototype.bar = 1; + var foo = {goo: undefined}; + + foo.bar; // 1 + 'bar' in foo; // true + + foo.hasOwnProperty('bar'); // false + foo.hasOwnProperty('goo'); // true + +Only `hasOwnProperty` will give the correct and expected result. See the section +on [`for in` loops](#object.forinloop) for more details on when to use +`hasOwnProperty` when iterating over object +properties. + +### `hasOwnProperty` as a Property + +JavaScript does not protect the property name `hasOwnProperty`; thus, if the +possibility exists that an object might have a property with this name, it is +necessary to use an *external* `hasOwnProperty` to get correct results. + + var foo = { + hasOwnProperty: function() { + return false; + }, + bar: 'Here be dragons' + }; + + foo.hasOwnProperty('bar'); // always returns false + + // Use another Object's hasOwnProperty and call it with 'this' set to foo + ({}).hasOwnProperty.call(foo, 'bar'); // true + + // It's also possible to use hasOwnProperty from the Object + // prototype for this purpose + Object.prototype.hasOwnProperty.call(foo, 'bar'); // true + + +### In Conclusion + +Using `hasOwnProperty` is the **only** reliable method to check for the +existence of a property on an object. It is recommended that `hasOwnProperty` +be used in many cases when iterating over object properties as described +in the section on [`for in` loops](#object.forinloop). + diff --git a/doc/bg/object/prototype.md b/doc/bg/object/prototype.md new file mode 100644 index 00000000..a5c21424 --- /dev/null +++ b/doc/bg/object/prototype.md @@ -0,0 +1,115 @@ +## Прототипът + +JavaScript не притежава класически модел за наследяване. Вместо това се +използва *прототипен* модел. + +Въпреки че това се смята за слабост на JavaScript, наследяването чрез +прототипи е всъщност по-мощен модел от класическия модел (чрез класове). Доста +по-лесно е да се осъществи класически модел на наследяване на основата на +прототипи отколкото обратното. + +JavaScript е единственият широко използван език, притежаващ наследяване чрез +прототипи. Затова може да ви отнеме време да разберете добре разликите между +двата модела. + +> **Note:** Simply using `Bar.prototype = Foo.prototype` will result in both objects +> sharing the **same** prototype. Therefore, changes to either object's prototype +> will affect the prototype of the other as well, which in most cases is not the +> desired effect. + + function Foo() { + this.value = 42; + } + Foo.prototype = { + method: function() {} + }; + + function Bar() {} + + // Set Bar's prototype to a new instance of Foo + Bar.prototype = new Foo(); + Bar.prototype.foo = 'Hello World'; + + // Make sure to list Bar as the actual constructor + Bar.prototype.constructor = Bar; + + var test = new Bar(); // create a new bar instance + + // The resulting prototype chain + test [instance of Bar] + Bar.prototype [instance of Foo] + { foo: 'Hello World', value: 42 } + Foo.prototype + { method: ... } + Object.prototype + { toString: ... /* etc. */ } + +In the code above, the object `test` will inherit from both `Bar.prototype` and +`Foo.prototype`; hence, it will have access to the function `method` that was +defined on `Foo`. It will also have access to the property `value` of the +**one** `Foo` instance that is its prototype. It is important to note that `new +Bar()` does **not** create a new `Foo` instance, but reuses the one assigned to +its prototype; thus, all `Bar` instances will share the **same** `value` property. + +> **Note:** Do **not** use `Bar.prototype = Foo`, since it will not point to +> the prototype of `Foo` but rather to the function object `Foo`. So the +> prototype chain will go over `Function.prototype` and not `Foo.prototype`; +> therefore, `method` will not be on the prototype chain. + +### Property Lookup + +When accessing the properties of an object, JavaScript will traverse the +prototype chain **upwards** until it finds a property with the requested name. + +If it reaches the top of the chain - namely `Object.prototype` - and still +hasn't found the specified property, it will return the value +[undefined](#core.undefined) instead. + +### The Prototype Property + +While the prototype property is used by the language to build the prototype +chains, it is still possible to assign **any** given value to it. However, +primitives will simply get ignored when assigned as a prototype. + + function Foo() {} + Foo.prototype = 1; // no effect + +Assigning objects, as shown in the example above, will work, and allows for dynamic +creation of prototype chains. + +### Performance + +The lookup time for properties that are high up on the prototype chain can have +a negative impact on performance, and this may be significant in code where +performance is critical. Additionally, trying to access non-existent properties +will always traverse the full prototype chain. + +Also, when [iterating](#object.forinloop) over the properties of an object +**every** property that is on the prototype chain will be enumerated. + +### Extension of Native Prototypes + +One mis-feature that is often used is to extend `Object.prototype` or one of the +other built in prototypes. + +This technique is called [monkey patching][1] and breaks *encapsulation*. While +used by popular frameworks such as [Prototype][2], there is still no good +reason for cluttering built-in types with additional *non-standard* functionality. + +The **only** good reason for extending a built-in prototype is to backport +the features of newer JavaScript engines; for example, +[`Array.forEach`][3]. + +### In Conclusion + +It is **essential** to understand the prototypal inheritance model before +writing complex code that makes use of it. Also, be aware of the length of the +prototype chains in your code and break them up if necessary to avoid possible +performance problems. Further, the native prototypes should **never** be +extended unless it is for the sake of compatibility with newer JavaScript +features. + +[1]: http://en.wikipedia.org/wiki/Monkey_patch +[2]: http://prototypejs.org/ +[3]: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach + diff --git a/doc/language.json b/doc/language.json index df12ab7d..ec4765ce 100644 --- a/doc/language.json +++ b/doc/language.json @@ -1,4 +1,4 @@ { "default": "en", - "listed": ["by","en","es","fi","fr","hu","it","ja","ko","pl","ptbr","ru","tr","zh","zhtw"] + "listed": ["bg", "by","en","es","fi","fr","hu","it","ja","ko","pl","ptbr","ru","tr","zh","zhtw"] }