JvaScript笔记

文中代码若无特别说明那么都是写在内的

基础

初识

JavaScript 可以通过不同的方式来输出数据:

  • 使用 window.alert() 弹出警告框来显示数据。
  • 使用 document.write() 方法将内容写到 HTML 文档中。
  • 使用 innerHTML 写入到 HTML 元素。
  • 使用 console.log() 写入到浏览器的控制台。

如需从 JavaScript 访问某个 HTML 元素,您可以使用 document.getElementById(id) 方法。

请使用 “id” 属性来标识 HTML 元素,并 innerHTML 来获取或插入元素内容:

1
2
3
<script>
document.getElementById("demo").innerHTML = "段落已修改。";
</script>

JavaScript 使用关键字 var 来定义变量, 使用等号来为变量赋值 var length;

变量的数据类型可以使用 typeof 操作符来查看

可以在字符串中使用引号,只要不匹配包围字符串的引号即可

单行注释://后面接内容

多行注释以 /* 开始,以 ***/** 结尾。

注释用于阻止其中一条代码行的执行(可用于调试)

break 用于跳出循环。
catch 语句块,在 try 语句块执行出错时执行 catch 语句块。
continue 跳过循环中的一个迭代。
do … while 执行一个语句块,在条件语句为 true 时继续执行该语句块。
for 在条件语句为 true 时,可以将代码块执行指定的次数。
for … in 用于遍历数组或者对象的属性(对数组或者对象的属性进行循环操作)。
function 定义一个函数
if … else 用于基于不同的条件来执行不同的动作。
return 退出函数
switch 用于基于不同的条件来执行不同的动作。
throw 抛出(生成)错误 。
try 实现错误处理,与 catch 一同使用。
var 声明一个变量。
while 当条件语句为 true 时,执行语句块。

代码将修改自身元素的内容 (使用 this.innerHTML):

1
<button onclick="this.innerHTML=Date()">现在的时间是?</button>

对象

对象属性有两种寻址方式

1
2
3
4
5
6
7
8
9
10
<script>
var person=
{
firstname : "John",
lastname : "Doe",
id : 5566
};
document.write(person.lastname + "<br>");
document.write(person["lastname"] + "<br>");
</script>

Undefined 这个值表示变量不含有值。

可以通过将变量的值设置为 null 来清空变量

当您声明新变量时,可以使用关键词 “new” 来声明其类型 var carname=new String;

作用域

在 JavaScript 中, 对象和函数同样也是变量。

在 JavaScript 中, 作用域为可访问变量,对象,函数的集合。

JavaScript 函数作用域: 作用域在函数内修改。

局部作用域

变量在函数内声明,变量为局部变量,具有局部作用域。

局部变量:只能在函数内部访问。

局部变量在函数开始执行时创建,函数执行完后局部变量会自动销毁。

全局变量

变量在函数外定义,即为全局变量。

全局变量有 全局作用域: 网页中所有脚本和函数均可使用。

如果变量在函数内没有声明(没有使用 var 关键字),该变量为全局变量。

1
2
3
4
5
// 此处可调用 carName 变量
function myFunction() {
carName = "Volvo";
// 此处可调用 carName 变量
}

事件

常见的HTML事件的列表:

事件 描述
onchange HTML 元素改变
onclick 用户点击 HTML 元素
onmouseover 鼠标指针移动到指定的元素上时发生
onmouseout 用户从一个 HTML 元素上移开鼠标时发生
onkeydown 用户按下键盘按键
onload 浏览器已完成页面的加载

字符串

可以使用内置属性 length 来计算字符串的长度

**match()**函数用来查找字符串中特定的字符,并且如果找到的话,则返回这个字符:document.write(str.match("world!"));

replace() 方法在字符串中用某些字符替换另一些字符:var txt = str.replace("Microsoft","Runoob");

在 JavaScript 中,字符串写在单引号或双引号中。

因为这样,以下实例 JavaScript 无法解析:"We are the so-called "Vikings" from the north."

字符串 “We are the so-called “ 被截断。

如何解决以上的问题呢?可以使用反斜杠 () 来转义 “Vikings” 字符串中的双引号,如下:

"We are the so-called \"Vikings\" from the north."

反斜杠是一个转义字符。 转义字符将特殊字符转换为字符串字符

' 单引号
" 双引号
\ 反斜杠
\n 换行
\r 回车
\t tab(制表符)
\b 退格符
\f 换页符

模板字符串

JavaScript 中的模板字符串是一种方便的字符串语法,允许你在字符串中嵌入表达式和变量。

模板字符串使用反引号 `` 作为字符串的定界符分隔的字面量。

模板字面量是用反引号(**`**)分隔的字面量,允许多行字符串、带嵌入表达式的字符串插值和一种叫带标签的模板的特殊结构。

语法

1
2
3
4
5
6
7
8
`string text`

`string text line 1
string text line 2`

`string text ${expression} string text`

tagFunction`string text ${expression} string text`

参数

  • string text:将成为模板字面量的一部分的字符串文本。几乎允许所有字符,包括换行符和其他空白字符。但是,除非使用了标签函数,否则无效的转义序列将导致语法错误。
  • expression:要插入当前位置的表达式,其值被转换为字符串或传递给 tagFunction。
  • tagFunction:如果指定,将使用模板字符串数组和替换表达式调用它,返回值将成为模板字面量的值。
1
2
3
4
<script>
let text=`Nice!`;
document.getElementById("demo").innerHTML=text;
</script>

(注意:变量名前面最好是 let或者 const

模板字符串支持同时使用单引号和双引号;支持多行文本而无需转义字符

若要转义模板字面量中的反引号(**`),需在反引号之前加一个反斜杠(**)。

1
`\`` === "`"; // true

模板字面量用反引号(**`)括起来,而不是双引号()或单引号(‘**)。

除了普通字符串外,模板字面量还可以包含占位符——一种由美元符号和大括号分隔的嵌入式表达式:**${expression}**。

字符串和占位符被传递给一个函数(要么是默认函数,要么是自定义函数)。默认函数(当未提供自定义函数时)只执行字符串插值来替换占位符,然后将这些部分拼接到一个字符串中。

模板字符串中允许我们使用变量

1
2
3
4
5
6
<script>
const name = 'Runoob';
const age = 30;
const message = `My name is ${name} and I'm ${age} years old.`;
document.getElementById("demo").innerHTML = message;
</script>

模板字符串中允许我们使用表达式

1
2
3
let price = 10;
let VAT = 0.25;
let total = `Total: ${(price * (1 + VAT)).toFixed(2)}`;

模板字符串当作 HTML 模板使用

1
2
3
4
5
6
7
8
let header = "";
let tags = ["RUNOOB", "GOOGLE", "TAOBAO"];

let html = `<h2>${header}</h2><ul>`;
for (const x of tags) {
html += `<li>${x}</li>`;
}
html += `</ul>`;

Date()对象

创建日期

参数大多数都是可选的,在不指定的情况下,默认参数是0。

1
2
3
4
new Date();  var today = new Date()
new Date(value); var d1 = new Date("October 13, 1975 11:13:00")
new Date(dateString); var d2 = new Date(79,5,24)
new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]]);var d3 = new Date(79,5,24,11,33,0)

设置日期

下面例子是设定一个特定的日期

1
2
var myDate=new Date();
myDate.setFullYear(2010,0,14);// 第二个参数为月份, 0 到 11 之间的整数值,表示从一月到十二月

这个例子是设成五天后的日期

1
2
var myDate=new Date();
myDate.setDate(myDate.getDate()+5);

如果增加天数会改变月份或者年份,那么日期对象会自动完成这种转换。

For/In循环

遍历对象的属性:

1
2
3
4
5
6
7
8
9
10
11
<script>
function myFunction(){
var x;
var txt="";
var person={fname:"Bill",lname:"Gates",age:56};
for (x in person){
txt=txt + person[x];
}
document.getElementById("demo").innerHTML=txt;
}
</script>

JavaScript 标签与 break 和 continue 一起使用的理解

如需标记 JavaScript 语句,请在语句之前加上冒号:lable:

break 和 continue 语句仅仅是能够跳出代码块的语句。语法如下:

1
2
break labelname;
continue labelname;

break 的作用是跳出代码块, 所以 break 可以使用于循环和 switch 等

