This commit is contained in:
Ilya Kantor 2016-07-08 18:21:13 +03:00
parent 14d6875887
commit 75cdcb406c
3 changed files with 64 additions and 48 deletions

View file

@ -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. 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. 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. - `null` for unknown values.
- `undefined` for unassigned values. - `undefined` for unassigned values.
- `symbol` for unique identifiers. - `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. The `typeof` operator allows to see which type is stored in the variable.

View file

@ -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`. 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"`. 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. There's still a way to bind "this" to a function.
[todo] ???? [todo] migrate bind here????
## Summary ## Summary

View file

@ -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. 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. 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 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 ```js run
alert( +{} ); // NaN let obj = { };
alert( {} + {} ); // [object Object][object Object]
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. From the first sight it's obvious:
## [[Class]]
From the chapter <info:types> 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.
```js run ```js run
let room = { let obj = { };
number: 777,
valueOf() { alert( obj ); // [object Object]
return this.number;
},
};
alert( +room ); // 777, valueOf is called
``` ```
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.