diff --git a/1-js/2-first-steps/07-types/article.md b/1-js/2-first-steps/07-types/article.md index a35ad46f..c95698fd 100644 --- a/1-js/2-first-steps/07-types/article.md +++ b/1-js/2-first-steps/07-types/article.md @@ -234,7 +234,7 @@ Here we have a variable `key` which contains the property name, probably evaluat Most of time, the dot is used to access object properties, but when we need a complex property name or to pass the name as a variable, then -- we go square brackets. -Javascript supports object inheritance. There are many types that are based on objects: `Date` for dates, `Array` for ordered data, `Error` for error-reporting and so on. So the word "object" is applicable to a variety of things. The term *plain objects* is used to represent "basic" objects, the ones we create with `{ ... }`. +Javascript supports object inheritance. There are many types that are based on objects: `Date` for dates, `Array` for ordered data, `Error` for error-reporting and so on. So the word "object" is applicable to a variety of things. The term *plain objects* or just `Object` (capital first) is used to represent "basic" objects, the ones we create with `{ ... }`. Objects in JavaScript are very powerful. Here we've just scratched the surface of the topic that is really huge. We'll be closely working with objects and learning more about them in further parts of the tutorial. @@ -385,7 +385,7 @@ There are 7 basic types in JavaScript. - `null` for unknown values. - `undefined` for unassigned values. - `symbol` for unique identifiers. -- `object` for more complex data structures (there exist many, we saw arrays). +- `object` for more complex data structures. The `typeof` operator allows to see which type is stored in the variable. diff --git a/1-js/2-first-steps/20-object-methods/article.md b/1-js/2-first-steps/20-object-methods/article.md index 3b07e45c..99cfbb78 100644 --- a/1-js/2-first-steps/20-object-methods/article.md +++ b/1-js/2-first-steps/20-object-methods/article.md @@ -264,7 +264,7 @@ Any operation on the Reference Type immediately "resolves" it: So any operation on the result of dot `'.'` except a direct call discards `this`. -## Explicit "this" with "call/apply" +## Explicit "this" with "call/apply" [#call-apply] We can call a function explicitly providing the value of `"this"`. @@ -335,7 +335,7 @@ So the use of `apply` over `call` is mainly a metter of personal preference. And There's still a way to bind "this" to a function. -[todo] ???? +[todo] migrate bind here???? ## Summary diff --git a/1-js/2-first-steps/21-object-tostring-valueof/article.md b/1-js/2-first-steps/21-object-tostring-valueof/article.md index 96dfb82f..3579de6f 100644 --- a/1-js/2-first-steps/21-object-tostring-valueof/article.md +++ b/1-js/2-first-steps/21-object-tostring-valueof/article.md @@ -94,7 +94,7 @@ In most projects though, only `toString()` is used, because objects are printed If only `toString()` is implemented, then both string and numeric conversions use it. -## Examples for built-ins +## Array example Let's check a few examples to finally get the whole picture. @@ -118,61 +118,77 @@ alert( '1,2' + 1 ); // '1,21' Now the addition has the first operand -- a string, so it converts the second one to a string also. Hence the result. -Now with a plain object: +## Object, toString for the type + +With plain objects it's much more interesting. + +An object has both `valueOf()` and `toString()`, but for plain objects `valueOf()` returns the object itself: ```js run -alert( +{} ); // NaN -alert( {} + {} ); // [object Object][object Object] +let obj = { }; + +alert( obj === obj.valueOf() ); // true, valueOf returns the object itself ``` -Plain objects actually have both `toString()` and `valueOf()`: +Because `ToPrimitive` ignores `valueOf` if it returns an object, here we can assume that `valueOf` does not exist at all. -................TODO ALG OF OBJECT TOSTRING +Now `toString`. -The result of these operations should be somewhat obvious now. - - - - - - -## [[Class]] - -From the chapter we know that `typeof` cannot distinguish different kinds of objects. Arrays, plain objects and others are all the same "object" for it. - -But there's a semi-hidden way to access the right class. - -Most built-in objects - - - - -Here are some built-in objects - -Most built-in object implement only `toString()`. From the algorithm string conversion is much more widely used - - - - - - -The similar thing with the method `valueOf`. It is called when the object is converted to a number. +From the first sight it's obvious: ```js run -let room = { - number: 777, +let obj = { }; - valueOf() { - return this.number; - }, -}; - -alert( +room ); // 777, valueOf is called +alert( obj ); // [object Object] ``` -What really sounds strange -- is the name of the method. Why is it called "valueOf", why not "toNumber"? +But it's much more powerful than that. -The reason is that `valueOf` is used by default to convert an object to a primitive for operations where a primitive value is required. +By [specification](https://tc39.github.io/ecma262/#sec-object.prototype.tostring), `toString` can work in the context of any value. And it returns `[object ...]` with the type of an object instead of dots. + +The algorithm of the `toString()` for plain objects looks like this: + +- If `this` value is `undefined`, return `[object Undefined]` +- If `this` value is `null`, return `[object Null]` +- ...For arrays return `[object Array]`, for dates return `[object Date]` etc. +It even works for environment-specific objects that exist only in the browser (like `window`) or in node.js (like `process`). + +All we need to do to get the type of an `obj` -- is to call plain object `toString` passing `this = obj`. + +We can do it like this: + +```js run +let s = {}.toString; // copy toString of Object to a variable + +// what type is this? +let arr = []; + +// copy Object toString to it: +arr.toStringPlain = s; + +alert( arr.toStringPlain() ); // [object Array] <-- right! + +// try getting the type of a browser window object? +window.toStringPlain = s; + +alert( window.toStringPlain() ); // [object Window] <-- it works! +``` + +Please note that different objects usually have their own `toString`. As we've seen above, the `toString` of `Array` returns a list of items. So we need to use exactly the `toString` of a plain object -- `{}.toString`. + +To call it in the right context, we copy it into a variable `s` -- in Javascript functions are not hardwired to objects, even built-in ones, so we do it -- and then assign as a property to another object `arr.toStringPlain` (not to override `arr.toString`). That's called *method borrowing*. + +Actually, we could evade all complexities using [call](info:object-methods#call-apply) to pass `this`: + +```js run +let arr = []; + +alert( {}.toString.call(arr) ); // [object Array] +alert( {}.toString.call(window) ); // [object Window] +``` + +Here we do the same in one line: get the `toString` of a plain object and call it with the right `this` to get its type. +