continue 的作用是进入下一个迭代, 所以 continue 只能用于循环的代码块。

代码块: 基本上是{}大括号之间

然后:

  1. 默认标签的情况(除了默认标签情况,其他时候必须要有名标签,否则会有惊喜)

当 break 和 continue 同时用于循环时,没有加标签,此时默认标签为当前”循环”的代码块。

当 break 用于 switch 时,默认标签为当前的 switch 代码块:

有名标签的情况

1
2
3
4
5
6
7
8
9
10
11
cars=["BMW","Volvo","Saab","Ford"];
list:
{
document.write(cars[0] + "");
document.write(cars[1] + "");
document.write(cars[2] + "");
break list;
document.write(cars[3] + "");
document.write(cars[4] + "");
document.write(cars[5] + "");
}

上述break list;会跳出list的代码块。如果将break换成continue会有惊喜(会报错),违反了明确中的第二点,因为list只是个普通代码块,而不是循环。除非list写成如下形式 list:

1
2
3
4
for(var i=0; i<10; ++i)
{
continue list;
}

有了标签,可以使用break和continue在多层循环的时候控制外层循环。

例如下面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
outerloop:
for (var i = 0; i < 10; i++)
{
innerloop:
for (var j = 0; j < 10; j++)
{
if (j > 3)
{
break;
}
if (i == 2)
{
break innerloop;
}
if (i == 4)
{
break outerloop;
}
document.write("i=" + i + " j=" + j + "");
}
}

undefined与null

null 表示 “什么都没有”,是一个只有一个值的特殊类型。表示一个空对象引用。

undefined 是一个没有设置值的变量。typeof 一个没有值的变量会返回 undefined

1
2
3
4
typeof undefined    // undefined
typeof null         // object
null === undefined // false
null == undefined // true

两者值相等但是类型不相等

类型转换

Number() 转换为数字, String() 转换为字符串, Boolean() 转换为布尔值

6 种不同的数据类型:string,number,boolean,object,function,symbol

3 种对象类型:Object,Date,Array

2 个不包含任何值的数据类型:null,undefined

注意:使用typrof操作符不能判断是Array还是Date,因为它两返回的数据类型都是object

constructor属性

返回所有 JavaScript 变量的构造函数

1
2
3
4
5
6
7
"John".constructor                 // 返回函数 String()  { [native code] }
(3.14).constructor                 // 返回函数 Number()  { [native code] }
false.constructor                  // 返回函数 Boolean() { [native code] }
[1,2,3,4].constructor              // 返回函数 Array()   { [native code] }
{name:'John', age:34}.constructor  // 返回函数 Object()  { [native code] }
new Date().constructor             // 返回函数 Date()    { [native code] }
function () {}.constructor         // 返回函数 Function(){ [native code] }

查看对象是否为数组的方法

第一种:使用constructor属性来判断

1
2
3
4
5
var fruits=["banana","orange",'apple'];
document.getElementById("demo").innerHTML=checkArray(fruits);
function checkArray(Array){
return Array.constructor.toString().indexOf("Array")>-1;
}

return myArray.constructor.toString().indexOf("Array") > -1;:这行代码使用 constructor 属性获取传入数组的构造函数,将其转换为字符串,并检查字符串中是否包含 “Array”。如果包含,返回 true 表示是数组,否则返回 false 表示不是数组。

第二种:使用内置函数来判断(gpt告诉我的,更为简便)

Array.isArray() 方法,它是 JavaScript 的内建方法,专门用于检查一个对象是否是数组

1
document.getElementById("demo").innerHTML = Array.isArray(fruits);

查看对象是否为日期的方法

第一种同上

第二种使用 instanceof 关键字可以确定一个对象是否属于特定的构造函数

1
2
3
4
5
6
var myDate = new Date();
if (myDate instanceof Date) {
console.log('myDate 是一个 Date 对象');
} else {
console.log('myDate 不是一个 Date 对象');
}

其中的 console.log被用于输出字符串到控制台,具体取决于 myDate 对象是否是 Date 类型。如果是 Date 类型,将输出 'myDate 是一个 Date 对象',否则将输出 'myDate 不是一个 Date 对象'。(摁F12或者直接查看开发者工具)

日期转化为字符串(还有数字,布尔值转化成字符串的方法网上都可以找到,这里就不一一列举了)

getDate() 从 Date 对象返回一个月中的某一天 (1 ~ 31)。
getDay() 从 Date 对象返回一周中的某一天 (0 ~ 6)。
getFullYear() 从 Date 对象以四位数字返回年份。
getHours() 返回 Date 对象的小时 (0 ~ 23)。
getMilliseconds() 返回 Date 对象的毫秒(0 ~ 999)。
getMinutes() 返回 Date 对象的分钟 (0 ~ 59)。
getMonth() 从 Date 对象返回月份 (0 ~ 11)。
getSeconds() 返回 Date 对象的秒数 (0 ~ 59)。
getTime() 返回 1970 年 1 月 1 日至今的毫秒数。

字符串转为数字的方法:

Number()

方法 描述
parseFloat() 解析一个字符串,并返回一个浮点数。
parseInt() 解析一个字符串,并返回一个整数。

正则表达式

正则表达式是由一个字符序列形成的搜索模式,当你在文本中搜索数据时,你可以用搜索模式来描述你要查询的内容。

正则表达式可以是一个简单的字符,或一个更复杂的模式,可用于所有文本搜索和文本替换的操作。

1
语法:/正则表达式主体/修饰符(可选)

正则表达式通常用于两个字符串方法 : search() 和 replace()。

search() 方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串,并返回子串的起始位置。

1
2
3
4
5
function myFunction(){
var str="Visit runoob";
var n=str.search(/Runoob/i);
document.getElementById("demo").innerHTML=n;
}

replace() 方法用于在字符串中用一些字符串替换另一些字符串,或替换一个与正则表达式匹配的子串。

1
2
3
4
5
function myFunction(){
var str=document.getElementById("demo").innerHTML;
var txt=str.replace(/die/i,"happy");
document.getElementById("demo").innerHTML=txt;
}

修饰符

i 执行对大小写不敏感的匹配。
g 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
m 执行多行匹配。

正则表达式模式

方括号用于查找某个范围内的字符:

表达式 描述
[abc] 查找方括号之间的任何字符。
[0-9] 查找任何从 0 至 9 的数字。
(x|y) 查找任何以 | 分隔的选项。

元字符是拥有特殊含义的字符:

元字符 描述
\d 查找数字。
\s 查找空白字符。
\b 匹配单词边界。
\uxxxx 查找以十六进制数 xxxx 规定的 Unicode 字符。

量词:

量词 描述
n+ 匹配任何包含至少一个 n 的字符串。
n* 匹配任何包含零个或多个 n 的字符串。
n? 匹配任何包含零个或一个 n 的字符串。

RegExp对象

RegExp 对象是一个预定义了属性和方法的正则表达式对象

创建 RegExp 对象的方式

  1. 字面量表示法:使用斜杠(/)将正则表达式括起来。

    1
    2
    javascriptCopy code
    var regex = /pattern/;
  2. 构造函数表示法:使用 RegExp 构造函数创建一个 RegExp 对象。

    1
    2
    javascriptCopy code
    var regex = new RegExp("pattern");

RegExp对象的常用方法和属性

  1. **test()**:用于检测字符串是否匹配正则表达式。如果匹配成功,则返回 true,否则返回 false

    1
    2
    var pattl=new RegExp("e");
    document.write(pattl.test("The best thing"));
  2. **exec()**:用于在字符串中执行一个搜索匹配。如果匹配成功,则返回一个结果数组;否则返回 null

    1
    2
    3
    4
    5
    6
    var regex = /\d+/g; // 定义一个正则表达式,用于匹配数字
    var str = "Today is 2024-01-11, and it's raining. The temperature is 15°C.";
    var match;
    while ((match = regex.exec(str)) !== null) {
    console.log("Found: " + match[0] + ", at index: " + match.index);
    }
  3. source:RegExp 对象的只读属性,返回正则表达式的文本字符串。

    1
    2
    javascriptCopy code
    console.log(regex.source);
  4. flags:RegExp 对象的只读属性,返回正则表达式的修饰符字符串。

1
console.log(regex.flags);

throw,try,catch

try 语句测试代码块的错误。

catch 语句处理错误。

