This commit is contained in:
Ilya Kantor 2017-01-29 02:57:35 +03:00
parent 7ed245d540
commit 799a7e220a
11 changed files with 410 additions and 37 deletions

View file

@ -575,11 +575,11 @@ In the code above, an error inside `try` always falls out, because there's no `c
The information from this section is not a part of the core Javascript. The information from this section is not a part of the core Javascript.
``` ```
Let's imagine we've got a fatal error outside of `try..catch`, and the script died. Like a programming error that no `try..catch` doesn't know how to handle, or something else terrible. Let's imagine we've got a fatal error outside of `try..catch`, and the script died. Like a programming error or something else terrible.
Is there a way to react on such happening? We may want to log the error, show something to the user (normally he doesn't see the error message) etc. Is there a way to react on such a happening? We may want to log the error, show something to the user (normally he doesn't see error messages) etc.
There is none in the specification, but environments usually provide it, because it's really handy. For instance, Node.JS has [process.on('uncaughtException')](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property. It will run in case of an uncaught error. There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.JS has [process.on('uncaughtException')](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property. It will run in case of an uncaught error.
The syntax: The syntax:
@ -621,7 +621,14 @@ For instance:
The role of the global handler `window.onerror` is usually not to recover the script execution -- that's probably impossible in case of programming errors, but to send the error message to developers. The role of the global handler `window.onerror` is usually not to recover the script execution -- that's probably impossible in case of programming errors, but to send the error message to developers.
There are also web-services that provide error-logging facilities for such cases, like <https://errorception.com> or <http://www.muscula.com>. They give a script with custom `window.onerror` function, and once inserted into a page, it reports about all errors it gets to their server. Afterwards developers can browse them and get notifications on email about fresh errors. There are also web-services that provide error-logging for such cases, like <https://errorception.com> or <http://www.muscula.com>.
They work like this:
1. We register at the service and get a piece of JS (or a script URL) from them to insert on pages.
2. That JS script has a custom `window.onerror` function.
3. When an error occurs, it sends a network request about it to the service.
4. We can log in to the service web interface and see errors.
## Summary ## Summary

View file

@ -4,9 +4,12 @@ importance: 5
# Inherit from SyntaxError # Inherit from SyntaxError
Create an error `FormatError` that inherits from `SyntaxError`. Create a class `FormatError` that inherits from the built-in `SyntaxError` class.
It should support `message`, `name` and `stack` properties.
Usage example: Usage example:
```js ```js
let err = new FormatError("formatting error"); let err = new FormatError("formatting error");
@ -14,5 +17,6 @@ alert( err.message ); // formatting error
alert( err.name ); // FormatError alert( err.name ); // FormatError
alert( err.stack ); // stack alert( err.stack ); // stack
alert( err instanceof SyntaxError ); // true alert( err instanceof FormatError ); // true
alert( err instanceof SyntaxError ); // true (because inherits from SyntaxError)
``` ```

View file

