JavaScript笔记03
流程控制
if 判断
- 和 Java 中
if
语句的使用方法相同。 - 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
let score = 90;
if (score === 100) { // 第一个判断
alert("great");
} else if (score >= 60 && score < 100) { // 第二个判断
alert("pass");
} else { // 否则...
alert("fail");
}
</script>
</head>
<body>
</body>
</html>
- 查看浏览器弹窗:
while 循环
- 和 Java 中
while
循环语句的使用方法相同。 - 注意:避免使用死循环。
- 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
let age = 0;
while (age < 100) {
age = age + 1;
console.log(age);
}
</script>
</head>
<body>
</body>
</html>
- 查看浏览器控制台:
- 补充:
do...while...
循环:
"use strict";
let age = 0;
do {
age = age + 1;
console.log(age);
} while (age < 100);
for 循环
- 和 Java 中
for
循环语句的使用方法相同。 - 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
for (let i = 0; i < 100; i++) {
console.log(i);
}
</script>
</head>
<body>
</body>
</html>
- 查看浏览器控制台:
forEach 循环
-
forEach()
的使用方法参考:JavaScript Array forEach() 方法 -
在 JavaScript 中,我们可以使用
forEach()
函数循环遍历数组中的元素。(ES 5.1) -
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
let fruits = ["apple", "banana", "watermelon", "pear", "strawberry"];
fruits.forEach(function (value) {
console.log(value);
});
</script>
</head>
<body>
</body>
</html>
- 查看浏览器控制台:
for…in 循环
for...in
的使用方法参考:JavaScript For In- 除了
forEach()
方法,在 JavaScript 中,我们还可以使用for...in
语句来循环遍历数组中的元素。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
let fruits = ["apple", "banana", "watermelon", "pear", "strawberry"];
for (let index in fruits) {
console.log(fruits[index])
}
</script>
</head>
<body>
</body>
</html>
- 查看浏览器控制台:
- 我们也可以使用
for...in
语句来循环遍历对象的属性。 - 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
let person = {
name: "张三",
age: 18,
gender: "男",
hobby: "打篮球"
}
for (let key in person) {
console.log(person[key])
}
</script>
</head>
<body>
</body>
</html>
- 查看浏览器控制台:
for…of 循环
-
for...of
语句也能遍历数组。使用方法参考:JavaScript For Of -
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
let fruits = ["apple", "banana", "watermelon", "pear", "strawberry"];
for (let fruit of fruits) {
console.log(fruit)
}
</script>
</head>
<body>
</body>
</html>
- 查看浏览器控制台:
集合 - Map 和 Set
- ES6 的新特性~
Map
Map
对象是键值对的集合。- 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
// Map和Set ES6+
// 学生的名字,学生的成绩
// let names = ["Tom", "Jerry", "Spike"];
// let score = [100,90,80];
// 创建Map对象 - 保存键值对,并且能够记住键的原始插入顺序
let map = new Map([["Tom", 100], ["Jerry", 90], ["Spike", 80]]);
// get() - 通过key获得value
let score1 = map.get("Tom");
console.log(score1);
// set() - 为Map对象添加或修改一个键值对
map.set("Tuffy", 60); // 添加
console.log(map);
map.set("Jerry", 95); // 修改
console.log(map);
// delete() - 删除键值对
map.delete("Spike");
console.log(map);
</script>
</head>
<body>
</body>
</html>
- 查看浏览器控制台:
Set
Set
对象是值的集合。Set
集合中的元素只会出现一次,即集合中的元素是唯一的(可以去重~)。- 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
// 创建Set对象 - 保存值,并且集合中的元素不重复,有序
let set = new Set([1, 1, 1, 1, 3, 4, 4, 4]);
console.log(set);
// add() - 添加元素
set.add(2);
console.log(set);
// delete() - 删除元素
set.delete(1);
console.log(set);
// has() - 判断Set对象是否包含某个元素
console.log(set.has(3));
</script>
</head>
<body>
</body>
</html>
- 查看浏览器控制台:
iterator
- 使用
for...of
语句来遍历Map
和Set
集合对象。(ES 6+)
遍历Map对象
- 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
let map = new Map([["Tom", 100], ["Jerry", 90], ["Spike", 80]]);
for (let student of map) {
console.log(student);
}
</script>
</head>
<body>
</body>
</html>
- 查看浏览器控制台:
遍历Set对象
- 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
let set = new Set([1, 1, 1, 1, 3, 4, 4, 4]);
for (let num of set) {
console.log(num);
}
</script>
</head>
<body>
</body>
</html>
- 查看浏览器控制台:
函数
- 函数是 JavaScript 中的基本组件之一,它是一组可以随时随地运行的语句。 当一个函数是一个对象的属性时,称之为方法。
定义函数
- 使用
function
关键字来定义函数。
定义方式一
- 定义一个取绝对值函数:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
</script>
</head>
<body>
</body>
</html>
- 一旦执行到
retrun
,函数就将停止执行,返回结果。 - 打开浏览器控制台,使用我们刚才定义的取绝对值函数
abs()
,分别传入一个正数和一个负数,查看结果:
- 补充:如果函数无明确的返回值,或调用了没有参数的
return
语句, 那么它的返回值为:undefined
。
定义方式二
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
// 匿名函数 - 没有函数名。
// 将结果赋值给变量abs,通过abs就可以调用该匿名函数!
let abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
</script>
</head>
<body>
</body>
</html>
- 打开浏览器控制台,向函数
abs()
中分别传入一个正数和一个负数,查看结果:
- 可以发现使用这两种方式来定义函数的效果是一样的。
参数问题
- 参数问题:JavaScript 可以传任意个参数,也可以不传递参数~
- 例:
- 我们打开浏览器控制台,向之前定义的取绝对值函数
abs()
中分别传入多个参数和不传递参数,查看结果:
- 我们打开浏览器控制台,向之前定义的取绝对值函数
- 可以看到程序依旧成功执行了,且并没有报错或提示出现异常。规避参数不存在的问题
规避参数不存在的问题
- 我们可以通过手动判断并抛出异常的方式来规避参数不存在的问题。
- 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
let abs = function (x) {
// 手动抛出异常
if (typeof x != "number") { // typeof - 返回一个字符串,表示操作数的类型
throw "Not a Number";
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
</script>
</head>
<body>
</body>
</html>
- 打开浏览器控制台,不向函数
abs()
中传递任何参数,查看结果:
- 可以看到程序提示了我们手动定义的异常
Not a Number
。
arguments
arguments
是一个对应于传递给函数的参数的类数组对象。它代表传递进函数的所有参数,是一个数组。参考:Arguments 对象 - JavaScript- 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
let abs = function (x) {
console.log("x=>"+x);
for (let i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
</script>
</head>
<body>
</body>
</html>
- 打开浏览器控制台,给
abs()
函数传入多个参数,查看结果:
剩余参数 - rest
- 剩余参数语法允许我们将一个不定数量的参数表示为一个数组。 (ES 6+)
- 剩余参数只能写在所有参数的最后面,用
...
标识。 - 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
let aaa = function (x, y, ...rest) {
console.log("x=>" + x);
console.log("y=>" + y);
console.log("rest=>" + rest);
}
</script>
</head>
<body>
</body>
</html>
- 打开浏览器控制台,给
aaa()
函数传入分别传入一个,两个以及多个参数,查看结果:
变量的作用域
- 在 JavaScript 中,
var
定义的变量实际是有作用域的。
局部变量
- 语句块中声明的变量将成为语句块所在函数的局部变量。
- 假设在函数体中声明,则在函数体外不可以使用 ~( 如果非要在函数体外引用的话,需要使用 闭包)
- 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
function abc() {
var x = 1;
x = x + 1;
}
x = x + 2; // Uncaught ReferenceError: x is not defined
</script>
</head>
<body>
</body>
</html>
- 打开浏览器控制台,发现程序报错:
Uncaught ReferenceError: x is not defined
- 如果两个函数使用了相同的变量名,只要都在函数内,就不冲突。
- 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
function abc() {
var x = 1;
x = x + 1;
}
function xyz() {
var x = 10086;
x = x + 1;
}
</script>
</head>
<body>
</body>
</html>
- 函数
abc()
和函数xyz()
都使用了x
作为变量名,但都在函数体内,所以两者的变量名不会发生冲突,程序能够正常运行,不会报错。 - 内部函数可以访问外部函数的成员,反之则不行。
- 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
function abc() {
var x = 1;
function xyz() {
var y = x + 1; // 2
}
var z = y + 1; // Uncaught ReferenceError: z is not defined
}
</script>
</head>
<body>
</body>
</html>
- 打开浏览器控制台,输入
console.log(z);
,查看结果:
- 假设内部函数和外部函数的变量重名。
- 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
function abc() {
var x = 1;
function xyz() {
var x = "A";
console.log("inner => " + x);
}
console.log("outer => " + x);
xyz(); // inner => A
}
abc(); // outer => 1
</script>
</head>
<body>
</body>
</html>
- 打开浏览器控制台,查看结果:
- 在 JavaScript 中,函数会从自身开始,由内向外查找变量,假设外部存在这个同名的函数变量,则内部函数会屏蔽外部函数的变量(双亲委派机制)。
提示变量的作用域
- 我们先来看以下代码:
- 我们将需要调用变量
y
的语句写在变量y
的声明与赋值语句之前:
- 我们将需要调用变量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
function abc() {
var x = "x" + y;
console.log(x);
var y = "y";
}
abc(); // xundefined
</script>
</head>
<body>
</body>
</html>
- 打开浏览器控制台,查看结果:
- 原因:JavaScript 的执行引擎自动提升了变量
y
的声明,但却不会提升变量y
的赋值。这是在 JavaScript 建立之初就存在的特性。 - 由于 JavaScript 存在以上的特性,所以我们在编码过程中要规范书写顺序,用到的变量必须是前面定义过的,不要乱放,以便代码维护。
- 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
function xyz() {
var x = 10,
y = 3,
z,i; // undefined
z = x + y;
i = x - y;
console.log(z);
console.log(i);
}
xyz();
</script>
</head>
<body>
</body>
</html>
- 打开浏览器控制台,查看结果:
全局变量
- 在函数之外声明的变量,叫做全局变量,它可被当前文档中的任何其他代码所访问。
- 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
var x = 1;
function f() {
console.log(x);
}
f();
console.log(x);
</script>
</head>
<body>
</body>
</html>
- 打开浏览器控制台,查看结果:
全局对象 - window
window
对象表示一个浏览器窗口或一个框架。在 JavaScript 中,window
对象是全局对象,所有的表达式都在当前的环境中计算。 也就是说在 JavaScript 中,默认所有的全局变量都会自动绑定在window
对象下。(函数本身也可以是变量)- 例如:我们常用的弹窗函数
alert()
就可以写成window.alert()
;同样的,我们定义的全局变量x
也可以写作window.x
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
var x = 1;
// 以下三种写法的表示的效果是相同的
alert(x);
window.alert(x);
window.alert(window.x);
</script>
</head>
<body>
</body>
</html>
- 这三种写法的表示的效果是相同的:
- 大胆尝试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
"use strict";
var x = "xxx";
window.alert(x);
var old_alert = window.alert;
// old_alert(x);
window.alert = function () {
};
// 发现alert()失效了
window.alert(123);
// 恢复
window.alert = window.old_alert;
window.alert(456);
</script>
</head>
<body>
</body>
</html>
- 以上尝试说明了 JavaScript 实际上只有一个全局作用域(
window
),任何变量(函数本身也可以作为变量),假设在函数作用范围内没有找到,就会向外查找。如果在全局作用域(window
)中都没有找到,那么就会报错:ReferenceError
(引用异常)。 - 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
window.alert(x);
</script>
</head>
<body>
</body>
</html>
- 打开浏览器控制台,查看结果:
规范
- 由于在 JavaScript 中,我们所有的全局变量都会绑定到
window
对象上。所以如果我们的项目中同时存在多个 js 文件,且它们之中使用了同名的全局变量,就会产生冲突。那么,我们应该如何减少这样的冲突呢? - 我们可以自己定义一个唯一全局变量来代替
window
对象,把自己的代码全部放进自己定义的唯一的空间名字中,通过这种方式来减少全局命名冲突的问题( jQuery 就是使用的这种方式 )。例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
// 唯一全局变量
var MyApp = {};
// 定义全局变量
MyApp.name = "clown";
MyApp.add = function (a, b) {
return a + b;
}
</script>
</head>
<body>
</body>
</html>
局部作用域 - let
- 我们先来看一个例子 - 在
for
循环体中使用var
定义变量,然后我们再在循环体外调用这个变量:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
function aaa() {
for (var i = 0; i < 100; i++) {
console.log(i);
}
console.log(i + 1);
}
aaa();
</script>
</head>
<body>
</body>
</html>
- 打开浏览器控制台,查看结果:
- 我们发现,使用
var
定义变量时,即使除了循环体,我们也能调用到在循环体中定于的变量。这就说明发生了作用域冲突问题。 - 为了解决作用域冲突这一问题,于是在 ES 6 就新推出了一个关键字:
let
。通过它,就能解决作用域冲突问题。它和var
的区别在于:var
定义的变量在其所在的整个函数体内都是可以被调用的,而let
定义的变量只在其所在的语句块里可以被调用。 - 下面我们把上面代码中的
var
改为let
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
function aaa() {
for (let i = 0; i < 100; i++) {
console.log(i);
}
console.log(i + 1); // Uncaught ReferenceError: i is not defined
}
aaa();
</script>
</head>
<body>
</body>
</html>
- 打开浏览器控制台,查看结果:
- 我们发现:在使用
let
定义循环体中的变量之后,循环体外的语句便不能再调用它了,作用域冲突问题得到了解决。 - 所以,建议在编程过程中都使用
let
来定义局部作用域中的变量。
常量 - const
- 和
let
一样,const
也是 ES 6 推出的新特性。 - 在 ES 6 推出之前,常量的定义方式:变量名的字母全部为大写字母的变量就代表常量(通过这种方法定义的 “常量” 本质上还是一个变量,它的值是可以被修改的)。所以如果我们在工作过程中见到了这样的变量名全部定义为大写的变量,建议不要去随意修改它的值,因为很可能它表示的是一个常量。
- 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
// 在 ES6 推出之前,约定俗成,名字全部用大写字母表示的变量,就代表它为常量
var PI = 3.14;
PI = 2;
console.log(PI); // 这样定义的常量的值其实是可以被改变的
</script>
</head>
<body>
</body>
</html>
- 打开浏览器控制台,查看结果:
- 所以,为了解决上述问题,规范编码,在 ES 6 中就推出了关键字 -
const
,用来定义常量(只读变量)。 - 例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
// 在 ES6 推出了 const 关键字,用来定义只读变量(常量)
const PI = 3.14;
PI = 2; // Uncaught TypeError: Assignment to constant variable.
console.log(PI);
</script>
</head>
<body>
</body>
</html>
- 我们可以发现 IDEA 会报错并提示我们该变量值是只读的,不允许修改:
- 运行:发现程序报错:
Uncaught TypeError: Assignment to constant variable.