throw 语句创建自定义错误。

finally 语句在 try 和 catch 语句之后,无论是否有触发异常,该语句都会执行。

抛出(throw)错误

当错误发生时,当事情出问题时,JavaScript 引擎通常会停止,并生成一个错误消息。

描述这种情况的技术术语是:JavaScript 将抛出一个错误。

try和catch

try 语句允许我们定义在执行时进行错误测试的代码块。

catch 语句允许我们定义当 try 代码块发生错误时,所执行的代码块。

JavaScript 语句 try 和 catch 是成对出现的。

1
2
3
4
5
6
7
try {
... //异常的抛出
} catch(e) {
... //异常的捕获与处理
} finally {
... //结束处理
}

实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
var txt="";
function message(){
try {
adddlert("Welcome guest!");
}
catch(err) {
txt="本页有一个错误。\n\n";
txt+="错误描述:" + err.message + "\n\n";
txt+="点击确定继续。\n\n";
alert(txt);
}
}
</script>
<input type="button" value="点击查看消息" onclick="message()"/>

对于err.message的理解:catch 块捕获了可能发生的错误,并将错误对象存储在变量 err 中。然后,通过 err.message 属性可以获取到该错误对象的消息内容,即错误的描述信息。

与finally语句之间的联用

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
<p>不管输入是否正确,输入框都会再输入后清空。</p>
<p>请输入 5 ~ 10 之间的数字:</p>
<input id="demo" type="text">
<button type="button" onclick="myFunction()">点我</button>
<p id="p01"></p>
<script>
function myFunction() {
var message, x;
message = document.getElementById("p01");
message.innerHTML = "";
x = document.getElementById("demo").value;
try {
if(x == "") throw "值是空的";
if(isNaN(x)) throw "值不是一个数字";
x = Number(x);
if(x > 10) throw "太大";
if(x < 5) throw "太小";
}
catch(err) {
message.innerHTML = "错误: " + err + ".";
}
finally {
document.getElementById("demo").value = "";
}
}
</script>

isNaN() 是 JavaScript 中的一个内置函数,用于检查一个值是否为 “NaN”(Not-a-Number,非数字)。

表单验证

HTML约束验证

HTML 约束验证基于:HTML 输入属性,CSS 伪类选择器,DOM 属性和方法

HTML 输入属性:

属性 描述
disabled 规定输入的元素不可用
max 规定输入元素的最大值
min 规定输入元素的最小值
pattern 规定输入元素值的模式
required 规定输入元素字段是必需的
type 规定输入元素的类型

必填或必选项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<head>
<script>
function validateForm(){
var x=document.forms["myForm"]["fname"].value;
if (x==null || x==""){
alert("姓必须填写");
return false;
}
}
</script>
</head>
<body>
<form name="myForm" action="demo-form.php" onsubmit="return validateForm()" method="post">
姓: <input type="text" name="fname">
<input type="submit" value="提交">
</form>
</body>
</html>

分析:var x=document.forms["myForm"]["fname"].value;:在函数内部,通过 document.forms["myForm"]["fname"] 获取了表单中名为 “fname” 的输入框,并使用 .value 获取了该输入框的值,将其赋给变量 x

return false;:返回 false,表示表单验证失败,阻止表单的提交(如果删除这行代码,则可以报错,但表单会继续提交)

E-mail验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
function validateForm(){
var x=document.forms["myForm"]["email"].value;
var atpos=x.indexOf("@");
var dotpos=x.lastIndexOf(".");
if (atpos<1 || dotpos<atpos+2 || dotpos+2>=x.length){
alert("不是一个有效的 e-mail 地址");
return false;
}
}
</script>
<form name="myForm" action="demo-form.php" onsubmit="return validateForm();" method="post">
Email: <input type="text" name="email">
<input type="submit" value="提交">
</form>

验证API

约束验证DOM方法

属性 描述
checkValidity() 如果 input 元素中的数据是合法的返回 true,否则返回 false。
setCustomValidity() 设置 input 元素的 validationMessage 属性,用于自定义错误提示信息的方法。使用 setCustomValidity 设置了自定义提示后,validity.customError 就会变成 true,checkValidity 总是会返回 false。如果要重新判断需要取消自定义提示,方式如下:setCustomValidity('') setCustomValidity(null) setCustomValidity(undefined)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<body>
<p>输入数字并点击验证按钮:</p>
<input id="id1" type="number" min="100" max="300" required>
<button onclick="myFunction()">验证</button>
<p>如果输入的数字小于 100 或大于300,会提示错误信息。</p>
<p id="demo"></p>
<script>
function myFunction() {
var inpObj = document.getElementById("id1");
if (inpObj.checkValidity() == false) {
document.getElementById("demo").innerHTML = inpObj.validationMessage;
} else {
document.getElementById("demo").innerHTML = "输入正确";
}
}
</script>
</body>

validationMessage 属性会返回一个包含了关于输入框验证失败的错误消息的字符串

约束验证DOM属性

属性 描述
validity 布尔属性值,返回 input 输入值是否合法
validationMessage 浏览器错误提示信息
willValidate 指定 input 是否需要验证

Validity属性

属性 描述
customError 设置为 true, 如果设置了自定义的 validity 信息。
patternMismatch 设置为 true, 如果元素的值不匹配它的模式属性。
rangeOverflow 设置为 true, 如果元素的值大于设置的最大值。
rangeUnderflow 设置为 true, 如果元素的值小于它的最小值。
stepMismatch 设置为 true, 如果元素的值不是按照规定的 step 属性设置。
tooLong 设置为 true, 如果元素的值超过了 maxLength 属性设置的长度。
typeMismatch 设置为 true, 如果元素的值不是预期相匹配的类型。
valueMissing 设置为 true,如果元素 (required 属性) 没有值。
valid 设置为 true,如果元素的值是合法的。

来个实例:

1
2
3
4
5
6
7
function myFunction() {
var txt = "";
if (document.getElementById("id1").validity.rangeOverflow) {
txt = "输入的值太大了";
}
document.getElementById("demo").innerHTML = txt;
}

this关键字

this 不是固定不变的,它会随着执行环境的改变而改变。

  • 在方法中,this 表示该方法所属的对象。(在 JavaScript 中,对象的属性可以是函数,这种属性称为方法)
  • 如果单独使用,this 表示全局对象。
  • 在函数中,this 表示全局对象。
  • 在函数中,在严格模式下,this 是未定义的(undefined)。
  • 在事件中,this 表示接收事件的元素。
  • 类似 call() 和 apply() 方法可以将 this 引用到任何对象。

方法中的this

1
2
3
4
5
6
7
8
9
var person={
firstname:"Sherlock",
Lastname:"Holmes",
id:5566,
fullname:function(){
return this.firstname+" "+this.Lastname;
}
};
document.getElementById("demo").innerHTML=person.fullname();

fullName 方法所属的对象就是 person

想要使用这个方法时,需要在方法名后面加上一对括号 (),这样 JavaScript 就知道你是在调用这个方法。如果不加括号,那么 person.fullname 将被视为一个函数对象,而不是调用该函数,那么页面中相应元素的内容将会是 function(),表示这个属性是一个函数

单独使用this

1
2
3
var x = this;
document.getElementById("demo").innerHTML = x;
//返回的结果是:[object Window]

在浏览器中,window 就是该全局对象

函数中的this

1
2
3
4
5
//"use strict";
document.getElementById("demo").innerHTML = myFunction();
function myFunction() {
return this;
}

函数的所属者默认绑定到 this 上,在浏览器中,window 就是该全局对象为 [object Window]

严格模式下,即在有第一行代码的情况下函数是没有绑定到 this 上,这时候 this 是 undefined,这是因为严格模式下不允许默认绑定

事件中的this

1
2
3
<body>
<button onclick="this.style.display='none'">点我后我就消失了</button>
</body>

this 关键字代表当前触发了事件的元素,也就是按钮本身。this.style.display='none' 表示设置按钮的 display 属性为 'none',这样按钮就不会显示在页面上了

显式函数绑定

在 JavaScript 中函数也是对象,对象则有方法,apply 和 call 就是函数对象的方法。这两个方法异常强大,他们允许切换函数执行的上下文环境(context),即 this 绑定的对象

