0%

关于Javascript的笔记

这是以头抢地系列结束后的第一篇数学笔记.值得在概括栏里cue一下(嗯哼).

Morten’s incomplete guide to navigating the JavaScript landscape:
(在linkedin上的Morten老师对于一篮子JavaScript类语言的理解说明)

Start from the core of the JavaScript itself. Sometimes referred to as vanilla JavaScript or Vanilla JS.
Everything else is built on top of JavaScript itself.

The browser implementation specification for JavaScript is called ECMAScript, named after the European Computer Manufacturers Association, ECMA.
ECMAScript is not the language itself but the official description of how the language should be interpreted by browsers.

Then TypeScript, variation, dialect, or flavor of JavaScript introducing features like strong typing.

React, Vue, Angular are tools written in JavaScript, the JavaScript frameworks allowing us to write JavaScript-based front-end application.

Node.js, JavaScript server runtime used to run JavaScript everywhere; used to run npm, WebPack. Babel, and more on your computer.




LinkedIn的课推荐使用visual studio,于是就跟着下了,以及live server的插件,用于及时在浏览器上运行.ESLintPrettier用来Debug,这两个需要node.js.
Visual studio好牛逼啊…

1
Ctrl + `

打开terminal.在文件目录下npm install.

The Node package manager goes onto the internet, finds the dependencies necessary, pulls them into my computer through the internet and installs them in our current project.
In the project, will have a new folder called node module that contains all of the dependencies that were installed.

虽然不是很懂,大概是让eslint和prettier run起来的东西吧.

最后去file > preferences > settings > search formatsonsave.
Check Editor: Format On Save.
每次save file的时候,eslint和prettier会run.




Comment

1
2
3
4
// single line comment

/* multi-line comment
See! this line is also commented out*/

Shortcut in VS code:
/** + return -> add mutli-line comment
place cursor on the line/lines + ctrl + forward slash

Atom也可以,markdown里的comment默认的是html的.救命,学到了.
再来一次ctrl + forward slash可以恢复.

Spacing in JS is for human readability only. Browser does not care.
Semicolons in JS is for human readability. JS does not care.
胃开始疼了起来.
Double and single quotes are for string JS does not care, but be consistent.




1
<script src="script.js"></script>

在同个directory下如此link js file.
注意html代码是一行一行头从到尾编译的,所以如果link上js代码中有什么body tag里的东西,但body tag在script tag之后,就会出error,多加注意.




Modules

跟当年写C++的时候一样,js也可以把代码放在不同的文件(Module)里.

在script.js中加入.

1
import backpack from "./backpack.js";

backpack.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const updateBackpack = (update) => {
let main = document.querySelector("main");
main.innerHTML = markup(backpack);
console.info(update);
};

const backpack = {
name: "Everyday Backpack",
volume: 30,
color: "grey",
pocketNum: 15,
strapLength: {
left: 26,
right: 26,
},
lidOpen: false,
toggleLid: function (lidStatus) {
this.lidOpen = lidStatus;
updateBackpack(`Lid status changed.`);
},
newStrapLength: function (lengthLeft, lengthRight) {
this.strapLength.left = lengthLeft;
this.strapLength.right = lengthRight;
updateBackpack(`Strap lengths updated.`);
},
};

export default backpack;

In backpack file中我们define了一个constant叫做backpack and exported it tell browser this entity called backpack.

同时在html中:

1
2
<script type="module" src="backpack.js"></script>
<script type="module" src="script.js"></script>

虽然这里type叫module, script.js是main file,backpack是module.

在console里call backpack会not defined. Backpack object only available in context of script.js, not to the browser.
All imports need to happen at the top of the main file where it’s being used.
把class文件作为module比较make sense.因为在top会先运行,也会先declare,还不会被consule change.



1
2
3
4
5
6
const backpack = {// variable holds the data
name: "Everyday Backpack", // properties defined using key-value pairs
toggleLid: function(lidStatus){
this.lidOpen = lidStatus; // Methods are properties containing functions
}
};

有趣的事情是,我们assign backpack as constant.我们不能把它改成什么,number 5因为其constant特性,但是我们可以更改其中的properties.
Term上来说,在object内的叫method,在object外的叫function.



1
console.log(“Print backpack:", backpack); //用console log在print backpack object

除了点以外,方括号也可以access field.

1
2
console.log(“Print backpack:", backpack.pocketNum);
console.log(“Print backpack:", backpack["pocketNum"]);

是一样的.

1
2
var theField = "pocketNum"
console.log(“Print backpack:", backpack[theField]);

这样也行.当然点的方式这样不行.




Class

用来生成objects.
不如说JS竟然可以像上述所说先跳过class生成一个object好牛逼.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* Creating classes:
*
* Class declaration: class Name {}
* Class expression: const Name = class {}
*/

class Backpack {
constructor(
// Defines parameters:
name,
volume,
color,
pocketNum,
strapLengthL,
strapLengthR,
lidOpen
) {
// Define properties, constructor method:
this.name = name;
this.volume = volume;
this.color = color;
this.pocketNum = pocketNum;
this.strapLength = {
left: strapLengthL,
right: strapLengthR,
};
this.lidOpen = lidOpen;
}
// Add methods like normal functions:
toggleLid(lidStatus) {
this.lidOpen = lidStatus;
}
newStrapLength(lengthLeft, lengthRight) {
this.strapLength.left = lengthLeft;
this.strapLength.right = lengthRight;
}
}

const everydayPack = new Backpack(
"Everyday Backpack",
30,
"grey",
15,
26,
26,
false
);

For class, we need class keyword + capitalized name.

The old way of object constructor function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

function Backpack(
name,
volume,
color,
pocketNum,
strapLengthL,
strapLengthR,
lidOpen
) {
this.name = name;
this.volume = volume;
this.color = color;
this.pocketNum = pocketNum;
this.strapLength = {
left: strapLengthL,
right: strapLengthR,
};
this.lidOpen = lidOpen;
this.toggleLid = function (lidStatus) {
this.lidOpen = lidStatus;
};
this.newStrapLength = function (lengthLeft, lengthRight) {
this.strapLength.left = lengthLeft;
this.strapLength.right = lengthRight;
};
}

const everydayPack = new Backpack(
"Everyday Backpack",
30,
"grey",
15,
26,
26,
false
);

The methods live inside the main construction function like the properties do.
Class allows to do more inside of the constructors, recommend to use the previous one!




String output

When browser renders a document, it creates a document object model of that document. Then we can access that document object using JS.

所以我们access document object.
在script.js中更改.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const content = `
<main>
<article>
<h1>${everydayPack.name}</h1>
<ul>
<li>Volume: ${everydayPack.volume}</li>
<li>Color: ${everydayPack.color}</li>
<li>Age: ${everydayPack.backpackAge()}</li>
<li>Number of pockets: ${everydayPack.pocketNum}</li>
<li>Left strap length: ${everydayPack.strapLength.left}</li>
<li>Right strap length: ${everydayPack.strapLength.right}</li>
<li>Lid status: ${everydayPack.lidOpen}</li>
</ul>
</article>
</main>
`;

document.body.innerHTML = content;

Back ticks tell the browser that anything inside here is a template literal meaning we can mix HTML and string with JS expressions to literally create templates.
这是一个template literal, anything you want to call in something generated by JS, we add placeholder.



我觉得template literal很牛逼很方便,以下是老式method:

1
2
3
const content = "<h1>" + everydayPack.name + "</h1>";

document.body.innerHTML = content;

使用string catenation.




DOM(document object model)

return DOM object

querySelector function will return a DOM object.是新的function.

类似的老function还有getElementById() -> return single element.
和getElementsByClassName() -> return an array-like object of all the nodes or child elements matching the query. The query is string of space separated class names.
得iterate through the array,比较麻烦.

1
document.querySelector("main");

选取document的main element.

1
document.querySelector(".maincontent");

选取document里一个名为”.maincontent”的class.
querySelector可以选择任何的css elements.




modify class

Old one: className
It’s avaiable for all elements in the dom. Class name holds a string, listing out all the classes appended to an element.

1
document.querySelector("h1").className

If you have an element with several classes, you can’t replace the classes with a new class, because that way you’re wiping out all the classes.
In React and other JS frameworks, the term class name is used in place of class in markup to avoid collisions with the JS class keyword which is used to set up classes.
We should not using class name property in frameworks lol.

We will use the class list property.
The class list property gives us a Dom token collection of all the classes appended to an element. <-就是一个array of things in that class.

1
2
3
4
5
document.querySelector("h1").classList

//还能modify
document.querySelector("h1").classList.add("new class")
document.querySelector("h1").classList.remove("new class")



Attribute

Does the attribute exist on this particular element.

1
document.querySelector("img").hasAttribute("src")
1
2
3
4
document.querySelector("img").getAttribute("src")//查看

document.querySelector("img").setAttribute("alt","A drawing of the backpack")
document.querySelector("img").removeAttribute("alt")

Everything inside the tag is considered an attribute.
If we target an element that has a class, the class will also show up as an attribute.




Inline

If an element has inline styles, meaning there are CSS declarations in the element itself, that inline CSS is stored in the style property of the elements and we can access it as a regular property.

1
document.querySelector(".site-title").style

会return一个CSSStyleDeclaration array.

1
document.querySelector(".site-title").color

可以access到array中的color这一项.

Btw we can’t have hyphens for property names.

Add DOM element

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* Add a navigation section to the DOM
*/
const navContent = `
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Backpacks</a></li>
<li><a href="#">Other things</a></li>
<li><a href="#">Contact</a></li>
`;

//create nav element
const mainNav = document.createElement("nav")
//add to page
mainNav.classList.add("main-navigation");
const navList = document.createElement("ul")
navList.innerHTML = navContent
//append ul emelent
mainNav.append(navList)

document.querySelector(".siteheader").append(mainNav)



Event

Event通过event listener detect.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const container = document.querySelector(".container");
const button = document.querySelector(".cta-button");
const posX = document.querySelector(".posX span");
const posY = document.querySelector(".posY span");

// Log when the button is clicked in the console.
button.addEventListener("click", () => {
button.classList.toggle("active");
console.log("Button was clicked!");
}, false);

// Update the x and y displays to show the current mouse position.
const mousePosition = (event) => {
posX.innerText = event.pageX;
posY.innerText = event.pageY;
};

window.addEventListener("mousemove", mousePosition, false);

// Change the color of the box when the mouse enters.
container.addEventListener(
"mouseenter",
() => {
container.classList.add("blue");
},
false
);

container.addEventListener(
"mouseleave",
() => {
container.classList.remove("blue");
},
false
);

Everything that happens in the browser is an event(这里的例子有click, mouseenter和mouseleave), can monitor any of those events by adding event listener. Event listeners can be appended to any element inside the window and inside the DOM, and you can trigger whatever function you want either using an anonymous function inside the event listener or by using a callback.

Eventlister:

target.addEventListener(target, callback [, options]);

第一个target: the event target object,可以是bottom之类的.
第二个target: 会触发的event,比如click.
options基本为空.

1
2
3
4
5
6
7
8
9
10
11
const button = backpackArticle.querySelector(".lid-toggle") //选中button
const status = backpackArticle.querySelector(".backpack__lid span")

//对button增加event
button.addEventListener("click", (event) => {
console.log(event)
status.innerText === "open" ? status.innerText = "closed" : status.innerText = "open"
})

return backpackArticle;
});



Variable

var为variable.是default for all variable, the default if we forget to say that we are creating a new variable.

something = 7

这时候something是var.

var x = 4, y = 5, z =”blue”

也可以打包define多个variable.
var是globally scoped variable.
如果要避免globally scoped,可以使用let.
let是block scoped local variable.
If we wanna call the locally scoped variable outside its scope, JS stops rendering at this point, and in console it will output error.

For most situations, when you want to use a changeable or mutable variable, you should use let. That includes when you want to use it in global scope. When you declare a let in global scope, it will apply everywhere except where you re-declare it.
The var is only really useful if you want a mutable variable with global scope all the time.

const key word fines a block-scoped constant.
We cant put new stuff in the const box, but we can change status or properties or other features of what the constant holds.
We can change the properties inside of an object inside a const, the entries in an array inside a const, but cant reassign the whole constant to replace the object with another object or the array with another array or an object with an array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

// String:
let stringDemo = "A string of text.";
console.log("String:", stringDemo);

// Numbes:
let integerDemo = 4;
console.log("Integer:", integerDemo);

let floatDemo = 5.6;
console.log("Floating point number:", floatDemo);

// Boolean:
let booleanDemo = true;
console.log("Boolean value:", booleanDemo);

// Null value (nothing):
let nullDemo = null;
console.log("Null value:", nullDemo);

// Undefined:
let undefinedDemo;
console.log("Undefined:", undefinedDemo);

let undefinedAssignedDemo = undefined;
console.log("Undefined assigned:", undefinedAssignedDemo);

// Object:
const objectDemo = {
dance: "Mambo",
number: 5,
};
console.log("Object:", objectDemo);

// Array:
const arrayDemo = ["tango", "foxtrot", "waltz", "rumba", "bolero"];
console.log("Array:", arrayDemo);

因为JS的type全靠缘(不是),可以使用typeof function来判定.

console.log(“Undefined:”, typeof undefinedDemo);



1
2
3
4
5
6
7
8
9
10
11
let a = 5;
let b = 4;

console.log(`let a: ${a} (${typeof a})`);
console.log(`let b: ${b} (${typeof b})`);

if (a == b) {
console.log(`Match! let a and let b are the same value.`);
} else {
console.error(`No match: let a and let b are NOT same value.`);
}

这里比较有意思(胃疼)的是,==是loose comparsion.如果a为5,b为“5”-> string.
还是会match.

1
2
3
4
5
if (a === b) {
console.log(`Match! let a and let b are the same value.`);
} else {
console.error(`No match: let a and let b are NOT same value.`);
}

但这样就会让type也比较!




Array

Array跟C++见过的很像.

  1. Index从0开始.
  2. 有各种build in function.
  3. 但是是dynamic的.

Built-in function

有pop,return并去除最后一个item.

shift,return并去除第一个item. Unshift,add item to the first one in the array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const deskArray = [
"pen",
"camera",
"phone",
"notebook",
"headphones",
"lightbulb",
"usb drive",
];
console.log("Original array:", deskArray);

// Remove the last item:
// @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop
// deskArray.pop();
// console.log("New array:", deskArray);

// Add last item as the first item on the array:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift
// deskArray.unshift(deskArray.pop());
// console.log("Last item is now first:", deskArray);

Sort, find 和splice(这个倒是第一次见).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Sort items by alphabetical order:
// @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
// deskArray.sort();
// console.log("Sorted array:", deskArray);

// Find "notebook":
// @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
// const foundItem = deskArray.find((item) => item === "notebook");
// console.log("Found item:", foundItem);

// Find and remove an item:
// @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
// @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
// let remove = "notebook";
// deskArray.splice(deskArray.indexOf(remove), 1);
// console.log(`Array with "${remove}" removed:`, deskArray);


但是dynamic

1
2
3
4
5
let item = "flashlight";

const collection = ["Piggy", item, 5, true];

console.log(collection);

Array跟其他JS object一样很混乱邪恶.最初define的时候并不需要(也不能)定义array的data type和length.

1
collection[collection.length] = "new item";

可以通过直接access未并定义的index来add new item.

1
collection[9] = "another new item";

如果assign一个比长度长很多的slot.
那前面空出来的,会被自动sign to empty.




Function

Function declaration

1
2
3
4
5
// Function declaration:
function doSomeMath(a, b) {
let c = a + b;
return c;
}

Function declaration是global scope的,在local scope define也会global scope.
还算advanced variable,可以被re-declared.
Function declarations are parsed, in the order they appear in the code. If you have a function B that relies on function A, you have to make sure function A is declared before function B in the code.




Function expression

1
2
3
4
5
// Function expression:
const doMoreMath = function (a = 3, b = 2) {
let c = a * b;
return c;
};

In a function expression, we set up a variable, in this case a constant, we give that constant a name and value set to anonymous function.
因为是variable,所以这个function也会有这个variable一样的same scope,用const也不会被re-declared.
Function expressions are not hoisted, they exist only in the scope they were created.
如果没有pass value也没有default value,会return NaN.




Immediately Invoked Function Expression

1
2
3
4
5
6
7
// Immediately Invoked Function Expression (IIFE)
(function () {
let a = 4;
let b = 6;
let c = doSomeMath(a, b);
console.log(`The sum of a and b is: ${c}`);
})();

In IIFE, we wrap an anonymous function or a name function inside parentheses, then we put place another set of parentheses outside.
The function will immediately run when browser encounters it.




Arrow function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//这里的currentPack是pass in value的指代,叫啥都行

const addPack = function (currentPack) {
const newArticle = document.createElement("article");
newArticle.innerHTML = `
<h1>${currentPack.name}</h1>
<ul>
<li>Volume: ${currentPack.volume}</li>
<li>Color: ${currentPack.color}</li>
<li>Number of pockets: ${currentPack.pocketNum}</li>
</ul>
`;
return newArticle;
};

// versus

const addPack = (currentPack) => {
const newArticle = document.createElement("article");
newArticle.innerHTML = `
<h1>${currentPack.name}</h1>
<ul>
<li>Volume: ${currentPack.volume}</li>
<li>Color: ${currentPack.color}</li>
<li>Number of pockets: ${currentPack.pocketNum}</li>
</ul>
`;
return newArticle;
};

Arrow function can only be called after they have been declared.
You can’t use arrow functions when declaring methods in an object.
In side an object you need to use proper anonymous function for declare method.

Arrow function可以变得非常混沌邪恶,建议不要用简洁版本的语法!!好好写码!!!




Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
window.volume = 20;

const greenPack = {
name: "Frog Pack",
color: "green",
volume: 8,
pocketNum: 3,
newVolume: function (volume) {
console.log("this.volume in the method:", this.volume);// 这里我们使用this来refer greenPack, output 5
this.volume = volume;//我们assign了pass进来的5
console.log("this.volume after update:", this.volume);
(function () {// 如果我们running a function inside of the method
console.log("this.volume in nested function:", this.volume);
})();//但是这里会output20,因为错误读取了window这个object
(() => {//但如果我们使用arrow function
console.log("this.volume in nested function:", this.volume);
})();//会output 5 again
},
};

console.log(greenPack.newVolume(5));

Arrow function versus regular function.

这里因为scope的不同.

If you use function declaration, the function declaration is hoisted to the global scope.

Arrow function does not have its own ‘this’, it does not know what ‘this’ means and it will refer to the closest available scope, which in this case is the object.
但是同理,我们不能用arrow function as method(function), 因为arrow function wouldn’t know what scope to use. Will refer back to global scope instead of the method scope.




Callback

我觉得有点像lamba,把function作为一个variable pass进另一个function.
在function expression中已经是存储成variable的,可以这样使用.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// Helper function to format currency numbers. Used by tipCalculator
const formatter = (locale = "en-US", currency = "USD", value) => {
let formattedValue = new Intl.NumberFormat(locale, {
style: "currency",
currency: currency,
}).format(value);

return formattedValue;
};

// Callback receives finalTip object, creates and outputs table on the DOM.
const printHTML = (finalTip) => {
const tipTable = document.createElement("table");
tipTable.innerHTML = `
<tr>
<td>Sum before tip:</td>
<td>${finalTip.sum}</td>
</tr>
<tr>
<td>Tip percentage:</td>
<td>${finalTip.percentage}</td>
</tr>
<tr>
<td>Tip:</td>
<td>${finalTip.tip}</td>
</tr>
<tr>
<td>Total:</td>
<td>${finalTip.total}</td>
</tr>
`;
document.querySelector("main").append(tipTable);
};

// Create a finalTip object with all the data. Send it to the printHTML callback.
const tipCalculator = (sum, percentage, locale, currency, printHTML) => {
let tip = sum * (percentage / 100);
let total = sum + tip;

const finalTip = {
sum: formatter(locale, currency, sum),
percentage: percentage + "%",
tip: formatter(locale, currency, tip),
total: formatter(locale, currency, total),
};

printHTML(finalTip);
};

tipCalculator(29.95, 18, "de-DE", "EUR", printHTML);




If else

普通版.

1
2
3
4
5
if (everydayPack.lidOpen === true){
console.log("Lid is open!");
} else {
console.log("Lid is closed :(");
}

出现了,C++出现过的语法.

1
everydayPack.lidOpen ? "open" : "closed"

Logical operator: &&是and, !=是不等于, ||是or. 跟C一样.

switch.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const usedStatus = () => {
let age = everydayPack.backpackAge();
age = 1095
let description;

switch (true) {
case age < 30:
description = "new"
break;
case age >= 30 && age < 365:
description = "lightly used"
break;
case age >= 365 && age < 1095:
description ="used"
break;
case age >= 1095:
description = "old"
break;
default:
console.log(`There is no description for ${age}.`)
}

console.log(`
Age: ${age} days
Status: ${description}
`);
};



Loop

For loop.

1
2
3
4
5
for (let i = 0; i < stuff.length; i++) {
let listItem = document.createElement("li");
listItem.innerHTML = stuff[i];
stuffList.append(listItem);
}



For…of loop and arrays.

1
2
3
4
5
for (const item of stuff) { //这里的item跟上面的i一样,是我们创造的variable的名字
let listItem = document.createElement("li");
listItem.innerHTML = item;
stuffList.append(listItem);
}



Foreach array method.

1
2
3
4
5
for (const item of stuff) {
let listItem = document.createElement("li");
listItem.innerHTML = item;
stuffList.append(listItem);
}



For…in loop and objects.

1
2
3
4
5
for (const singleObject in nestedObjects) {
let listItem = document.createElement("li");
listItem.innerHTML = `Name: ${nestedObjects[singleObject].name}`;
stuffList.append(listItem);
}



1
2
3
4
5
6
// map() through the stuff array to make a new stuffItems array.
const stuffItems = stuff.map((item) => {
let listItem = document.createElement("li");
listItem.innerHTML = item;
return listItem;
});

Map is for creating a new array to do something further with the data.
If just wanna iterate through an array, use a foreach loop.
其实效果都一样.




Addition files

Links from JavaScript Essential Training with Morten Rand-Hendriksen

Chapter 1. JavaScript: A Brief Introduction



Chapter 2. Up and Running with JavaScript



Chapter 3. Objects



Chapter 4. Sidebar: String Output



Chapter 5. DOM



Chapter 6. Sidebar: Variables and Data Types



Chapter 7. Arrays



Chapter 8. Functions and Methods



Chapter 9. Events



Chapter 10. Advanced Things