From 06f99274069b186c8c355fde6405509318904e8f Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Fri, 10 May 2019 10:52:35 +0300 Subject: [PATCH] remove extra article --- .../01-prototype-inheritance/article.md | 63 +++++++++++++ .../rabbit-animal-object.png | Bin .../rabbit-animal-object@2x.png | Bin .../05-getting-all-properties/article.md | 83 ------------------ 4 files changed, 63 insertions(+), 83 deletions(-) rename 1-js/08-prototypes/{05-getting-all-properties => 01-prototype-inheritance}/rabbit-animal-object.png (100%) rename 1-js/08-prototypes/{05-getting-all-properties => 01-prototype-inheritance}/rabbit-animal-object@2x.png (100%) delete mode 100644 1-js/08-prototypes/05-getting-all-properties/article.md diff --git a/1-js/08-prototypes/01-prototype-inheritance/article.md b/1-js/08-prototypes/01-prototype-inheritance/article.md index e763d5f3..ea6f7c9d 100644 --- a/1-js/08-prototypes/01-prototype-inheritance/article.md +++ b/1-js/08-prototypes/01-prototype-inheritance/article.md @@ -251,6 +251,68 @@ If we had other objects like `bird`, `snake` etc inheriting from `animal`, they As a result, methods are shared, but the object state is not. +## for..in loop + +The `for..in` loops over inherited properties too. + +For instance: + +```js run +let animal = { + eats: true +}; + +let rabbit = { + jumps: true, + __proto__: animal +}; + +*!* +// only own keys +alert(Object.keys(rabbit)); // jumps +*/!* + +*!* +// inherited keys too +for(let prop in rabbit) alert(prop); // jumps, then eats +*/!* +``` + +If that's not what we want, and we'd like to exclude inherited properties, there's a built-in method [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): it returns `true` if `obj` has its own (not inherited) property named `key`. + +So we can filter out inherited properties (or do something else with them): + +```js run +let animal = { + eats: true +}; + +let rabbit = { + jumps: true, + __proto__: animal +}; + +for(let prop in rabbit) { + let isOwn = rabbit.hasOwnProperty(prop); + alert(`${prop}: ${isOwn}`); // jumps: true, then eats: false +} +``` + +Here we have the following inheritance chain: `rabbit`, then `animal`, then `Object.prototype` (because `animal` is a literal object `{...}`, so it's by default), and then `null` above it: + +![](rabbit-animal-object.png) + +Note, there's one funny thing. Where is the method `rabbit.hasOwnProperty` coming from? Looking at the chain we can see that the method is provided by `Object.prototype.hasOwnProperty`. In other words, it's inherited. + +...But why `hasOwnProperty` does not appear in `for..in` loop, if it lists all inherited properties? The answer is simple: it's not enumerable. Just like all other properties of `Object.prototype`. That's why they are not listed. + +```smart header="All other iteration methods ignore inherited properties" +All other key/value-getting methods, such as `Object.keys`, `Object.values` and so on ignore inherited properties. + +They only operate on the object itself. Properties from the prototype are taken into account. +``` + + ## Summary - In JavaScript, all objects have a hidden `[[Prototype]]` property that's either another object or `null`. @@ -258,3 +320,4 @@ As a result, methods are shared, but the object state is not. - The object referenced by `[[Prototype]]` is called a "prototype". - If we want to read a property of `obj` or call a method, and it doesn't exist, then JavaScript tries to find it in the prototype. Write/delete operations work directly on the object, they don't use the prototype (unless the property is actually a setter). - If we call `obj.method()`, and the `method` is taken from the prototype, `this` still references `obj`. So methods always work with the current object even if they are inherited. +- The `for..in` loop iterates over both own and inherited properties. All other key/value-getting methods only operate on the object itself. diff --git a/1-js/08-prototypes/05-getting-all-properties/rabbit-animal-object.png b/1-js/08-prototypes/01-prototype-inheritance/rabbit-animal-object.png similarity index 100% rename from 1-js/08-prototypes/05-getting-all-properties/rabbit-animal-object.png rename to 1-js/08-prototypes/01-prototype-inheritance/rabbit-animal-object.png diff --git a/1-js/08-prototypes/05-getting-all-properties/rabbit-animal-object@2x.png b/1-js/08-prototypes/01-prototype-inheritance/rabbit-animal-object@2x.png similarity index 100% rename from 1-js/08-prototypes/05-getting-all-properties/rabbit-animal-object@2x.png rename to 1-js/08-prototypes/01-prototype-inheritance/rabbit-animal-object@2x.png diff --git a/1-js/08-prototypes/05-getting-all-properties/article.md b/1-js/08-prototypes/05-getting-all-properties/article.md deleted file mode 100644 index 34518178..00000000 --- a/1-js/08-prototypes/05-getting-all-properties/article.md +++ /dev/null @@ -1,83 +0,0 @@ - -# Getting all properties - -There are many ways to get keys/values from an object. - -Most of them operate on the object itself, excluding the prototype, let's recall them: - -- [Object.keys(obj)](mdn:js/Object/keys) / [Object.values(obj)](mdn:js/Object/values) / [Object.entries(obj)](mdn:js/Object/entries) -- returns an array of enumerable own string property names/values/key-value pairs. These methods only list *enumerable* properties, and those that have *strings as keys*. - -If we want symbolic properties: - -- [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) -- returns an array of all own symbolic property names. - -If we want non-enumerable properties: - -- [Object.getOwnPropertyNames(obj)](mdn:js/Object/getOwnPropertyNames) -- returns an array of all own string property names. - -If we want *all* properties: - -- [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) -- returns an array of all own property names. - -These methods are a bit different about which properties they return, but all of them operate on the object itself. Properties from the prototype are not listed. - -## for..in loop - -The `for..in` loop is different: it loops over inherited properties too. - -For instance: - -```js run -let animal = { - eats: true -}; - -let rabbit = { - jumps: true, - __proto__: animal -}; - -*!* -// only own keys -alert(Object.keys(rabbit)); // jumps -*/!* - -*!* -// inherited keys too -for(let prop in rabbit) alert(prop); // jumps, then eats -*/!* -``` - -If that's not what we want, and we'd like to exclude inherited properties, there's a built-in method [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): it returns `true` if `obj` has its own (not inherited) property named `key`. - -So we can filter out inherited properties (or do something else with them): - -```js run -let animal = { - eats: true -}; - -let rabbit = { - jumps: true, - __proto__: animal -}; - -for(let prop in rabbit) { - let isOwn = rabbit.hasOwnProperty(prop); - alert(`${prop}: ${isOwn}`); // jumps: true, then eats: false -} -``` - -Here we have the following inheritance chain: `rabbit`, then `animal`, then `Object.prototype` (because `animal` is a literal object `{...}`, so it's by default), and then `null` above it: - -![](rabbit-animal-object.png) - -Note, there's one funny thing. Where is the method `rabbit.hasOwnProperty` coming from? Looking at the chain we can see that the method is provided by `Object.prototype.hasOwnProperty`. In other words, it's inherited. - -...But why `hasOwnProperty` does not appear in `for..in` loop, if it lists all inherited properties? The answer is simple: it's not enumerable. Just like all other properties of `Object.prototype`. That's why they are not listed. - -## Summary - -Most methods ignore inherited properties, with a notable exception of `for..in`. - -For the latter we can use [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): it returns `true` if `obj` has its own (not inherited) property named `key`.