1
2
3
4
5
6
7
8
9
10
11
var person1 = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person2 = {
firstName:"John",
lastName: "Doe",
}
var x = person1.fullName.call(person2);
document.getElementById("demo").innerHTML = x;

使用 person2 作为参数来调用 person1.fullName 方法时, this 将指向 person2, 即便它是 person1 的方法

let和const

let 声明的变量只在 let 命令所在的代码块内有效。

const 声明一个只读的常量,声明时必须进行初始化,一旦声明,常量的值就不能改变。

let 声明的变量只在 let 命令所在的代码块 {} 内有效,在 {} 之外不能访问

1
2
3
4
{ 
let x = 2;
}
// 这里不能使用 x 变量

在相同的作用域或块级作用域中,不能使用 let 关键字来重置 var 关键字声明的变量,,同样不能使用 var 关键字来重置 let 关键字声明的变量。(就是哪个关键字先声明变量就是合法的)

1
2
3
4
5
6
var x = 2;       // 合法
let x = 3; // 不合法
{
var x = 4; // 合法
let x = 5 // 不合法
}

const 的本质: const 定义的变量并非常量,并非不可变,它定义了一个常量引用一个值。使用 const 定义的对象或者数组,其实是可变的,也就是说我们可以修改其对象或者数组里面的元素,但是不能对该对象或者数组进行重新赋值,因为这样的话内存地址会发生变化,这是不允许的

1
2
3
4
5
const car = {type:"Fiat", model:"500", color:"white"};
car = {type:"Volvo", model:"EX60", color:"red"}; // 错误
car.color = "red";
car.owner = "Johnson";
document.getElementById("demo").innerHTML = "Car owner is " + car.owner;

在相同的作用域或块级作用域中,不能使用 const 关键字来重置 const 关键字声明的变量

const 关键字在不同作用域,或不同块级作用域中是可以重新声明赋值的

JSON

以下 JSON 语法定义了 sites 对象: 3 条网站信息(对象)的数组:

1
2
3
4
5
{"sites":[
{"name":"Runoob", "url":"www.runoob.com"},
{"name":"Google", "url":"www.google.com"},
{"name":"Taobao", "url":"www.taobao.com"}
]}

JSON格式化后为JavaScript对象

语法规则:

  • 数据为 键/值 对。
  • 数据由逗号分隔。
  • 大括号保存对象
  • 方括号保存数组

JSON 字符串转换为 JavaScript 对象

1
2
3
4
5
6
7
var text = '{ "sites" : [' +
'{ "name":"Runoob" , "url":"www.runoob.com" },' +
'{ "name":"Google" , "url":"www.google.com" },' +
'{ "name":"Taobao" , "url":"www.taobao.com" } ]}';

obj = JSON.parse(text);
document.getElementById("demo").innerHTML = obj.sites[1].name + " " + obj.sites[1]

首先,创建 JavaScript 字符串,字符串为 JSON 格式的数据;然后,使用 JavaScript 内置函数 JSON.parse() 将字符串转换为 JavaScript 对象;最后,在你的页面中使用新的 JavaScript 对象

函数 描述
JSON.parse() 用于将一个 JSON 字符串转换为 JavaScript 对象。
JSON.stringify() 用于将 JavaScript 值转换为 JSON 字符串

void

void主要的就是防止页面跳转

javascript:void(0)

语法格式如下:

1
2
void(func())
javascript:void(func())

实例如下:

1
2
3
<body>
<a href="javascript:void(0)">单击此处什么也不会发生</a>
</body>

当用户链接时,void(0) 计算为 0,但 Javascript 上没有任何效果。


1
2
3
4
<body>
<p>点击以下链接查看结果:</p>
<a href="javascript:void(alert('Warning!!!'))">点我!</a>
</body>

void()仅仅是代表不返回任何值,但是括号内的表达式还是要运行

href=”#”

# 包含了一个位置信息,默认的锚是**#top** 也就是网页的上端。

而javascript:void(0), 仅仅表示一个死链接。

在页面很长的时候会使用 # 来定位页面的具体位置,格式为:**# + id**

1
2
3
4
5
6
<a href="javascript:void(0);">点我没有反应的!</a>
<a href="#pos">点我定位到指定位置!</a>
<br>
...
<br>
<p id="pos">尾部定位点</p>

异步编程(回调函数)

同步按你的代码顺序执行,异步不按照代码顺序执行,异步的执行效率更高。

通俗地解释一下就是从主线程发射一个子线程来完成任务

什么时候使用异步编程

在前端编程中(甚至后端有时也是这样),我们在处理一些简短、快速的操作时,例如计算 1 + 1 的结果,往往在主线程中就可以完成。主线程作为一个线程,不能够同时接受多方面的请求。所以,当一个事件没有结束时,界面将无法处理其他请求。

现在有一个按钮,如果我们设置它的 onclick 事件为一个死循环,那么当这个按钮按下,整个网页将失去响应。

为了避免这种情况的发生,我们常常用子线程来完成一些可能消耗时间足够长以至于被用户察觉的事情,比如读取一个大文件或者发出一个网络请求。因为子线程独立于主线程,所以即使出现阻塞也不会影响主线程的运行。但是子线程有一个局限:一旦发射了以后就会与主线程失去同步,我们无法确定它的结束,如果结束之后需要处理一些事情,比如处理来自服务器的信息,我们是无法将它合并到主线程中去的。

为了解决这个问题,JavaScript 中的异步操作函数往往通过回调函数来实现异步任务的结果处理。

回调函数

回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么

1
2
3
4
5
<script>
setTimeout(function(){
document.getElementById("demo").innerHTML="Messi!";
},3000);
</script>

setTimeout 函数是 JavaScript 中的一个定时器函数,用于在一定的时间延迟后执行指定的代码或函数;基础语法如下:

1
setTimeout(function, milliseconds);

其中function 是要执行的函数或代码块;milliseconds 是延迟的毫秒数

由于setTimeout是在子线程中执行的,主线程没有停止,在主线程里面可以执行其他函数

1
2
3
4
5
6
<script>
setTimeout(function(){
document.getElementById("demo").innerHTML="Messi!";//子线程
},3000);
document.getElementById("demo2").innerHTML="MCI!";//主线程
</script>

HTML载入外部JavaScript文件

1
<script src="myscript.js">

JS函数

函数定义

函数表达式存储在变量后,变量也可作为一个函数使用

1
2
3
4
<script>
var x = function (a, b) {return a * b};
document.getElementById("demo").innerHTML = x(4, 3);
</script>

函数存储在变量中,不需要函数名称,通常通过变量名来调用,上述函数以分号结尾是因为它是一个执行语句

自调用函数

自调用函数是指在定义后立即执行的 JavaScript 函数,语法格式如下:

1
2
3
(function() {
// 在这里编写函数体
})();

实例如下:

1
2
3
4
5
<script>
(function () {
document.getElementById("demo").innerHTML = "Hello! 我是自己调用的";
})();
</script>

在JavaScript中把函数描述为对象更加的准确一点,这里的函数也有属性和方法

例子:arguments.length 属性返回函数调用过程接收到的参数个数

1
2
3
4
5
6
<script>
function myFunction(a, b) {
return arguments.length;
}
document.getElementById("demo").innerHTML = myFunction(4, 3);
</script>

toString() 方法将函数作为一个字符串返回

1
2
3
4
5
6
<script>
function myFunction(a, b) {
return a * b;
}
document.getElementById("demo").innerHTML = myFunction.toString();
</script>

箭头函数

箭头函数的表达式更加的简洁,语法如下:

1
2
3
(参数1, 参数2, …, 参数N) => { 函数声明 }
(参数1, 参数2, …, 参数N) => 表达式(单一)
// 相当于:(参数1, 参数2, …, 参数N) =>{ return 表达式; }

当只有一个函数时,圆括号是可加可不加的

1
2
(单一参数) => {函数声明}
单一参数 => {函数声明}

没有参数的函数圆括号不能省略:() => {函数声明}

例子如下:

1
2
3
4
<script>
const x = (x, y) => x * y;
document.getElementById("demo").innerHTML = x(5, 5);
</script>

函数参数

显式参数和隐式参数

函数显式参数在函数定义时列出;隐式参数在函数调用时传递给函数真正的值。

ES5 中如果函数在调用时未提供隐式参数,参数会默认设置为: undefined

