基本语法格式
条件表达式为true,则执行if的{}中的代码。
// 形式1 if (条件) { 语句 } // 形式2 if (条件) { 语句1 } else { 语句2 } // 形式3 if (条件1) { 语句1 } else if (条件2) { 语句2 } else if .... { 语句... } else { 语句N }
练习案例
代码示例1:判定一个数字是奇数还是偶数。
var num = 10;
if (num % 2 == 0) {
console.log("num 是偶数");
}
else {
console.log("num 是奇数");
}
注意:
不能写成num % 2 == 1就是奇数。负的奇数 % 2结果可能是-1。
代码示例2:判定一个数字是正数还是负数。
var num = 10;
if (num > 0) {
console.log("num 是正数");
}
else if (num < 0) {
console.log("num 是负数");
}
else {
console.log("num 是 0");
}
代码示例3:判定某一年份是否为闰年。
var year = 2000;
if (year % 100 == 0) {
// 判定世纪闰年
if (year % 400 == 0) {
console.log("是闰年");
}
else {
console.log("不是闰年");
}
}
else {
// 普通闰年
if (year % 4 == 0) {
console.log("是闰年");
}
else {
console.log("不是闰年");
}
}
三元表达式
是if else的简化写法。
条件 ? 表达式1 : 表达式2
条件为真,返回表达式1的值。条件为假,返回表达式2的值。
注意:
三元表达式的优先级是比较低的。
更适合多分支的场景。
switch (表达式) { case 值1: 语句1; break; case 值2: 语句2; break; default: 语句N; }
练习案例
代码示例1:用户输入一个整数,提示今天是星期几。
var day = prompt("请输入今天星期几: ");
switch (parseInt(day)) {
case 1:
console.log("星期一");
break;
case 2:
console.log("星期二");
break;
case 3:
console.log("星期三");
break;
case 4:
console.log("星期四");
break;
case 5:
console.log("星期五");
break;
case 6:
console.log("星期六");
break;
case 7:
console.log("星期日");
break;
default:
console.log("输入有误");
}
重复执行某些语句。
while (条件) { 循环体; }
执行过程:
练习案例
代码示例1:打印1-10。
var num = 1;
while (num <= 10) {
console.log(num);
num++;
}
代码示例2:计算5的阶乘。
var result = 1;
var i = 1;
while (i <= 5) {
result *= i;
i++;
}
console.log(result)
结束这次循环。
练习案例
代码示例1: 吃五个李子,发现第三个李子里有一只虫子,于是扔掉这个,继续吃下一个李子。
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="style.js"></script>
</body>
</html>
style.js
var i = 1;
while (i <= 5) {
if (i == 3) {
i++;
continue;
}
console.log("我在吃第" + i + "个李子");
i++;
}
展示结果:
代码示例2:找到100-200中所有3的倍数。
var num = 100;
while (num <= 200) {
if (num % 3 != 0) {
num++; // 这里的 ++ 不要忘记! 否则会死循环.
continue;
}
console.log("找到了 3 的倍数, 为:" + num);
num++;
}
结束整个循环。
练习案例
代码示例1:吃五个李子,发现第三个李子里有虫子,于是剩下的也不吃了。
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="style.js"></script>
</body>
</html>
style.js
var i = 1;
while (i <= 5) {
if (i == 3) {
break;
}
console.log("我在吃第" + i + "个李子");
i++;
}
展示结果:
代码示例2:找到100-200中第一个3的倍数。
var num = 100;
while (num <= 200) {
if (num % 3 == 0) {
console.log("找到了 3 的倍数, 为:" + num);
break;
}
num++;
}
for (表达式1; 表达式2; 表达式3) { 循环体 }
执行过程:
练习案例
代码示例1:打印数字1-10。
for (var num = 1; num <= 10; num++) {
console.log(num);
}
代码示例2:计算5的阶乘。
var result = 0;
for (var i = 1; i <= 5; i++) {
result *= i;
}
console.log("result = " + result);
使用new关键字创建。
// Array 的 A 要大写 var arr = new Array();
使用字面量方式创建。
var arr = [];
var arr2 = [1, 2, 'One Piece', false]; // 数组中保存的内容称为 "元素"
注意:
JS的数组不要求元素是相同类型。
这点和C/C++、Java等静态类型的语言差别很大。但是Python、PHP等动态类型语言也是如此。
使用下标的方式访问数组元素(从0开始)。
var arr = ['路飞太郎', '索隆十郎', '山五郎'];
console.log(arr);
console.log(arr[0]);
console.log(arr[1]);
console.log(arr[2]);
arr[2] = '海侠甚平';
console.log(arr);
如果下标超出范围读取元素,则结果为undefined。
console.log(arr[3]); // undefined
console.log(arr[-1]); // undefined
注意:
不要给数组名直接赋值,此时数组中的所有元素都没了。
相当于本来arr是一个数组,重新赋值后变成字符串了。
var arr = ['路飞太郎', '索隆十郎', '山五郎'];
arr = '海侠甚平';
1. 通过修改length新增
相当于在末尾新增元素。新增的元素默认值为undefined。
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="style.js"></script>
</body>
</html>
style.js
var arr = [9, 5, 2, 7];
arr.length = 6;
console.log(arr);
console.log(arr[4], arr[5]);
展示结果:
2. 通过下标新增
如果下标超出范围赋值元素,则会给指定位置插入新元素。
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="style.js"></script>
</body>
</html>
style.js
var arr = [];
arr[2] = 10;
console.log(arr);
展示结果:
3. 使用push进行追加元素
代码示例1:给定一个数组,把数组中的奇数放到一个newArr中。
var arr = [9, 5, 2, 7, 3, 6, 8];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] % 2 != 0) {
newArr.push(arr[i]);
}
}
console.log(newArr);
使用splice方法删除元素。
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="style.js"></script>
</body>
</html>
style.js
var arr = [9, 5, 2, 7];
// 第一个参数表示从下表为 2 的位置开始删除. 第二个参数表示要删除的元素个数是 1 个
arr.splice(2, 1);
console.log(arr);
展示结果:
注意:
// 创建函数/函数声明/函数定义 function 函数名(形参列表) { 函数体 return 返回值; } // 函数调用 函数名(实参列表) // 不考虑返回值 返回值 = 函数名(实参列表) // 考虑返回值
function hello() {
console.log("hello");
}
// 如果不调用函数, 则没有执行打印语句
hello();
// 调用函数
hello();
// 定义函数
function hello() {
console.log("hello");
}
实参和形参之间的个数可以不匹配。但是实际开发一般要求形参和实参个数要匹配。
1. 如果实参个数比形参个数多,则多出的参数不参与函数运算。
sum(10, 20, 30); // 30
2. 如果实参个数比形参个数少,则此时多出来的形参值为undefined。
sum(10); // NaN, 相当于 num2 为 undefined.
JS的函数传参比较灵活,这一点和其他语言差别较大。事实上这种灵活性往往不是好事。
另外一种函数的定义方式。
var add = function() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
console.log(add(10, 20)); // 30
console.log(add(1, 2, 3, 4)); // 10
console.log(typeof add); // function
此时形如function(){ }这样的写法定义了一个匿名函数,然后将这个匿名函数用一个变量来表示。
后面就可以通过这个add变量来调用函数了。
JS中函数是一等公民,可以用变量保存,也可以作为其他函数的参数或者返回值。
某个标识符名字在代码中的有效范围。
在ES6标准之前,作用域主要分成两个:
// 全局变量
var num = 10;
console.log(num);
function test() {
// 局部变量
var num = 20;
console.log(num);
}
function test2() {
// 局部变量
var num = 30;
console.log(num);
}
test();
test2();
console.log(num);
创建变量时如果不写var,则得到一个全局变量。
function test() {
num = 100;
}
test();
console.log(num);
另外,很多语言的局部变量作用域是按照代码块(大括号)来划分的,JS在ES6之前不是这样的。
if (1 < 2) {
var a = 10;
}
console.log(a);
背景:
内部函数可以访问外部函数的变量。采取的是链式查找的方式。从内到外依次进行查找。
var num = 1;
function test1() {
var num = 10;
function test2() {
var num = 20;
console.log(num);
}
test2();
}
test1();
执行console.log(num)的时候,会现在test2的局部作用域中查找num。如果没找到,则继续去test1中查找。如果还没找到,就去全局作用域查找。
对象是指一个具体的事物。
"电脑"不是对象,而是一个泛指的类别。而"我的联想笔记本"就是一个对象。
在JS中,字符串、数值、数组、函数都是对象。
每个对象中包含若干的属性和方法。
对象需要保存的属性有多个,虽然数组也能用于保存多个数据,但是不够好。
例如表示一个学生信息。(姓名路飞太郎,身高180cm,体重170斤) var student = ['路飞太郎', 180, 170]; 但是这种情况下到底180和170谁表示身高,谁表示体重,就容易分不清。
JavaScript的对象和Java的对象概念上基本一致。只是具体的语法表项形式差别较大。
使用{}创建对象。
var a = {}; // 创建了一个空的对象
var student = {
name: '路飞太郎',
height: 180,
weight: 170,
sayHello: function() {
console.log("One Piece");
}
};
使用对象的属性和方法:
// 1. 使用 . 成员访问运算符来访问属性 `.` 可以理解成 "的"
console.log(student.name);
// 2. 使用 [ ] 访问属性, 此时属性需要加上引号
console.log(student['height']);
// 3. 调用方法, 别忘记加上 ()
student.sayHello();
var student = new Object(); // 和创建数组类似
student.name = "路飞太郎";
student.height = 180;
student['weight'] = 170;
student.sayHello = function () {
console.log("One Piece");
}
console.log(student.name);
console.log(student['weight']);
student.sayHello();
注意:
使用{ }创建的对象也可以随时使用student.name = "路飞太郎"; 这样的方式来新增属性。
前面的创建对象方式只能创建一个对象。而使用构造函数可以很方便的创建多个对象。
例如:创建几个猫咪对象。
var yun = {
name: "云云",
type: "布偶猫",
miao: function () {
console.log("喵");
}
};
var tang = {
name: "汤圆",
type: "金渐层",
miao: function () {
console.log("猫呜");
}
}
var po = {
name: "破破",
type: "拿破仑",
miao: function () {
console.log("咕噜噜");
}
}
此时写起来就比较麻烦。使用构造函数可以把相同的属性和方法的创建提取出来,简化开发过程。
基本语法
function 构造函数名(形参) { this.属性 = 值; this.方法 = function... } var obj = new 构造函数名(实参);
注意:
this相当于”我“。
使用构造函数重新创建猫咪对象。
function Cat(name, type, sound) {
this.name = name;
this.type = type;
this.miao = function () {
console.log(sound); // 别忘了作用域的链式访问规则
}
}
var yun = new Cat('云云', '布偶猫', '喵');
var tang = new Cat('汤圆', '汤圆', '猫呜');
var po = new Cat('破破', '拿破仑', '咕噜噜');
console.log(yun);
yun.miao();
new的执行过程:
1. JavaScript没有“类”的概念
对象其实就是"属性" + "方法"。
类相当于把一些具有共性的对象的属性和方法单独提取了出来,相当于一个"月饼模子"。
在JavaScript中的"构造函数"也能起到类似的效果。
而且即使不是用构造函数,也可以随时的通过{ }的方式指定出一些对象。
在ES6中也引入了class关键字,就能按照类似于Java的方式创建类和对象了。
2. JavaScript对象不区分"属性"和"方法"
JavaScript中的函数是"一等公民",和普通的变量一样。存储了函数的变量能够通过( )来进行调用执行。
3. JavaScript对象没有private / public等访问控制机制。
对象中的属性都可以被外界随意访问。
4. JavaScript对象没有"继承"。
继承本质就是"让两个对象建立关联"。或者说是让一个对象能够重用另一个对象的属性/方法。
JavaScript中使用"原型"机制实现类似的效果。
例如:创建一个Cat对象和Dog对象,让这两个对象都能使用animal对象中的eat方法。
通过 __proto__ 属性来建立这种关联关系(proto翻译作“原型”)。
var Dog = {
name: "dog",
__proto__: animal //指向animal对象
};
var Cat = {
name: "cat",
__proto__: animal //指向animal对象
}
Dog.eat(); //dog is eating
Cat.eat(); //cat is eating
当eat方法被调用的时候,先在自己的方法列表中寻找,如果找不到,就去找原型中的方法,如果原型中找不到,就去原型的原型中去寻找...... 最后找到Object那里,如果还找不到,那就是未定义了。
5. JavaScript没有"多态"。
多态的本质在于"程序猿不必关注具体的类型,就能使用其中的某个方法"。
C++、Java等静态类型的语言对于类型的约束和校验比较严格。因此通过子类继承父类,并重写父类的方法的方式来实现多态的效果。
但是在JavaScript中本身就支持动态类型,程序猿在使用对象的某个方法的时候本身也不需要对对象的类型做出明确区分。因此并不需要在语法层面上支持多态。
例如: 在Java中有ArrayList和LinkedList。为了让程序猿使用方便,往往写作 List<String> list = new ArrayList<>() 然后我们可以写一个方法:
void add(List<String> list, String s) {
list.add(s);
}
我们不必关注list是ArrayList还是LinkedList,只要是List就行。因为List内部带有add方法。
当我们使用JavaScript的代码的时候:
function add(list, s) {
list.add(s)
}
add对于list这个参数的类型本身就没有任何限制。只需要list这个对象有add方法即可。就不必像Java那样先继承再重写绕一个圈子。