@ -1,36 +1,35 @@
# Custom errors, extending Error # Custom errors, extending Error
When we develop our software, we need our own error classes. For network operations we may need `HttpError`, for database operations `DbError`, for searching operations `NotFoundError` and so on. When we develop something, we often need our own error classes to reflect specific things that may go wrong in our tasks. For errors in network operations we may need `HttpError`, for database operations `DbError`, for searching operations `NotFoundError` and so on.
Our errors should inherit from with the basic `Error` class and have basic error properties like `message`, `name` and, preferably, `stack`. But they also may have other properties of their own, e.g. `HttpError` objects may have `statusCode` property, that is `404` for the "page not found" error. Our errors should inherit from basic `Error` class and support basic error properties like `message`, `name` and, preferably, `stack`. But they also may have other properties of their own, e.g. `HttpError` objects may have `statusCode` property with a value like `404` or `403` or `500`.
Technically, we can use standalone classes for errors, because Javascript allows to use `throw` with any argument. But if we inherit from `Error`, then we can use `obj instanceof Error` check to identify error objects. So it's better to inherit from it. Technically, we can use standalone classes for our errors, because Javascript allows to use `throw` with any argument. But if we inherit from `Error`, then it becomes possible to use `obj instanceof Error` check to identify error objects. So it's better to inherit from it.
As we build our application, our own errors naturally form a hierarchy, for instance `HttpTimeoutError` may inherit from `HttpError`. Examples will follow soon. As we build our application, our own errors naturally form a hierarchy, for instance `HttpTimeoutError` may inherit from `HttpError`. Examples will follow soon.
## Extending Error ## Extending Error
As an example, let's create a function `readUser(json)` that should read JSON with user data. We are getting that data from a remote server or, maybe it may be altered by a visitor, or just for the sheer safety -- we should to be aware of possible errors in `json`. As an example, let's consider a function `readUser(json)` that should read JSON with user data.
Here's an example of how a valid `json` may look: Here's an example of how a valid `json` may look:
```js ```js
let json = `{ "name": "John", "age": 30 }`; let json = `{ "name": "John", "age": 30 }`;
``` ```
If the function receives malformed `json`, then it should throw `SyntaxError`. Fortunately, `JSON.parse` does exactly that. If `JSON.parse` receives malformed `json`, then it throws `SyntaxError`. But even if `json` is syntactically correct, it may don't have the necessary data. For instance, if may not have `name` and `age` properties that are essential for our users.
...But if the `json` is correct, that doesn't mean it has all the data. For instance, if may not have `name` or `age`. That's called "data validation" -- we need to ensure that the data has all the necessary fields. And if the validation fails, then it not really a `SyntaxError`, because the data is syntactically correct. Let's create `ValidationError` -- the error object of our own with additional information about the offending field.
That's called "data validation" -- we need to ensure that the data has all the necessary fields. And if the validation fails, then throwing `SyntaxError` would be wrong, because the data is syntactically correct. So we should throw `ValidationError` -- the error object of our own with the proper message and, preferable, with additional information about the offending field. Our `ValidationError` should inherit from the built-in `Error` class. To better understand what we're extending -- here's the approximate code for built-in [Error class](https://tc39.github.io/ecma262/#sec-error-message):
Let's make the `ValidationError` class. But to better understand what we're extending -- here's the approximate code for built-in [Error class](https://tc39.github.io/ecma262/#sec-error-message):
```js ```js
// "pseudocode" for the built-in Error class defined by Javascript itself
class Error { class Error {
constructor(message) { constructor(message) {
this.message = message; this.message = message;
this.name = "Error"; // (different names for different built-in errors) this.name = "Error"; // (different names for different built-in error classes)
this.stack = <sequence of nested calls>; // non-standard! most environments support it this.stack = <nested calls>; // non-standard, but most environments support it
} }
} }
``` ```
@ -38,7 +37,9 @@ class Error {
Now let's inherit from it: Now let's inherit from it:
```js run untrusted ```js run untrusted
*!*
class ValidationError extends Error { class ValidationError extends Error {
*/!*
constructor(message) { constructor(message) {
super(message); // (1) super(message); // (1)
this.name = "ValidationError"; // (2) this.name = "ValidationError"; // (2)
@ -58,11 +59,10 @@ try {
} }
``` ```
Notes: Please note:
1. In the line `(1)` we call the parent constructor to set the message. Javascript requires us to call `super` in the child constructor anyway.
2. The `name` property for our own errors should be assigned manually, otherwise it would be set by the superclass (to `"Error"`).
1. In the line `(1)` we call the parent constructor to set the message. Javascript requires us to call `super` in the child constructor.
2. The parent constructor sets the `name` property to `"Error"`, so here we reset it to the right value.
Let's try to use it in `readUser(json)`: Let's try to use it in `readUser(json)`:
@ -105,15 +105,15 @@ try {
} }
``` ```
Everything works -- both our `ValidationError` and the built-in `SyntaxError` from `JSON.parse` are correctly handled. Everything works -- both our `ValidationError` and the built-in `SyntaxError` from `JSON.parse` can be generated and handled.
Please note how the code check for the error type in `catch (err) { ... }`. We could use `if (err.name == "ValidationError")`, but `if (err instanceof ValidationError)` is much better, because in the future we are going to extend `ValidationError`, make new subtypes of it, namely `PropertyRequiredError`. And `instanceof` check will continue to work. So that's future proof. Please take a look at how the code checks for the error type in `catch (err) { ... }`. We could use `if (err.name == "ValidationError")`, but `if (err instanceof ValidationError)` is much better, because in the future we are going to extend `ValidationError`, make new subtypes of it, namely `PropertyRequiredError`. And `instanceof` check will continue to work. So that's future-proof.
Also it's important that if we meet an unknown error, then we just rethrow it. The `catch` only knows how to handle validation and syntax errors, other kinds (due to a typo in the code or such) should fall through. Also it's important that if `catch` meets an unknown error, then it rethrows it. The `catch` only knows how to handle validation and syntax errors, other kinds (due to a typo in the code or such) should fall through.
## Further inheritance ## Further inheritance
The `ValidationError` class is very generic. Let's make a more concrete class `PropertyRequiredError`, exactly for the absent properties. It will carry additional information about the property that's missing. The `ValidationError` class is very generic. Many things may be wrong. The property may be absent or it may be in a wrong format (like a string value for `age`). Let's make a more concrete class `PropertyRequiredError`, exactly for absent properties. It will carry additional information about the property that's missing.
```js run ```js run
class ValidationError extends Error { class ValidationError extends Error {
@ -166,13 +166,11 @@ try {
} }
``` ```
The new class `PropertyRequiredError` is easier to use, because we just pass the property name to it: `new PropertyRequiredError(property)`. The human-readable `message` is generated by the constructor. The new class `PropertyRequiredError` is easy to use: we only need to pass the property name: `new PropertyRequiredError(property)`. The human-readable `message` is generated by the constructor.
Plese note that `this.name` in `PropertyRequiredError` once again assigned manually. We could evade that by using `this.constructor.name` for `this.name` in the superclass. Plese note that `this.name` in `PropertyRequiredError` once again assigned manually. We could make our own "basic error" class, name it `MyError` that removes this burden from our shoulders by using `this.constructor.name` for `this.name` in the constructor. And then inherit from it.
The generic solution would be to make `MyError` class that takes care of it, and inherit from it. Here we go:
For instance:
```js run ```js run
class MyError extends Error { class MyError extends Error {
@ -193,21 +191,21 @@ class PropertyRequiredError extends ValidationError {
} }
} }
// name is correct
alert( new PropertyRequiredError("field").name ); // PropertyRequiredError alert( new PropertyRequiredError("field").name ); // PropertyRequiredError
``` ```
Now the inheritance became simpler, as we got rid of the `"this.name = ..."` line in the constructor.
## Wrapping exceptions ## Wrapping exceptions
The purpose of the function `readUser` in the code above is -- to "read the user data", right? There may occur different kinds of errors in the process, not only `SyntaxError` and `ValidationError`, but probably others if we continue developing it. The purpose of the function `readUser` in the code above is "to read the user data", right? There may occur different kinds of errors in the process. Right now we have `SyntaxError` and `ValidationError`, but there may appear more if we put more stuff into it.
Right now the code which calls `readUser` uses multiple `if` in `catch` to check for different error types and rethrow if the error is unknown. Right now the code which calls `readUser` uses multiple `if` in `catch` to check for different error types. The important questions is: do we really want to check for all error types one-by-one every time we call `readUser`?
But the important questions is: do we want to check for all these types every time we call `readUser`? Often the answer is: "No". The outer code wants to be "one level above all that". It wants to have some kind of "data reading error". Why exactly it happened -- is usually irrelevant (the message has the info). Or, even better if there is a way to get more details, but only if we need to.
Often the answer is: "No". The outer code wants to be "one level above all that". It wants to have some kind of "data reading error", and why exactly it happened -- is usually irrelevant (the message has the info). Or, even better if there is a way to get more details, but only if it wants to. So let's make a new class `ReadError` to represent such errors. If an error occurs inside `readUser`, we'll catch it there and generate `ReadError`. We'll also keep the reference to the original error in the `cause` property.
In our case, when a data-reading error occurs, we will create an object of the new class `ReadError`, that will provide the proper message. And we'll also keep the original error in its `cause` property, just in case.
```js run ```js run
class ReadError extends Error { class ReadError extends Error {
@ -237,21 +235,25 @@ function readUser(json) {
try { try {
user = JSON.parse(json); user = JSON.parse(json);
} catch (err) { } catch (err) {
*!*
if (err instanceof SyntaxError) { if (err instanceof SyntaxError) {
throw new ReadError("Syntax Error", err); throw new ReadError("Syntax Error", err);
} else { } else {
throw err; throw err;
} }
*/!*
} }
try { try {
validateUser(user); validateUser(user);
} catch (err) { } catch (err) {
*!*
if (err instanceof ValidationError) { if (err instanceof ValidationError) {
throw new ReadError("Validation Error", err); throw new ReadError("Validation Error", err);
} else { } else {
throw err; throw err;
} }
*/!*
} }
} }
@ -271,8 +273,9 @@ try {
} }
``` ```
The approach is called "wrapping exceptions", because we take "low level exceptions" and "wrap" them into `ReadError` that is more abstract and more convenient to use for the calling code. In the code above, `readUser` does exactly as described -- catches syntax and validation errors and throws `ReadError` errors instead (unknown errors are rethrown as usual).
The approach is called "wrapping exceptions", because we take "low level exceptions" and "wrap" them into `ReadError` that is more abstract and more convenient to use for the calling code. It is widely used in object-oriented programming.
## Summary ## Summary

View file

@ -0,0 +1,104 @@
# Browser environment, specs
The Javascript language was born for web browsers. But as of now, it evolved and became a language with many use cases, not tied to browsers.
The Javascript standard though assumes that the execution happens in a *host environment*, say Node.JS server, or a web-browser.
That host environment may provide additional objects and functions though. Web browsers provide means to control web pages. Node.JS provides server-side features. There are other host environments too.
[cut]
Here's a bird-eye view of what we have when Javascript runs in a web-browser:
![](windowObjects.png)
On the top, there's `window` -- the object has two meanings:
1. First, it is a [global object](info:global-object) in terms of Javascript.
2. Second, it represents the "browser window" object, supports methods to control it and read its parameters.
For instance, to see the window height:
```js run
alert(window.innerHeight); // some number
```
Now we go from left to right.
## Document Object Model (DOM)
The `document` object gives access to a webpage contents. We can change or create literally anything.
For instance:
```js run
document.body.style.background = 'red';
alert('The <body> element became red! In 1 second it will become normal.');
setTimeout(() => document.body.style.background = '', 1000);
```
There are two working groups who develop the standard:
1. [W3C](https://en.wikipedia.org/wiki/World_Wide_Web_Consortium) -- the documentation is at <https://www.w3.org/TR/dom>.
2. [WhatWG](https://en.wikipedia.org/wiki/WHATWG), publishing at <https://dom.spec.whatwg.org>.
About 99.9% of time these two groups agree, so the actual documentation is almost the same. There are very minor differences that you shouldn't even notice that in practice.
I find <https://dom.spec.whatwg.org> more pleasant to use.
Historically, once there was no standard at all -- each browser did whatever it wanted. So different browsers had different methods and properties, and we had to find different code for each of them. Yeah, terrible, please don't remind.
Then the DOM standard appeared, in an attempt to bring them to an agreement. The first version is now called DOM Level 1. Then it was extended by DOM Level 2, new methods got added, then DOM Level 3, and now DOM Level 4.
People from WhatWG got tired of version and are calling that just "DOM", without a number. So will do we.
```smart header="DOM is not only for browsers"
The DOM specification explains the tree structure of a document and methods to manipulate it. There are non-browser instruments that use it as well. For instance, server-side tools that download HTML pages and process them. They may support only a part of the specification though.
```
```smart header="CSSOM for styling"
CSS styles and stylesheets are organized not like HTML. They form a standalone domain.
So there's a separate specification [CSSOM](https://www.w3.org/TR/cssom-1/) that explains how CSS styles and rules can be read and modified as objects, how to read and write them in the document.
If you're interested to read about general document structure, creating and modifying elements -- then it's DOM. But if it's about styles, then it's CSSOM.
```
## BOM (part of HTML spec)
Browser Object Model (BOM) are objects to work with anything except the document.
For instance:
- The [navigator](mdn:api/Window/navigator) object provides background information about the browser and the operation system. There are many properties, but two most widely known are: `navigator.userAgent` -- about the current browser, and `navigator.platform` -- about the platform (can help to differ between Windows/Linux/Mac etc).
- The [location](mdn:api/Window/location) object allows to read the current URL and redirect the browser to a new one.
- Functions `alert/confirm/prompt` -- are also a part of BOM, they are not related to "document".
- ...and so on.
Here's how we can use the `location`:
```js run
alert(location.href); // shows current URL
```
```smart header="HTML specification"
BOM is the part of the general [HTML specification](https://html.spec.whatwg.org).
Yes, right. The HTML spec at <https://html.spec.whatwg.org> covers not only the "HTML language" (tags, attributes), but also a bunch of objects, methods and browser-specific DOM extensions, including those listed above.
```
## Summary
So, talking about general standards, we have:
DOM specification
: Describes the document structure, manipulations and events, see <https://dom.spec.whatwg.org>.
CSSOM specification
: Describes styles, manipulations with them and their binding to documents, see <https://www.w3.org/TR/cssom-1/>.
HTML specification
: Describes HTML language and also BOM (browser object model) -- various browser functions: `setTimeout`, `alert`, `location` and so on, see <https://html.spec.whatwg.org>.
Now we'll get down to learning DOM, because the document plays the central role in the UI, and working with it is the most complex part.
Please note the links above, because there's so many stuff to learn, it's impossible to cover and remember everything. When you'd like to read about a property or a method -- can go <https://developer.mozilla.org/en-US/search>, but looking up the corresponding spec is even better. Longer to read, but will make your fundamental knowledge stronger.

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View file

@ -0,0 +1,20 @@
Выведет `null`, так как на момент выполнения скрипта тег `<body>` ещё не обработан браузером.
Попробуйте в действии:
```html run
<html>
<head>
<script>
alert( document.body ); // null
</script>
</head>
<body>
Привет, мир!
</body>
</html>
```

View file

@ -0,0 +1,26 @@
importance: 5
---
# Что выведет этот alert?
Что выведет `alert`?
```html
<html>
<head>
*!*
<script>
alert( document.body ); // ?
</script>
*/!*
</head>
<body>
Привет, мир!
</body>
</html>
```

View file

@ -0,0 +1,203 @@
libs:
- d3
- domtree
---
# DOM tree
When we look at HTML we see nested tags, right? According to Document Object Model (DOM), every HTML-tag is an object. Nested tags are his "children". And the text inside it is an object as well. All these objects are accessible using Javascript.
## An example of DOM
For instance, let's see the DOM tree for this document:
```html run no-beautify
<!DOCTYPE HTML>
<html>
<head>
<title>About elks</title>
</head>
<body>
The truth about elks.
</body>
</html>
```
Here's how it looks:
<div class="domtree"></div>
<script>
var node = {"name":"HTML","nodeType":1,"children":[{"name":"HEAD","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"\n "},{"name":"TITLE","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"About elks"}]},{"name":"#text","nodeType":3,"content":"\n "}]},{"name":"#text","nodeType":3,"content":"\n "},{"name":"BODY","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"\n The truth about elks."}]}]}
drawHtmlTree(node, 'div.domtree', 690, 300);
</script>
There are two types of tree nodes in the example:
1. Tags are called *element nodes* (or just elements). Naturally, nested tags become children of the enclosing ones. Because of that we have a tree.
2. The text inside elements forms *text nodes*, labelled as `#text`. A text node contains only a string. It may not have children and is always a leaf of the tree.
```online
**On the picture above element nodes you can click on element nodes. Their children will open/collapse.**
```
Please note the special characters in text nodes:
- a newline: `↵` (in Javascript known as `\n`)
- a space: `␣`
**Spaces and newlines -- are all valid characters, they form text nodes and become a part of the DOM.**
For instance, in the example above `<html>` contains not only elements `<head>` and `<body>`, but also the `#text` (spaces, line breaks) between them.
However, on the topmost level there are exclusions of that rule: spaces and newlines before `<head>` are ignored for historical reasons, and if we put something after `</body>`, then it is considered a malformed HTML, and that text is moved inside the `body`, at the end (there may be nothing after the `body`).
In other cases everything's honest -- if there are spaces (just like any character) in the document, then they text nodes in DOM, and if we remove them, then there won't be any in DOM, like here:
```html no-beautify
<!DOCTYPE HTML>
<html><head><title>About elks</title></head><body>The truth about elks.</body></html>
```
<div class="domtree"></div>
<script>
var node = {"name":"HTML","nodeType":1,"children":[{"name":"HEAD","nodeType":1,"children":[{"name":"TITLE","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"About elks"}]}]},{"name":"BODY","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"The truth about elks."}]}]}
drawHtmlTree(node, 'div.domtree', 690, 210);
</script>
```smart
From here on, spaces and line-breaks on DOM pictures will only be shown for "space-only" nodes that have no other text.
```
## Autocorrection
If the browser encounters malformed HTML, it automatically corrects it when making DOM.
For instance, the top tag is always `<html>`. Even if it doesn't exist in the document -- it will be in DOM, the browser will create it. The same about `<body>`.
Like, if the HTML file is a single word `"Hello"`, the browser will wrap it into `<html>` and `<body>`.
**While generating DOM, browser automatically processes errors in the document, closes tags and so on.**
Such a document:
```html no-beautify
<p>Hello
<li>Mom
<li>and
<li>Dad
```
...Will make a respectable DOM, as the browser knows how to read tags (from the spec):
<div class="domtree"></div>
<script>
var node = {"name":"HTML","nodeType":1,"children":[{"name":"HEAD","nodeType":1,"children":[]},{"name":"BODY","nodeType":1,"children":[{"name":"P","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"Hello"}]},{"name":"LI","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"Mom"}]},{"name":"LI","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"and"}]},{"name":"LI","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"Dad"}]}]}]}
drawHtmlTree(node, 'div.domtree', 690, 400);
</script>
````warn header="Tables always have `<tbody>`"
An interesting "special case" is tables. By the DOM specification they must have `<tbody>`, but HTML text may omit it. Then the browser creates `<tbody>` on it's own.
For the HTML:
```html no-beautify
<table id="table"><tr><td>1</td></tr></table>
```
DOM-structure will be:
<div class="domtree"></div>
<script>
var node = {"name":"TABLE","nodeType":1,"children":[{"name":"TBODY","nodeType":1,"children":[{"name":"TR","nodeType":1,"children":[{"name":"TD","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"1"}]}]}]}]};
drawHtmlTree(node, 'div.domtree', 600, 200);
</script>
Do you see? The `<tbody>` has appeared out of nowhere. Should keep in mind while working with tables to evade surprises.
````
## Other node types
Let's add more tags and a comment to the page:
```html
<!DOCTYPE HTML>
<html>
<body>
The truth about elks.
<ol>
<li>An elk is a smart</li>
*!*
<!-- comment -->
*/!*
<li>...and cunning animal!</li>
</ol>
</body>
</html>
```
<div class="domtree"></div>
<script>
var node = {"name":"HTML","nodeType":1,"children":[{"name":"HEAD","nodeType":1,"children":[]},{"name":"BODY","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"\n The truth about elks.\n "},{"name":"OL","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"\n "},{"name":"LI","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"An elk is a smart"}]},{"name":"#text","nodeType":3,"content":"\n "},{"name":"#comment","nodeType":8,"content":"comment"},{"name":"#text","nodeType":3,"content":"\n "},{"name":"LI","nodeType":1,"children":[{"name":"#text","nodeType":3,"content":"...and cunning animal!"}]},{"name":"#text","nodeType":3,"content":"\n "}]},{"name":"#text","nodeType":3,"content":"\n \n"}]}]};
drawHtmlTree(node, 'div.domtree', 690, 500);
</script>
Here we see a new tree node type -- *comment node*.
We may think -- why a comment is added to the DOM? It doesn't affect the visual representation anyway. But there's a rule -- if something's in HTML, then it also must be in the DOM tree.
**Everything in HTML has its place in DOM.**
Even the `<!DOCTYPE...>` directive at the very beginning of HTML is also a DOM node. It's in the DOM tree right before `<html>`. The pictures above don't show that fact, because we are not going to touch that node, but it's there.
The `document` object that represents the whole document is, formally, a DOM node as well.
There are 12 node types. In practice we only work with 4 of them:
1. `document` -- the "entry point" into DOM.
2. element nodes -- HTML-tags, the tree building blocks.
3. text nodes -- they contain text.
4. comments -- sometimes we can put the information there, that won't be shown, but JS can read it from DOM.
If you want to explore how DOM changes with the document, please consider the [Live DOM Viewer](http://software.hixie.ch/utilities/js/live-dom-viewer/). Just type in/modify the document, and it will show up DOM at instant.
## Power of DOM
Why besides nice pictures do we need DOM? To manipulate the page -- read the information from HTML, create and modify elements.
The `<html>` node is accessible as `document.documentElement`, and `<body>` -- as `document.body`.
Then we can do something with the node.
Like changing the color:
```js run
document.body.style.background = 'yellow';
alert('The body is now yellow');
// return back in 3 seconds
setTimeout(() => document.body.style.background = '', 3000);
```
...But actually much more.
In the next chapters we're going to learn it.
## Summary
- DOM-модель -- это внутреннее представление HTML-страницы в виде дерева.
- Все элементы страницы, включая теги, текст, комментарии, являются узлами DOM.
- У элементов DOM есть свойства и методы, которые позволяют изменять их.
- IE8- не генерирует пробельные узлы.
Кстати, DOM-модель используется не только в JavaScript, это известный способ представления XML-документов.
В следующих главах мы познакомимся с DOM более плотно.

3
2-ui/1-document/index.md Normal file
View file

@ -0,0 +1,3 @@
# Document and the web-page.
Here we'll learn to manipulate a web-page using Javascript.

3
2-ui/index.md Normal file
View file

@ -0,0 +1,3 @@
# Browser: Document, DOM, Interfaces (in progress)
Learning how to manage the browser page: add elements, manipulate their size and position, dynamically create interfaces and interact with the visitor.