解释:y=y||0,如果 y 已经定义,y || 0 返回 y,因为 y 是 true,否则返回 0,因为 undefined 为 false。

ES6 支持函数带有默认参数

1
2
3
4
5
6
function myFunction(x, y = 10) {
// y is 10 if not passed or undefined
return x + y;
}
myFunction(0, 2) // 输出 2
myFunction(5); // 输出 15, y 参数的默认值

arguments对象

JavaScript 函数有个内置的对象 arguments 对象,它包含了函数调用的参数数组。

通过这种方式你可以很方便的找到最大的一个参数的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
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;
}
document.getElementById("demo").innerHTML = x;
</script>

函数调用

使用构造函数调用函数

如果函数调用前使用了 new 关键字, 则是调用了构造函数。

这看起来就像创建了新的函数,但实际上 JavaScript 函数是重新创建的对象

1
2
3
4
5
6
7
8
<script>
function myFunction(arg1, arg2) {
this.firstName = arg1;
this.lastName = arg2;
}
var x = new myFunction("John","Doe")
document.getElementById("demo").innerHTML = x.firstName;
</script>

myFunction是构造函数,构造函数的调用会创建一个新的对象。新对象会继承构造函数的属性和方法

构造函数中 this 关键字没有任何的值。this 的值在函数调用实例化对象(new object)时创建。

作为函数方法调用函数

前文中的this关键字一节中也有提到过

call()apply() 是预定义的函数方法。 两个方法可用于调用函数,两个方法的第一个参数必须是对象本身。

1
2
3
4
5
6
7
8
<script>
var myObject;
function myFunction(a, b) {
return a * b;
}
myObject = myFunction.call(myObject, 10, 2); // 返回 20
document.getElementById("demo").innerHTML = myObject;
</script>

闭包

变量声明时如果不使用 var 关键字,那么它就是一个全局变量,即便它在函数内定义。

在 JavaScript 中,函数可以访问其定义时所在的作用域中的变量。当一个函数在另一个函数内部被定义时,它可以访问包含它的外部函数的作用域,形成了闭包

闭包是指一个函数和其周围的状态的组合。这个环境包含了函数创建时所处的作用域中的所有局部变量,以及它们的值。这意味着函数可以访问其外部作用域中定义的变量,即使在它被调用时,这些变量已经不再处于活动状态。

闭包通常由以下两个特点组成:

  1. 内部函数引用外部变量:闭包函数内部定义的函数引用了外部函数的局部变量。
  2. 外部函数返回内部函数:外部函数返回了内部定义的函数,使得该函数的作用域仍然可以访问外部函数中的变量。

我们可以使用自调用函数来实现闭包

1
2
3
4
5
6
7
8
9
<script>
var add=(function(){
var counter=0;
return function(){return counter +=1;}
})();
function myFunction(){
document.getElementById("demo").innerHTML=add();
}
</script>

对上述代码的解释:var add = (function() { ... })();:这是一个立即执行函数表达式(Immediately Invoked Function Expression,IIFE)。这个函数返回了一个内部函数,并将这个内部函数赋值给变量 add。在这个内部函数内部,创建了一个私有变量 counter,并返回一个闭包函数,这个闭包函数用来递增 counter 的值

counter 是一个闭包变量,它被包含在返回的匿名函数内部,并且由于闭包的特性,该变量在函数执行完毕后并不会被销毁,而是会一直保存在内存中,直到程序退出或者手动释放,因此,每次调用 add 函数时,实际上是在调用返回的闭包函数,这个闭包函数中的 counter 变量会保留之前的值,并在每次调用时进行累加操作

也可以这样说,counter 变量是在外部函数作用域中定义的,即 IIFE 的作用域。而内部函数(闭包函数)保留了对这个作用域的引用,因此它可以在每次调用时访问和修改 counter 变量的值

类的基础

使用 class 关键字来创建一个类,类体在一对大括号 {} 中,我们可以在大括号 {} 中定义类成员的位置,如方法或构造函数。

每个类中包含了一个特殊的方法 **constructor()**,它是类的构造函数,这种方法用于创建和初始化一个由 class 创建的对象。

创建一个类的语法格式如下:

1
2
3
class ClassName {
constructor() { ... }
}

在定义好类之后,我们可以使用 new关键字来创建对象:

1
2
3
4
5
6
7
8
9
10
<script>
class MNC{
constructor(name,captain){
this.name=name;
this.captain=captain;
}
}
let site=new MNC("MNC","鲁本");
document.getElementById("demo").innerHTML=site.name+": "+site.captain;
</script>

创建对象时会自动调用构造函数方法 constructor()

类表达式

类表达式是定义类的另一种方法。类表达式可以命名或不命名。命名类表达式的名称是该类体的局部名称。

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 未命名/匿名类
let Runoob = class {
constructor(name, url) {
this.name = name;
this.url = url;
}
};
console.log(Runoob.name);
// output: "Runoob"

// 命名类
let Runoob = class Runoob2 {
constructor(name, url) {
this.name = name;
this.url = url;
}
};
console.log(Runoob.name);
// 输出: "Runoob2"

构造方法

构造方法是一种特殊的方法:

  • 构造方法名为 constructor()。
  • 构造方法在创建新对象时会自动执行。
  • 构造方法用于初始化对象属性。
  • 如果不定义构造方法,JavaScript 会自动添加一个空的构造方法。

类的方法

使用关键字 class 创建一个类,可以添加一个 constructor() 方法,然后添加任意数量的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
class King{
constructor(name,year) {
this.name=name;
this.year=year;
}
age(){
let date=new Date();
return date.getFullYear()-this.year;
}
}
let king=new King("Messi",2022);
document.getElementById("demo").innerHTML="Messi is the king for "+king.age()+" years.";
</script>

也可以向类的方法发送参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
class Runoob {
constructor(name, year) {
this.name = name;
this.year = year;
}
age(x) {
return x - this.year;
}
}
let date = new Date();
let year = date.getFullYear();
let runoob = new Runoob("菜鸟教程", 2020);
document.getElementById("demo").innerHTML=
"菜鸟教程 " + runoob.age(year) + " 岁了。";
</script>

类关键字

关键字 描述
extends 继承一个类
static 在类中定义一个静态方法
super 调用父类的构造方法

类继承

使用ES6类继承

JavaScript 类继承使用 extends 关键字。

继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。

super() 方法用于调用父类的构造函数。

当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类(父类),新建的类称为派生类(子类)

继承代表了 is a 关系。例如,哺乳动物是动物,狗是哺乳动物,因此,狗是动物,等等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<script>
class Who {
constructor(name) {
this.name = name;
}
present(){
return '我喜欢' + this.name;
}
}
class King extends Who{
constructor(name,age){
super(name);
this.age=age;
}
show(){
return this.present()+',他成为球王'+this.age+'年了。';
}
}
let king=new King("梅西",2);
document.getElementById("demo").innerHTML=king.show();
</script>

super() 方法引用父类的构造方法。

通过在构造方法中调用 super() 方法,我们调用了父类的构造方法,这样就可以访问父类的属性和方法。

使用原型链继承

详情见下一节

getter和setter

类中我们可以使用 getter 和 setter 来获取和设置值,getter 和 setter 都需要在严格模式下执行。

类中添加 getter 和 setter 使用的是 get 和 set 关键字,实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
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;
</script>

getter/setter 方法的名称不能与属性的名称相同,很多开发者在属性名称前使用下划线字符 _ 将 getter/setter 与实际属性分开

静态方法

静态方法是使用 static 关键字修饰的方法,又叫类方法,属于类的,但不属于对象,在实例化对象之前可以通过 类名.方法名 调用静态方法。静态方法不能在对象上调用,只能在类中调用。

如果想在对象中使用静态方法,可以把对象作为一个参数传递给它:

1
2
3
4
5
6
7
8
9
10
11
12
<script>
class Runoob {
constructor(name) {
this.name = name;
}
static hello(x) {
return "Hello " + x.name;
}
}
let noob = new Runoob("菜鸟教程");
document.getElementById("demo").innerHTML = Runoob.hello(noob);
</script>

原型链

构造函数

实例如下

1
2
3
4
function Person(name, age) {
this.name = name;
this.age = age;
}

原型对象

JS的每个函数在创建的时候,都会生成一个属性prototype,这个属性指向一个对象,这个对象就是此函数的原型对象。该原型对象中有个属性为constructor,指向该函数。这样原型对象它的函数之间就产生了联系。

