- nodejs的原型链污染和xss都要js的知识,学之前先看看js基础,学完感觉重点是DOM和BOM
基本语法
-
每句结束要打分号
-
script标签中可以插入代码
<script>
alert("我的第一个 JavaScript");
</script>
- 脚本可位于 HTML 的 \
<!DOCTYPE html>
<html>
<head>
<script>
function myFunction()
{
document.getElementById("demo").innerHTML="我的第一个 JavaScript 函数";
}
</script>
</head>
<body>
<h1>我的 Web 页面</h1>
<p id="demo">一个段落</p>
<button type="button" onclick="myFunction()">尝试一下</button>
</body>
</html>
- 脚本可位于 HTML 的 \
<!DOCTYPE html>
<html>
<body>
<h1>我的 Web 页面</h1>
<p id="demo">一个段落</p>
<button type="button" onclick="myFunction()">尝试一下</button>
<script>
function myFunction()
{
document.getElementById("demo").innerHTML="我的第一个 JavaScript 函数";
}
</script>
</body>
</html>
- 可位于外部
<!DOCTYPE html>
<html>
<body>
<script src="myScript.js"></script>
</body>
</html>
- 一些关键字与作用
break 用于跳出循环。
catch 语句块,在 try 语句块执行出错时执行 catch 语句块。
continue 跳过循环中的一个迭代。
do ... while 执行一个语句块,在条件语句为 true 时继续执行该语句块。
for 在条件语句为 true 时,可以将代码块执行指定的次数。
for ... in 用于遍历数组或者对象的属性(对数组或者对象的属性进行循环操作)。
function 定义一个函数
if ... else 用于基于不同的条件来执行不同的动作。
return 退出函数
switch 用于基于不同的条件来执行不同的动作。
throw 抛出(生成)错误 。
try 实现错误处理,与 catch 一同使用。
var 声明一个变量。
while 当条件语句为 true 时,执行语句块。
- 注释
单行注释以 // 开头。
本例用单行注释来解释代码:
// 输出标题:
document.getElementById("myH1").innerHTML="欢迎来到我的主页";
// 输出段落:
document.getElementById("myP").innerHTML="这是我的第一个段落。";
多行注释以 /* 开始,以 */ 结尾。
下面的例子使用多行注释来解释代码:
/*
下面的这些代码会输出
一个标题和一个段落
并将代表主页的开始
*/
document.getElementById("myH1").innerHTML="欢迎来到我的主页";
document.getElementById("myP").innerHTML="这是我的第一个段落。";
输出
-
JavaScript 可以通过不同的方式来输出数据:
-
使用 window.alert()弹出警告框。
<!DOCTYPE html>
<html>
<body>
<h1>我的第一个页面</h1>
<p>我的第一个段落。</p>
<script>
window.alert(5 + 6);
</script>
</body>
</html>
- 使用 innerHTML 写入到 HTML 元素。
如需从 JavaScript 访问某个 HTML 元素,您可以使用 document.getElementById(id) 方法
<!DOCTYPE html>
<html>
<body>
<h1>我的第一个 Web 页面</h1>
<p id="demo">我的第一个段落</p>
<script>
document.getElementById("demo").innerHTML = "段落已修改。";
</script>
</body>
</html>
- 使用 document.write() 方法将内容写到 HTML 文档中。这会覆盖所有内容
<!DOCTYPE html>
<html>
<body>
<h1>我的第一个 Web 页面</h1>
<p>我的第一个段落。</p>
<script>
document.write(Date());
</script>
</body>
</html>
变量与常量
- 当您向变量分配文本值时,应该用双引号或单引号包围这个值。当您向变量赋的值是数值时,不要使用引号。如果您用引号包围数值,该值会被作为文本来处理。
var pi=3.14;
var pi='3.14';
var person="John Doe";
var answer='Yes I am!';
-
值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol。引用数据类型(对象类型):对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)。
-
变量的数据类型可以使用 typeof 操作符来查看:
typeof "John" // 返回 string
typeof 3.14 // 返回 number
typeof false // 返回 boolean
typeof [1,2,3,4] // 返回 object
typeof {name:'John', age:34} // 返回 object
- JavaScript 只有一种数字类型。数字可以带小数点,也可以不带:
var x1=34.00; //使用小数点来写
var x2=34; //不使用小数点来写
选择
-
在 JavaScript 中,我们可使用以下条件语句:
-
if 语句 - 只有当指定条件为 true 时,使用该语句来执行代码
-
if...else 语句 - 当条件为 true 时执行代码,当条件为 false 时执行其他代码
-
if...else if....else 语句- 使用该语句来选择多个代码块之一来执行
-
switch 语句 - 使用该语句来选择多个代码块之一来执行
-
if语法
if (condition)
{
当条件为 true 时执行的代码
}
请使用小写的 if。使用大写字母(IF)会生成 JavaScript 错误!
- if else语法
if (condition)
{
当条件为 true 时执行的代码
}
else
{
当条件不为 true 时执行的代码
}
- if...else if...else 语法
if (condition1)
{
当条件 1 为 true 时执行的代码
}
else if (condition2)
{
当条件 2 为 true 时执行的代码
}
else
{
当条件 1 和 条件 2 都不为 true 时执行的代码
}
- JavaScript switch 语法
switch(n)
{
case 1:
执行代码块 1;
break;
case 2:
执行代码块 2;
break;
default:
与 case 1 和 case 2 不同时执行的代码;
}
工作原理:首先设置表达式 n(通常是一个变量)。随后表达式的值会与结构中的每个 case 的值做比较。如果存在匹配,则与该 case 关联的代码块会被执行。请使用 break 来阻止代码自动地向下一个 case 运行。
var d=new Date().getDay();
switch (d)
{
case 6:x="今天是星期六";
break;
case 0:x="今天是星期日";
break;
default:
x="期待周末";
}
document.getElementById("demo").innerHTML=x;
循环
- for循环
document.write(cars[0] + "<br>");
document.write(cars[1] + "<br>");
document.write(cars[2] + "<br>");
document.write(cars[3] + "<br>");
document.write(cars[4] + "<br>");
document.write(cars[5] + "<br>");
使用for循环
for (var i=0;i<cars.length;i++)
{
document.write(cars[i] + "<br>");
}
同时您还可以省略语句 1(比如在循环开始前已经设置了值时):
var i=2,len=cars.length;
for (; i<len; i++)
{
document.write(cars[i] + "<br>");
}
var i=0,len=cars.length;
for (; i<len; )
{
document.write(cars[i] + "<br>");
i++;
}
- JavaScript for/in 语句循环遍历对象的属性:
var person={fname:"Bill",lname:"Gates",age:56};
for (x in person) // x 为属性名
{
txt=txt + person[x];
}
- while
while (i<5)
{
x=x + "The number is " + i + "<br>";
i++;
}
do/while 循环是 while 循环的变体。该循环会在检查条件是否为真之前执行一次代码块,然后如果条件为真的话,就会重复这个循环。
do
{
x=x + "The number is " + i + "<br>";
i++;
}
while (i<5);
cars=["BMW","Volvo","Saab","Ford"];
var i=0;
while (cars[i])
{
document.write(cars[i] + "<br>");
i++;
}
- break 语句可用于跳出循环。
for (i=0;i<10;i++)
{
if (i==3)
{
break;
}
x=x + "The number is " + i + "<br>";
}
while (i < 10){
if (i == 3){
i++; //加入i++不会进入死循环
continue;
}
x= x + "该数字为 " + i + "<br>";
i++;
}
数组
- 下面的代码创建名为 cars 的数组:
var cars=new Array();
cars[0]="Saab";
cars[1]="Volvo";
cars[2]="BMW";
或者 (condensed array):
var cars=new Array("Saab","Volvo","BMW");
或者 (literal array):
var cars=["Saab","Volvo","BMW"];
函数
function myFunction(a, b) {
return a * b;
}
- 函数表达式可以存储在变量中
var x = function (a, b) {return a * b};
var z = x(4, 3);
- 函数同样可以通过内置的 JavaScript 函数构造器(Function())定义
var myFunction = new Function("a", "b", "return a * b");
var x = myFunction(4, 3);
- 提升(Hoisting)是 JavaScript 默认将当前作用域提升到前面去的行为。所以可以先调用函数再声明
myFunction(5);
function myFunction(y) {
return y * y;
}
- 函数是对象,arguments.length 属性返回函数调用过程接收到的参数个数
function myFunction(a, b) {
return arguments.length;
}
- toString() 方法将函数作为一个字符串返回
function myFunction(a, b) {
return a * b;
}
var txt = myFunction.toString();
得到:
function myFunction(a, b) { return a * b; }
- 如果函数在调用时未提供隐式参数,参数会默认设置为: undefined
function myFunction(x, y) {
if (y === undefined) {
y = 0;
}
}
或者
function myFunction(x, y) {
y = y || 0;
}
- ES6 支持函数带有默认参数,就判断 undefined 和 || 的操作
function myFunction(x, y = 10) {
// y is 10 if not passed or undefined
return x + y;
}
myFunction(0, 2) // 输出 2
myFunction(5); // 输出 15, y 参数的默认值
- JavaScript 函数有个内置的对象 arguments 对象。arguments 对象包含了函数调用的参数数组。
x = findMax(1, 123, 500, 115, 44, 88);
function findMax() {
var i, max = arguments[0];
if(arguments.length < 2) return max;
for (i = 0; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
- 以上函数不属于任何对象。但是在 JavaScript 中它始终是默认的全局对象。在 HTML 中默认的全局对象是 HTML 页面本身,所以函数是属于 HTML 页面。
function myFunction(a, b) {
return a * b;
}
window.myFunction(10, 2);
- call() 和 apply() 是预定义的函数方法。 两个方法可用于调用函数,两个方法的第一个参数必须是对象本身。
function myFunction(a, b) {
return a * b;
}
myObject = myFunction.call(myObject, 10, 2); // 返回 20
function myFunction(a, b) {
return a * b;
}
myArray = [10, 2];
myObject = myFunction.apply(myObject, myArray); // 返回 20
- 所有函数都能访问全局变量。 所有函数都能访问它们上一层的作用域。嵌套函数可以访问上一层的函数变量。该实例中,内嵌函数 plus() 可以访问父函数的 counter 变量:
function add() {
var counter = 0;
function plus() {counter += 1;}
plus();
return counter;
}
类
- 构造函数
class Runoob {
constructor(name, url) {
this.name = name;
this.url = url;
}
}
- new关键字
class Runoob {
constructor(name, url) {
this.name = name;
this.url = url;
}
}
let site = new Runoob("菜鸟教程", "https://www.runoob.com");
-
函数声明和类声明之间的一个重要区别在于, 函数声明会提升,类声明不会。
-
继承,和java差不多
class Site {
constructor(name) {
this.sitename = name;
}
present() {
return '我喜欢' + this.sitename;
}
}
class Runoob extends Site {
constructor(name, age) {
super(name);
this.age = age;
}
show() {
return this.present() + ', 它创建了 ' + this.age + ' 年。';
}
}
let noob = new Runoob("菜鸟教程", 5);
document.getElementById("demo").innerHTML = noob.show();
- 类中我们可以使用 getter 和 setter 来获取和设置值,以下实例为 sitename 属性创建 getter 和 setter, sitename不用声明
class Runoob {
constructor(name) {
this.sitename = name;
}
get s_name() {
return this.sitename;
}
set s_name(x) {
this.sitename = x;
}
}
let noob = new Runoob("菜鸟教程");
document.getElementById("demo").innerHTML = noob.s_name;
get或set的函数名无关紧要,主要是看return的值,也可以写作
class Runoob {
constructor(name) {
this._sitename = name;
}
get sitename() {
return this._sitename;
}
set sitename(x) {
this._sitename = x;
}
}
let noob = new Runoob("菜鸟教程");
document.getElementById("demo").innerHTML = noob.sitename;
要使用 setter,请使用与设置属性值时相同的语法,虽然 set 是一个方法,但需要不带括号
class Runoob {
constructor(name) {
this._sitename = name;
}
set sitename(x) {
this._sitename = x;
}
get sitename() {
return this._sitename;
}
}
let noob = new Runoob("菜鸟教程");
noob.sitename = "RUNOOB";
document.getElementById("demo").innerHTML = noob.sitename;
- js也有静态方法,加static关键字即可,不过感觉只是为了兼容其他语言,没啥用
class Runoob {
constructor(name) {
this.name = name;
}
static hello() {
return "Hello!!";
}
}
let noob = new Runoob("菜鸟教程");
// 可以在类中调用 'hello()' 方法
document.getElementById("demo").innerHTML = Runoob.hello();
// 不能通过实例化后的对象调用静态方法
// document.getElementById("demo").innerHTML = noob.hello();
// 以上代码会报错
DOM
- 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model),大概就是根据不同的html标签生成了一个树状结构,依次渲染
- js可以对DOM进行许多操作
JavaScript 能够改变页面中的所有 HTML 元素
JavaScript 能够改变页面中的所有 HTML 属性
JavaScript 能够改变页面中的所有 CSS 样式
JavaScript 能够对页面中的所有事件做出反应
查找html元素
- 通过 id 找到 HTML 元素
var x=document.getElementById("intro");
- 通过标签名查找 HTML 元素
var x=document.getElementById("main");
var y=x.getElementsByTagName("p");//查找所有<p>标签
- 通过类名找到 HTML 元素
var x=document.getElementsByClassName("intro");//查找 class="intro" 的元素
改变html内容
- document.write(),这将覆盖函数前面生成的所有页面
<!DOCTYPE html>
<html>
<body>
<script>
document.write(Date());
</script>
</body>
</html>
- innerHTML 属性
<html>
<body>
<p id="p1">Hello World!</p>
<script>
document.getElementById("p1").innerHTML="新文本!";
</script>
</body>
</html>
/*
间接写也可以
<script>
var element=document.getElementById("p1");
element.innerHTML="新文本";
</script>
*/
- 直接使用.来调用标签的属性值
<!DOCTYPE html>
<html>
<body>
<img id="image" src="smiley.gif">
<script>
document.getElementById("image").src="landscape.jpg";
</script>
</body>
</html>
改变css
- .style来调用css的属性值
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<p id="p1">Hello World!</p>
<p id="p2">Hello World!</p>
<script>
document.getElementById("p2").style.color="blue";
document.getElementById("p2").style.fontFamily="Arial";
document.getElementById("p2").style.fontSize="larger";
</script>
<p>以上段落通过脚本修改。</p>
</body>
</html>
DOM事件
- 我们可以在事件发生时执行 JavaScript,比如当用户在 HTML 元素上点击时.有以下事件
onload 和 onunload 事件会在用户进入或离开页面时被触发。
onload 事件可用于检测访问者的浏览器类型和浏览器版本,并基于这些信息来加载网页的正确版本。
onload 和 onunload 事件可用于处理 cookie。
onchange 事件常结合对输入字段的验证来使用。
onmouseover 和 onmouseout 事件可用于在用户的鼠标移至 HTML 元素上方或移出元素时触发函数
onmousedown, onmouseup 以及 onclick 构成了鼠标点击事件的所有部分。
首先当点击鼠标按钮时,会触发 onmousedown 事件,当释放鼠标按钮时,会触发 onmouseup 事件
最后,当完成鼠标点击时,会触发 onclick 事件。
监听器
- addEventListener() 方法用于向指定元素添加事件句柄。addEventListener() 方法添加的事件句柄不会覆盖已存在的事件句柄。
element.addEventListener(event, function, useCapture);
第一个参数是事件的类型 (如 "click" 或 "mousedown").
第二个参数是事件触发后调用的函数。
第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的。
element.addEventListener("click", function(){ alert("Hello World!"); });
或者
element.addEventListener("click", myFunction);
function myFunction() {
alert ("Hello World!");
}
-
可以监听的事件有一堆,贴个链接https://www.runoob.com/jsref/dom-obj-event.html
-
removeEventListener() 方法移除由 addEventListener() 方法添加的事件句柄
element.removeEventListener("mousemove", myFunction);
DOM元素操作
- 要创建新的 HTML 元素 (节点)需要先创建一个元素,然后在已存在的元素中添加它。appendChild() 方法,它用于添加新元素到尾部
<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另外一个段落。</p>
</div>
<script>
var para = document.createElement("p");
var node = document.createTextNode("这是一个新的段落。");
para.appendChild(node);//给创建的p标签添加了属性值
var element = document.getElementById("div1");
element.appendChild(para);//给element的div标签末尾添加了创建的p标签
</script>
- 将新元素添加到开始位置,可以使用 insertBefore() 方法
<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另外一个段落。</p>
</div>
<script>
var para = document.createElement("p");
var node = document.createTextNode("这是一个新的段落。");
para.appendChild(node);
var element = document.getElementById("div1");
var child = document.getElementById("p1");
element.insertBefore(para, child);
</script>
- 要移除一个元素,你需要知道该元素的父元素。
<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另外一个段落。</p>
</div>
<script>
var parent = document.getElementById("div1");
var child = document.getElementById("p1");
parent.removeChild(child);//只能向上级元素发送删除下级元素的请求
</script>
- 我们可以使用 replaceChild() 方法来替换 HTML DOM 中的元素
<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另外一个段落。</p>
</div>
<script>
var para = document.createElement("p");
var node = document.createTextNode("这是一个新的段落。");
para.appendChild(node);//生成新的p标签
var parent = document.getElementById("div1");
var child = document.getElementById("p1");
parent.replaceChild(para, child);//向上级标签发送替换请求
</script>
BOM
计时器
- setInterval() - 间隔指定的毫秒数不停地执行指定的代码
window.setInterval("javascript function",milliseconds);
var myVar=setInterval(function(){myTimer()},1000);
function myTimer()
{
var d=new Date();
var t=d.toLocaleTimeString();
document.getElementById("demo").innerHTML=t;
}
- clearInterval() 方法用于停止 setInterval() 方法执行的函数代码,window.clearInterval() 方法可以不使用window前缀,直接使用函数clearInterval(),要使用 clearInterval() 方法, 在创建计时方法时你必须使用全局变量
<p id="demo"></p>
<button onclick="myStopFunction()">停止</button>
<script>
var myVar=setInterval(function(){myTimer()},1000);
function myTimer(){
var d=new Date();
var t=d.toLocaleTimeString();
document.getElementById("demo").innerHTML=t;
}
function myStopFunction(){
clearInterval(myVar);
}
</script>
- setTimeout() - 在指定的毫秒数后执行指定代码
setTimeout(function(){alert("Hello")},3000);
- clearTimeout() 方法用于停止执行setTimeout()方法的函数代码。window.clearTimeout() 方法可以不使用window 前缀。要使用clearTimeout() 方法, 你必须在创建超时方法中(setTimeout)使用全局变量
var myVar;
function myFunction()
{
myVar=setTimeout(function(){alert("Hello")},3000);
}
function myStopFunction()
{
clearTimeout(myVar);
}
访问信息
- window.navigator 对象包含有关访问者浏览器的信息
<script>
txt = "<p>浏览器代号: " + navigator.appCodeName + "</p>";
txt+= "<p>浏览器名称: " + navigator.appName + "</p>";
txt+= "<p>浏览器版本: " + navigator.appVersion + "</p>";
txt+= "<p>启用Cookies: " + navigator.cookieEnabled + "</p>";
txt+= "<p>硬件平台: " + navigator.platform + "</p>";
txt+= "<p>用户代理: " + navigator.userAgent + "</p>";
txt+= "<p>用户代理语言: " + navigator.language + "</p>";
document.getElementById("example").innerHTML=txt;
</script>
Window 对象
- 获取浏览器长宽
var w=window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
var h=window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;
-
window.open() - 打开新窗口
-
window.close() - 关闭当前窗口
-
window.moveTo() - 移动当前窗口
-
window.resizeTo() - 调整当前窗口的尺寸
-
screen.availWidth - 可用的屏幕宽度
-
screen.availHeight - 可用的屏幕高度
弹窗
- window.alert() 方法可以不带上window对象,直接使用alert()方法
window.alert("sometext");
- window.confirm() 方法可以不带上window对象,直接使用confirm()方法
var r=confirm("按下按钮");
if (r==true)
{
x="你按下了\"确定\"按钮!";
}
else
{
x="你按下了\"取消\"按钮!";
}
- window.prompt() 方法可以不带上window对象,直接使用prompt()方法
var person=prompt("请输入你的名字","Harry Potter");//Harry Potter是默认值
if (person!=null && person!="")
{
x="你好 " + person + "! 今天感觉如何?";
document.getElementById("demo").innerHTML=x;
}
Window 地址
-
location.hostname 返回 web 主机的域名
-
location.pathname 返回当前页面的路径和文件名
-
location.port 返回 web 主机的端口 (80 或 443)
-
location.protocol 返回所使用的 web 协议(http: 或 https:)
-
location.assign() 方法加载新的文档。相当于跳转
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<script>
function newDoc(){
window.location.assign("https://www.runoob.com")
}
</script>
</head>
<body>
<input type="button" value="加载新文档" onclick="newDoc()">
</body>
</html>
历史记录
- history.back() - 与在浏览器点击后退按钮相同
- history.forward() - 与在浏览器中点击向前按钮相同
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
function goForward()
{
window.history.forward()
}
</script>
</head>
<body>
<input type="button" value="Forward" onclick="goForward()">
</body>
</html>
- 除此之外可以用 history.go() 这个方法来实现向前,后退的功能。
function a(){
history.go(1); // go() 里面的参数表示跳转页面的个数 例如 history.go(1) 表示前进一个页面
}
function b(){
history.go(-1); // go() 里面的参数表示跳转页面的个数 例如 history.go(-1) 表示后退一个页面
}
function a(){
history.go(0); // go() 里面的参数为0,表示刷新页面
}
cookie
- JavaScript 可以使用 document.cookie 属性来创建 、读取、及删除 cookie。
- JavaScript 中,创建 cookie 如下所示:
document.cookie="username=John Doe";
- 您还可以为 cookie 添加一个过期时间(以 UTC 或 GMT 时间)。默认情况下,cookie 在浏览器关闭时删除:
document.cookie="username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT";
- 您可以使用 path 参数告诉浏览器 cookie 的路径。默认情况下,cookie 属于当前页面。
document.cookie="username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT; path=/";
- 在 JavaScript 中, 可以使用以下代码来读取 cookie:
var x = document.cookie;
-
在 JavaScript 中,修改 cookie 类似于创建 cookie,旧的 cookie 将被覆盖。
-
删除 cookie 非常简单。您只需要设置 expires 参数为以前的时间即可,如下所示,设置为 Thu, 01 Jan 1970 00:00:00 GMT:
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
- 最后贴一份在cookie中查某键值的js代码,改改就能用
function setCookie(cname,cvalue,exdays){
var d = new Date();
d.setTime(d.getTime()+(exdays*24*60*60*1000));
var expires = "expires="+d.toGMTString();
document.cookie = cname+"="+cvalue+"; "+expires;
}
function getCookie(cname){
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name)==0) { return c.substring(name.length,c.length); }
}
return "";
}
function checkCookie(){
var user=getCookie("username");
if (user!=""){
alert("欢迎 " + user + " 再次访问");
}
else {
user = prompt("请输入你的名字:","");
if (user!="" && user!=null){
setCookie("username",user,30);
}
}
}
==整理和cv自菜鸟教程JavaScript 教程 | 菜鸟教程 (runoob.com)==