You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 1-js/08-prototypes/01-prototype-inheritance/article.md
+63
Original file line number
Diff line number
Diff line change
@@ -251,10 +251,73 @@ If we had other objects like `bird`, `snake` etc inheriting from `animal`, they
251
251
252
252
As a result, methods are shared, but the object state is not.
253
253
254
+
## for..in loop
255
+
256
+
The `for..in` loops over inherited properties too.
257
+
258
+
For instance:
259
+
260
+
```js run
261
+
let animal = {
262
+
eats:true
263
+
};
264
+
265
+
let rabbit = {
266
+
jumps:true,
267
+
__proto__: animal
268
+
};
269
+
270
+
*!*
271
+
// only own keys
272
+
alert(Object.keys(rabbit)); // jumps
273
+
*/!*
274
+
275
+
*!*
276
+
// inherited keys too
277
+
for(let prop in rabbit) alert(prop); // jumps, then eats
278
+
*/!*
279
+
```
280
+
281
+
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`.
282
+
283
+
So we can filter out inherited properties (or do something else with them):
284
+
285
+
```js run
286
+
let animal = {
287
+
eats:true
288
+
};
289
+
290
+
let rabbit = {
291
+
jumps:true,
292
+
__proto__: animal
293
+
};
294
+
295
+
for(let prop in rabbit) {
296
+
let isOwn =rabbit.hasOwnProperty(prop);
297
+
alert(`${prop}: ${isOwn}`); // jumps: true, then eats: false
298
+
}
299
+
```
300
+
301
+
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:
302
+
303
+

304
+
305
+
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.
306
+
307
+
...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.
308
+
309
+
```smart header="All other iteration methods ignore inherited properties"
310
+
All other key/value-getting methods, such as `Object.keys`, `Object.values` and so on ignore inherited properties.
311
+
312
+
They only operate on the object itself. Properties from the prototype are taken into account.
313
+
```
314
+
315
+
254
316
## Summary
255
317
256
318
- In JavaScript, all objects have a hidden `[[Prototype]]` property that's either another object or `null`.
257
319
- We can use `obj.__proto__` to access it (a historical getter/setter, there are other ways, to be covered soon).
258
320
- The object referenced by `[[Prototype]]` is called a "prototype".
259
321
- 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).
260
322
- 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.
323
+
- The `for..in` loop iterates over both own and inherited properties. All other key/value-getting methods only operate on the object itself.
0 commit comments