**_proto_**

每个通过构造函数创建出来的实例对象,其本身有个属性__proto__,这个属性会指向该实例对象构造函数原型对象

当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会通过它的__proto__隐式属性,找到它的构造函数原型对象,如果还没有找到就会再在其构造函数prototype__proto__中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链

注意:如果通过p1实例对象__proto__属性赋值,则会改变其构造函数原型对象,从而被所有实例所共享。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 构造函数
function Preson(name, age) {
this.name = name;
this.age = age;
}
// 所有实例共享的公共方法
Preson.prototype.say = function (word) {
console.log(`${this.name}说:${word}`);
}
const p1 = new Preson('张三', 18); // 创建一个Person实例对象
const p2 = new Preson('李四', 20); // 新创建一个Proson实例对象
p1.say('hello world'); // 调用公共方法
p1.hasOwnProperty('say') // false 说明不是定义在其本身上的
p1.__proto__.do = function () {
console.log('往原型对象中添加方法');
}
p2.do(); // 打印出了-往原型对象中添加方法

原型链的尽头

构造函数,通过打印它的prototype属性,可以发现它有个__proto__属性指向了一个Object对象该对象的构造函数function Object,我们由此可以得知,所有的原型对象__proto__属性都是指向function Object原型对象function Object原型对象在上图中我们可以得知是不存在__proto__这个属性的,它指向了null。我们就得知了原型链的尽头是null


当你创建一个自定义的函数时(比如 Animal 函数),JavaScript 会自动为这个函数创建一个 prototype 对象。你可以通过给这个 prototype 对象添加属性和方法来定义该函数的原型,从而实现函数的原型继承。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Animal(name) {
this.name = name;
}//构造函数
Animal.prototype.eat = function() {
console.log(this.name + " is eating.");
};

function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}//构造函数

// 建立原型链,让 Dog 继承 Animal
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log(this.name + " is barking.");
};
var dog = new Dog("Buddy", "Labrador");
dog.eat(); // 调用从 Animal 继承的方法
dog.bark(); // 调用 Dog 的方法

Dog 的构造函数中,我们使用 Animal.call(this, name) 来调用父类 Animal 的构造函数,确保了在创建 Dog 实例时能够正确初始化 name 属性

Dog.prototype = Object.create(Animal.prototype);:,通过 Object.create(Animal.prototype)Dog 的原型对象指向了 Animal 的原型对象,从而实现了 Dog 对象对 Animal 对象的继承。

Object.create() 是 JavaScript 中用来创建一个新对象,并将新对象的原型设置为指定的原型对象的函数。它的语法结构如下:

1
Object.create(proto[, propertiesObject])

其中,proto 参数是新对象的原型对象,而 propertiesObject 是可选的,用于定义新对象的可枚举属性。这个方法返回一个新对象,该对象的原型为指定的 proto 参数。

使用 Object.create() 可以很方便地创建一个继承自指定原型对象的新对象。在上面提到的代码示例中,就是利用 Object.create() 来建立了 Dog 对象对 Animal 对象的原型继承关系。


相关链接:一文搞懂JS原型与原型链(超详细,建议收藏) - 掘金 (juejin.cn)

HTML DOM (文档对象模型)

查找HTML元素

1.通过 id 找到 HTML 元素:var x=document.getElementById("intro");

2.通过标签名找到 HTML 元素

1
2
3
4
5
6
7
8
9
10
11
12
<body>
<p>你好世界!</p>
<div id="main">
<p> DOM 是非常有用的。</p>
<p>该实例展示了 <b>getElementsByTagName</b> 方法</p>
</div>
<script>
var x=document.getElementById("main");
var y=x.getElementsByTagName("p");
document.write('id="main"元素中的第一个段落为:' + y[0].innerHTML);
</script>
</body>

3.通过类名找到 HTML 元素:var x=document.getElementsByClassName("intro");

改变HTML

改变 HTML 元素的内容,请使用这个语法:document.getElementById(*id*).innerHTML=新的 HTML

改变 HTML 元素的属性,请使用这个语法:document.getElementById(*id*).*attribute=新属性值,例子如下

1
2
3
4
5
6
7
<body>
<img id="image" src="smiley.gif" width="160" height="120">
<script>
document.getElementById("image").src="landscape.jpg";
</script>
<p>原图片为 smiley.gif,脚本将图片修改为 landscape.jpg</p>
</body>

DOM事件

HTML 事件的例子:

  • 当用户点击鼠标时
  • 当网页已加载时
  • 当图像已加载时
  • 当鼠标移动到元素上时
  • 当输入字段被改变时
  • 当提交 HTML 表单时
  • 当用户触发按键时

onload 和 onunload 事件

onload 和 onunload 事件会在用户进入或离开页面时被触发。

onload 事件可用于检测访问者的浏览器类型和浏览器版本,并基于这些信息来加载网页的正确版本。

onload 和 onunload 事件可用于处理 cookie

1
2
3
4
5
6
7
8
9
10
11
12
<body onload="checkCookies()">
<script>
function checkCookies(){
if (navigator.cookieEnabled==true){
alert("Cookies 可用")
}
else{
alert("Cookies 不可用")
}
}
</script>//弹窗-提示浏览器 cookie 是否可用
</body>

onchange 事件

onchange 事件是在 HTML 元素的值发生改变时触发的事件。这个事件通常用于表单元素,比如 <input><select><textarea> 等,当用户在这些元素上进行修改后,就会触发 onchange 事件

1
2
3
4
5
6
7
8
<h1>开始测试</h1>
输入字母:<input type="text" id="demo" onchange="myFunction()">
<script>
function myFunction(){
var x=document.getElementById("demo");
x.value=x.value.toUpperCase();
}
</script>//焦点离开输入框后,函数就会被触发

onmouseover 和 onmouseout 事件

onmouseover 和 onmouseout 事件可用于在用户的鼠标移至 HTML 元素上方或移出元素时触发函数。

1
2
3
4
5
6
7
8
9
<div onmouseover="mOver(this)" onmouseout="mOut(this)" style="background-color:#D94A38;width:120px;height:20px;padding:40px;">Mouse Over Me</div>
<script>
function mOver(obj){
obj.innerHTML="Thank You"
}
function mOut(obj){
obj.innerHTML="Mouse Over Me"
}
</script>

onmousedown, onmouseup 以及 onclick事件

onmousedown, onmouseup 以及 onclick 构成了鼠标点击事件的所有部分。首先当点击鼠标按钮时,会触发 onmousedown 事件,当释放鼠标按钮时,会触发 onmouseup 事件,最后,当完成鼠标点击时,会触发 onclick 事件

1
2
3
4
5
6
7
8
9
10
11
12
<body>
<script>
function lighton(){
document.getElementById('myimage').src="bulbon.gif";
}
function lightoff(){
document.getElementById('myimage').src="bulboff.gif";
}
</script>
<img id="myimage" onmousedown="lighton()" onmouseup="lightoff()" src="bulboff.gif" width="100" height="180" />
<p>点击不释放鼠标灯将一直亮着!</p>
</body>

onfocus事件

1
2
3
4
5
6
7
8
9
<body>
<script>
function myFunction(x){
x.style.background="yellow";
}
</script>
输入你的名字: <input type="text" onfocus="myFunction(this)">
<p>当输入框获取焦点时,修改背景色(background-color属性) 将被触发。</p>
</body>

DOM EventListener

addEventListener() 方法

addEventListener() 方法用于向指定元素添加事件句柄。

addEventListener() 方法添加的事件句柄不会覆盖已存在的事件句柄。

你可以向一个元素添加多个事件句柄。

你可以向同个元素添加多个同类型的事件句柄,如:两个 “click” 事件。

你可以向任何 DOM 对象添加事件监听,不仅仅是 HTML 元素。如: window 对象。

addEventListener() 方法可以更简单的控制事件(冒泡与捕获)。

下面实例为点击按钮后触发监听事件:

1
2
3
4
5
6
7
8
<button id="muBtn">点击</button>
<p id="demo"></p>
<script>
document.getElementById("muBtn").addEventListener("click",showDate);
function showDate(){
document.getElementById("demo").innerHTML=Date();
}
</script>

该方法的语法:element.addEventListener(event, function, useCapture);

第一个参数是事件的类型 (如 “click” 或 “mousedown”);第二个参数是事件触发后调用的函数;第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的

注意:事件不需要加”on”前缀

向元素添加事件句柄

1
2
3
4
5
<script>
document.getElementById("myBtn").addEventListener("click", function(){
alert("Hello World!");
});
</script>

除了上述方法,也可以使用函数名,引用外部函数

1
2
3
4
document.getElementById("myBtn").addEventListener("click", myFunction);
function myFunction() {
alert ("Hello World!");
}

addEventListener() 方法允许向同一个元素添加多个事件,且不会覆盖已存在的事件

可以向同个元素添加不同类型的事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let x=document.getElementById("muBtn")
x.addEventListener("click",showDate)
x.addEventListener("mouseover",first);
x.addEventListener("mouseout",second);
function showDate(){
let date=Date();
document.getElementById("demo").innerHTML+=date+"<br>";
}
function first(){
document.getElementById("demo").innerHTML+="first<br>"
}
function second(){
document.getElementById("demo").innerHTML+="second<br>"
}

向window对象添加事件句柄

addEventListener() 方法允许你在 HTML DOM 对象添加事件监听, HTML DOM 对象如: HTML 元素, HTML 文档, window 对象。或者其他支持的事件对象如: xmlHttpRequest 对象

1
2
3
4
5
<script>//重置窗口大小的时候会触发"resize" 事件句柄
window.addEventListener("resize", function(){
document.getElementById("demo").innerHTML = Math.random();
});
</script>

传递参数

当传递参数值时,使用”匿名函数”调用带参数的函数

1
2
3
4
5
6
7
8
9
let p1=5;
let p2=4;
document.getElementById("myBtn").addEventListener("click",function(){
myFunction(p1,p2);
});
function myFunction(a,b){
var result=a*b;
document.getElementById("demo").innerHTML=result;
}

document.getElementById("myBtn").addEventListener("click",myFunction(p1, p2));错误原因:事件监听器中的函数应该是一个函数的引用,而不是一个函数的调用。因此,在添加事件监听器时,应该传递函数名而不是调用函数。myFunction(p1, p2) 是一个函数调用,而不是函数的引用。

事件冒泡或捕获

事件传递有两种方式:冒泡与捕获。

事件传递定义了元素事件触发的顺序。 如果你将

元素插入到

元素中,用户点击

元素, 哪个元素的 “click” 事件先被触发呢?

冒泡 中,内部元素的事件会先被触发,然后再触发外部元素,即:

元素的点击事件先触发,然后会触发

元素的点击事件。

捕获 中,外部元素的事件会先被触发,然后才会触发内部元素的事件,即:

元素的点击事件先触发 ,然后再触发

元素的点击事件。

addEventListener() 方法可以指定 “useCapture” 参数来设置传递类型:

1
addEventListener(event,function,useCapture);

默认值为 false, 即冒泡传递,当值为 true 时, 事件使用捕获传递。

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
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<style>
div {
background-color: coral;
border: 1px solid;
padding: 50px;
}
</style>
</head>
<body>
<div id="myDiv">
<p id="myP">点击段落,我是冒泡。</p>
</div><br>
<div id="myDiv2">
<p id="myP2">点击段落,我是捕获。 </p>
</div>
<script>
document.getElementById("myP").addEventListener("click", function() {
alert("你点击了 P 元素!");
}, false);
document.getElementById("myDiv").addEventListener("click", function() {
alert(" 你点击了 DIV 元素 !");
}, false);
document.getElementById("myP2").addEventListener("click", function() {
alert("你点击了 P2 元素!");
}, true);
document.getElementById("myDiv2").addEventListener("click", function() {
alert("你点击了 DIV2 元素 !");
}, true);
</script>
</body>

removeEventListener() 方法

removeEventListener() 方法移除由 addEventListener() 方法添加的事件句柄:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>薯条的测试</title>
<style>
#myDIV {
background-color: coral;
border: 1px solid;
padding: 50px;
color: white;
}
</style>
</head>
<body>
<h1>开始测试</h1>
<div id="myDIV"> div 元素添加了 onmousemove 事件句柄,鼠标在桔红色的框内移动时会显示随机数。
<p>点击按钮移除 DIV 的事件句柄。</p>
<button onclick="removeHandler()" id="myBtn">点我</button>
</div>
<p id="demo"></p>
<script>
document.getElementById("myDIV").addEventListener("mousemove", myFunction);
function myFunction() {
document.getElementById("demo").innerHTML = Math.random();
}
function removeHandler() {
document.getElementById("myDIV").removeEventListener("mousemove", myFunction);
}
</script>
</body>
</html>

DOM元素(节点)

如何向文档中添加和移除元素

创建新的 HTML 元素 (节点) - appendChild()

1
2
3
4
5
6
7
8
9
10
11
<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");
element.appendChild(para);
</script>

解析:这行代码是用于创建

元素:var para = document.createElement("p");

元素创建一个新的文本节点:var node = document.createTextNode("这是一个新的段落。");

将文本节点添加到

元素中:para.appendChild(node);

最后,在一个已存在的元素中添加 p 元素。

查找已存在的元素:var element = document.getElementById("div1");

添加到已存在的元素中:element.appendChild(para);

创建新的 HTML 元素 (节点) - insertBefore()

appendChild() 方法:它用于添加新元素到尾部

insertBefore() 方法:将新元素添加到开始位置

1
2
3
4
5
6
7
HTML代码跟appendChild()方法里面的代码一致,js代码如下所示:
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);//新元素插到child元素之前

移除已存在的元素

要移除之前我们必须知道该元素的父元素

1
2
3
4
5
6
7
8
9
10
<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);
parent.parentNode.removeChild(parent);
</script>

parent.parentNode.removeChild(parent);parentNode 是一个 DOM 属性,它指向节点的父节点。在这个特定的代码中,parent 是一个通过 document.getElementById("div1") 获取到的 <div> 元素,因此 parent.parentNode 就是 <div> 元素的父节点

替换元素-replaceChild()

用 replaceChild() 方法来替换 HTML DOM 中的元素

1
2
3
4
5
6
7
8
<script>
var para = document.createElement("p");
var node = document.createTextNode("这是一个新的段落。");
para.appendChild(node);
var parent = document.getElementById("div1");
var child = document.getElementById("p1");
parent.replaceChild(para, child);
</script>

集合(Collection)

getElementsByTagName() 方法返回 HTMLCollection 对象。

HTMLCollection 对象类似包含 HTML 元素的一个数组。

集合中的元素可以通过索引(以 0 为起始位置)来访问

1
2
3
4
5
6
7
8
<p>MNC</p>
<p>曼城</p>
<p id="demo"></p>
<script>
let myCollection=document.getElementsByTagName("p");//myCollection为HTMLCollection 对象
let a=myCollection[1].innerHTML; // 使用 textContent 获取文本内容
document.getElementById("demo").innerHTML=`第二个段落是${a}`;
</script>

HTMLCollection 对象的 length 属性定义了集合中元素的数量,例子如下:

1
在上述js代码后面再加上:document.getElementById("demo").innerHTML = "文档包含" + myCollection.length + " 个段落。";

集合 length 属性常用于遍历集合中的元素

1
2
3
4
5
var myCollection = document.getElementsByTagName("p");
var i;
for (i = 0; i < myCollection.length; i++) {
myCollection[i].style.backgroundColor = "red";
}

NodeList对象

NodeList 对象是一个从文档中获取的节点列表 (集合) ,类似 HTMLCollection 对象,用法也与它差不多

所有浏览器的 childNodes 属性返回的是 NodeList 对象。

大部分浏览器的 querySelectorAll() 返回 NodeList 对象。

1
var myNodelist = document.querySelectorAll("p");

浏览器对象模型 (BOM)

window

所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员。

全局变量是 window 对象的属性。

全局函数是 window 对象的方法。

window尺寸

有三种方法能够确定浏览器窗口的尺寸。

对于Internet Explorer、Chrome、Firefox、Opera 以及 Safari:

  • window.innerHeight - 浏览器窗口的内部高度(包括滚动条)
  • window.innerWidth - 浏览器窗口的内部宽度(包括滚动条)

对于 Internet Explorer 8、7、6、5:

  • document.documentElement.clientHeight
  • document.documentElement.clientWidth

或者

  • document.body.clientHeight
  • document.body.clientWidth
1
2
3
4
5
6
7
8
9
10
<script>
let w=window.innerWidth
||document.documentElement.clientWidth
||document.body.clientWidth;
let h=window.innerHeight
||document.documentElement.clientHeight
||document.body.clientHeight;
let x=document.getElementById("demo");
x.innerHTML=`浏览器宽度为${w},高度为${h}。`
</script>

window的其他一些方法:

  • window.open() - 打开新窗口
  • window.close() - 关闭当前窗口
  • window.moveTo() - 移动当前窗口
  • window.resizeTo() - 调整当前窗口的尺寸

Window Screen

window.screen 对象包含有关用户屏幕的信息

window.screen对象在编写时可以不使用 window 这个前缀。

一些属性:

  • screen.availWidth - 返回访问者屏幕的宽度,以像素计,减去界面特性,比如窗口任务栏document.write("可用宽度: " + screen.availWidth);
  • screen.availHeight - 返回访问者屏幕的高度,以像素计,减去界面特性,比如窗口任务栏 document.write("可用高度: " + screen.availHeight);

Window Location

window.location 对象在编写时可不使用 window 这个前缀。 一些例子:

一些实例:

  • location.hostname 返回 web 主机的域名
  • location.pathname 返回当前页面的路径和文件名:document.write(location.pathname);
  • location.port 返回 web 主机的端口 (80 或 443)
  • location.protocol 返回所使用的 web 协议(http: 或 https:)

location.href 属性返回当前页面的 URL。实例如下:

1
document.write(location.href);//返回完整的URL

location.assign() 方法加载新的文档。实例如下:

1
2
3
4
5
6
<script>
function newDoc(){
window.location.assign("https://www.runoob.com")
}
</script>
<input type="button" value="加载新文档" onclick="newDoc()">

Window history

window.history对象在编写时可不使用 window 这个前缀。

一些方法:

  • history.back() - 与在浏览器点击后退按钮相同
1
2
3
4
5
6
7
<script>
function goBack()
{
window.history.back()
}
</script>
<input type="button" value="Back" onclick="goBack()">
  • history.forward() - 与在浏览器中点击向前按钮相同:起作用的前提是你处于的不是最新界面

Window Navigator

window.navigator 对象包含有关访问者浏览器的信息,下面实例里面有几个弃用的,可以找到更好的替代

1
2
3
4
5
6
7
8
9
10
11
<div id="example"></div>
<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>

弹窗

弹窗使用 反斜杠 + “n”(\n) 来设置换行:alert("Hello\nHow are you?");

警告窗

警告框经常用于确保用户可以得到某些信息。 alert("你好,我是一个警告框!");

当警告框出现后,用户需要点击确定按钮才能继续进行操作。

确认窗

确认框通常用于验证是否接受用户操作:window.confirm("sometext");wnidow.可加可不加

当确认框弹出时,用户可以点击 “确认” 或者 “取消” 来确定用户操作。

当你点击 “确认”, 确认框返回 true, 如果点击 “取消”, 确认框返回 false

1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
function myFunction(){
var x;
var r=confirm("按下按钮!");
if (r==true){
x="你按下了\"确定\"按钮!";
}
else{
x="你按下了\"取消\"按钮!";
}
document.getElementById("demo").innerHTML=x;
}
</script>

提示框

提示框经常用于提示用户在进入页面前输入某个值:window.prompt("sometext","defaultvalue");后面那个相当于预填充的值

当提示框出现后,用户需要输入某个值,然后点击确认或取消按钮才能继续操纵。

如果用户点击确认,那么返回值为输入的值。如果用户点击取消,那么返回值为 null。

1
2
3
4
5
6
7
8
9
10
<script>
function myFunction(){
var x;
var person=prompt("请输入你的名字","Harry Potter");
if (person!=null && person!=""){
x="你好 " + person + "! 今天感觉如何?";
document.getElementById("demo").innerHTML=x;
}
}
</script>

计时事件

通过使用 JavaScript,我们有能力做到在一个设定的时间间隔之后来执行代码,而不是在函数被调用后立即执行。我们称之为计时事件。

setInterval() 方法

setInterval() 间隔指定的毫秒数不停地执行指定的代码:setInterval("javascript function",milliseconds);

setInterval() 第一个参数是函数(function),第二个参数间隔的毫秒数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//3秒弹出一个"hello"警告窗
function myFunction(){
setInterval(function(){alert("Hello")},3000);
}
//显示时钟,并停止
<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>

clearInterval() 方法用于停止 setInterval() 方法执行的函数代码:clearInterval(intervalVariable)

要使用 clearInterval() 方法, 在创建计时方法时你必须使用全局变量myVar=setInterval("javascriptfunction",milliseconds);

然后你可以使用 clearInterval() 方法来停止执行:clearInterval(myVar);

setTimeout()方法

具体知识在上面的“异步编程”一节中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<body>
<script>
function timedText(){
var x=document.getElementById('txt');
var t1=setTimeout(function(){x.value="2 秒"},2000);
var t2=setTimeout(function(){x.value="4 秒"},4000);
var t3=setTimeout(function(){x.value="6 秒"},6000);
}
</script>
<form>
<input type="button" value="显示文本时间!" onclick="timedText()" />
<input type="text" id="txt" />
</form>
<p>点击上面的按钮,输出的文本将告诉你2秒,4秒,6秒已经过去了。</p>
</body>

clearTimeout() 方法用于停止执行setTimeout()方法的函数代码

要使用clearTimeout() 方法, 你必须在创建超时方法中(setTimeout)使用全局变量:

JavaScript 可以使用 document.cookie 属性来创建 、读取、及删除 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=/";

读取cookie

1
格式:var x = document.cookie;

document.cookie 将以字符串的方式返回所有的 cookie,类型格式: cookie1=value; cookie2=value; cookie3=value;

修改cookie

在 JavaScript 中,修改 cookie 类似于创建 cookie,如下所示:

1
document.cookie="username=John Smith; expires=Thu, 18 Dec 2043 12:00:00 GMT; path=/";

旧的 cookie 将被覆盖。

删除cookie

删除 cookie 非常简单。您只需要设置 expires 参数为以前的时间即可,如下所示,设置为 Thu, 01 Jan 1970 00:00:00 GMT:

1
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT";

注意,当您删除时不必指定 cookie 的值。

一个关于cookie的完整实例

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<head>
<script>
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;
}//cookie 的名称为 cname,cookie 的值为 cvalue,并设置了 cookie 的过期时间 expires

function getCookie(cname){//cookie 名的参数为 cname
var name = cname + "=";//创建一个文本变量用于检索指定 cookie
var ca = document.cookie.split(';');//使用分号来分割 document.cookie 字符串,并将分割后的字符串数组赋值给 ca
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); }
}//循环 ca 数组 (i=0;i<ca.length;i++),然后读取数组中的每个值,并去除前后空格 (c=ca[i].trim())
return "";
}//如果找到 cookie(c.indexOf(name) == 0),返回 cookie 的值;没有找到 cookie, 返回 ""

function checkCookie(){
var user=getCookie("username");
if (user!=""){
alert("欢迎 " + user + " 再次访问");
}
else {
user = prompt("请输入你的名字:","");
if (user!="" && user!=null){
setCookie("username",user,30);
}
}
}
如果设置了 cookie,将显示一个问候信息。
如果没有设置 cookie,将会显示一个弹窗用于询问访问者的名字,并调用 setCookie 函数将访问者的名字存储 365 天
</script>
</head>
<body onload="checkCookie()"></body>
</html>

这里使用 substring() 方法获取从名称长度到字符串末尾的子字符串,即获取了指定名称的 cookie 的值,并将其返回。

其他

网页上显示一个钟表

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<script>
function startTime(){
var today=new Date();
var h=today.getHours();
var m=today.getMinutes();
var s=today.getSeconds();// 在小于10的数字前加一个‘0’
m=checkTime(m);
s=checkTime(s);
document.getElementById('txt').innerHTML=h+":"+m+":"+s;
t=setTimeout(function(){startTime()},500);
}
function checkTime(i){
if (i<10){
i="0" + i;
}
return i;
}
</script>
</head>
<body onload="startTime()">
<div id="txt"></div>
</body>
</html>

不止以上这一种方法