1 -> 基础数据类型
1.1 -> 条件语句
1.1.1 if语句
基本语法格式
条件表达式为true,则执行if的{}中的代码。
// 形式1 if (条件) { 语句 } // 形式2 if (条件) { 语句1 } else { 语句2 } // 形式3 if (条件1) { 语句1 } else if (条件2) { 语句2 } else if .... { 语句... } else { 语句N }
练习案例
代码示例1:判定一个数字是奇数还是偶数。
代码语言:javascript复制var num = 10;
if (num % 2 == 0) {
console.log("num 是偶数");
}
else {
console.log("num 是奇数");
}
注意:
不能写成num % 2 == 1就是奇数。负的奇数 % 2结果可能是-1。
代码示例2:判定一个数字是正数还是负数。
代码语言:javascript复制var num = 10;
if (num > 0) {
console.log("num 是正数");
}
else if (num < 0) {
console.log("num 是负数");
}
else {
console.log("num 是 0");
}
代码示例3:判定某一年份是否为闰年。
代码语言:javascript复制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的值。
注意:
三元表达式的优先级是比较低的。
1.2 -> 分支语句
1.2.1 -> switch语句
更适合多分支的场景。
switch (表达式) { case 值1: 语句1; break; case 值2: 语句2; break; default: 语句N; }
练习案例
代码示例1:用户输入一个整数,提示今天是星期几。
代码语言:javascript复制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("输入有误");
}
1.3 -> 循环语句
重复执行某些语句。
1.3.1 -> while循环
while (条件) { 循环体; }
执行过程:
- 先执行条件语句。
- 条件为true,执行循环体代码。
- 条件为false,直接结束循环。
练习案例
代码示例1:打印1-10。
代码语言:javascript复制var num = 1;
while (num <= 10) {
console.log(num);
num ;
}
代码示例2:计算5的阶乘。
代码语言:javascript复制var result = 1;
var i = 1;
while (i <= 5) {
result *= i;
i ;
}
console.log(result)
1.3.2 -> continue
结束这次循环。
练习案例
代码示例1: 吃五个李子,发现第三个李子里有一只虫子,于是扔掉这个,继续吃下一个李子。
test.html
代码语言:javascript复制<!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
代码语言:javascript复制var i = 1;
while (i <= 5) {
if (i == 3) {
i ;
continue;
}
console.log("我在吃第" i "个李子");
i ;
}
展示结果:
代码示例2:找到100-200中所有3的倍数。
代码语言:javascript复制var num = 100;
while (num <= 200) {
if (num % 3 != 0) {
num ; // 这里的 不要忘记! 否则会死循环.
continue;
}
console.log("找到了 3 的倍数, 为:" num);
num ;
}
1.3.3 -> break
结束整个循环。
练习案例
代码示例1:吃五个李子,发现第三个李子里有虫子,于是剩下的也不吃了。
test.html
代码语言:javascript复制<!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
代码语言:javascript复制var i = 1;
while (i <= 5) {
if (i == 3) {
break;
}
console.log("我在吃第" i "个李子");
i ;
}
展示结果:
代码示例2:找到100-200中第一个3的倍数。
代码语言:javascript复制var num = 100;
while (num <= 200) {
if (num % 3 == 0) {
console.log("找到了 3 的倍数, 为:" num);
break;
}
num ;
}
1.3.4 -> for循环
for (表达式1; 表达式2; 表达式3) { 循环体 }
- 表达式1:用于初始化循环变量。
- 表达式2:循环条件。
- 表达式3:更新循环变量。
执行过程:
- 先执行表达式1,初始化循环变量。
- 再执行表达式2,判定循环条件。
- 如果条件为true,则执行循环体代码;如果条件为false,结束循环。
- 执行表达式3,更新循环变量。
练习案例
代码示例1:打印数字1-10。
代码语言:javascript复制for (var num = 1; num <= 10; num ) {
console.log(num);
}
代码示例2:计算5的阶乘。
代码语言:javascript复制var result = 0;
for (var i = 1; i <= 5; i ) {
result *= i;
}
console.log("result = " result);
1.4 -> 数组
1.4.1 -> 创建数组
使用new关键字创建。
// Array 的 A 要大写 var arr = new Array();
使用字面量方式创建。
代码语言:javascript复制var arr = [];
var arr2 = [1, 2, 'One Piece', false]; // 数组中保存的内容称为 "元素"
注意:
JS的数组不要求元素是相同类型。
这点和C/C 、Java等静态类型的语言差别很大。但是Python、PHP等动态类型语言也是如此。
1.4.2 -> 获取数组元素
使用下标的方式访问数组元素(从0开始)。
代码语言:javascript复制var arr = ['路飞太郎', '索隆十郎', '山五郎'];
console.log(arr);
console.log(arr[0]);
console.log(arr[1]);
console.log(arr[2]);
arr[2] = '海侠甚平';
console.log(arr);
如果下标超出范围读取元素,则结果为undefined。
代码语言:javascript复制console.log(arr[3]); // undefined
console.log(arr[-1]); // undefined
注意:
不要给数组名直接赋值,此时数组中的所有元素都没了。
相当于本来arr是一个数组,重新赋值后变成字符串了。
代码语言:javascript复制var arr = ['路飞太郎', '索隆十郎', '山五郎'];
arr = '海侠甚平';
1.4.3 -> 新增数组元素
1. 通过修改length新增
相当于在末尾新增元素。新增的元素默认值为undefined。
test.html
代码语言:javascript复制<!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
代码语言:javascript复制var arr = [9, 5, 2, 7];
arr.length = 6;
console.log(arr);
console.log(arr[4], arr[5]);
展示结果:
2. 通过下标新增
如果下标超出范围赋值元素,则会给指定位置插入新元素。
test.html
代码语言:javascript复制<!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
代码语言:javascript复制var arr = [];
arr[2] = 10;
console.log(arr);
展示结果:
3. 使用push进行追加元素
代码示例1:给定一个数组,把数组中的奇数放到一个newArr中。
代码语言:javascript复制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);
1.4.4 -> 删除数组中的元素
使用splice方法删除元素。
test.html
代码语言:javascript复制<!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
代码语言:javascript复制var arr = [9, 5, 2, 7];
// 第一个参数表示从下表为 2 的位置开始删除. 第二个参数表示要删除的元素个数是 1 个
arr.splice(2, 1);
console.log(arr);
展示结果:
注意:
- arr.length,length使用的时候不带括号,此时length就是一个普通的变量(称为成员变量,也叫属性)。
- arr.push()、arr.splice()使用的时候带括号,并且可以传参数,此时是一个函数(也叫方法)。
2 -> 函数
2.1 -> 语法格式
// 创建函数/函数声明/函数定义 function 函数名(形参列表) { 函数体 return 返回值; } // 函数调用 函数名(实参列表) // 不考虑返回值 返回值 = 函数名(实参列表) // 考虑返回值
- 函数定义并不会执行函数体内容,必须要调用才会执行。调用几次就会执行几次。
function hello() {
console.log("hello");
}
// 如果不调用函数, 则没有执行打印语句
hello();
- 调用函数的时候进入函数内部执行,函数结束时回到调用位置继续执行。可以借助调试器来观察。
- 函数的定义和调用的先后顺序没有要求(这一点和变量不同,变量必须先定义再使用)。
// 调用函数
hello();
// 定义函数
function hello() {
console.log("hello");
}
2.2 -> 关于参数个数
实参和形参之间的个数可以不匹配。但是实际开发一般要求形参和实参个数要匹配。
1. 如果实参个数比形参个数多,则多出的参数不参与函数运算。
代码语言:javascript复制sum(10, 20, 30); // 30
2. 如果实参个数比形参个数少,则此时多出来的形参值为undefined。
代码语言:javascript复制sum(10); // NaN, 相当于 num2 为 undefined.
JS的函数传参比较灵活,这一点和其他语言差别较大。事实上这种灵活性往往不是好事。
2.3 -> 函数表达式
另外一种函数的定义方式。
代码语言:javascript复制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中函数是一等公民,可以用变量保存,也可以作为其他函数的参数或者返回值。
3 -> 作用域
某个标识符名字在代码中的有效范围。
在ES6标准之前,作用域主要分成两个:
- 全局作用域:在整个script标签中,或者单独的js文件中生效。
- 局部作用域/函数作用域:在函数内部生效。
// 全局变量
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,则得到一个全局变量。
代码语言:javascript复制function test() {
num = 100;
}
test();
console.log(num);
另外,很多语言的局部变量作用域是按照代码块(大括号)来划分的,JS在ES6之前不是这样的。
代码语言:javascript复制if (1 < 2) {
var a = 10;
}
console.log(a);
4 -> 作用域链
背景:
- 函数可以定义在函数内部。
- 内层函数可以访问外层函数的局部变量。
内部函数可以访问外部函数的变量。采取的是链式查找的方式。从内到外依次进行查找。
代码语言:javascript复制var num = 1;
function test1() {
var num = 10;
function test2() {
var num = 20;
console.log(num);
}
test2();
}
test1();
执行console.log(num)的时候,会现在test2的局部作用域中查找num。如果没找到,则继续去test1中查找。如果还没找到,就去全局作用域查找。
5 -> 对象
5.1 -> 基本概念
对象是指一个具体的事物。
"电脑"不是对象,而是一个泛指的类别。而"我的联想笔记本"就是一个对象。
在JS中,字符串、数值、数组、函数都是对象。
每个对象中包含若干的属性和方法。
- 属性:事物的特征。
- 方法:事物的行为。
对象需要保存的属性有多个,虽然数组也能用于保存多个数据,但是不够好。
例如表示一个学生信息。(姓名路飞太郎,身高180cm,体重170斤) var student = ['路飞太郎', 180, 170]; 但是这种情况下到底180和170谁表示身高,谁表示体重,就容易分不清。
JavaScript的对象和Java的对象概念上基本一致。只是具体的语法表项形式差别较大。
5.2 -> 使用字面量创建对象
使用{}创建对象。
代码语言:javascript复制var a = {}; // 创建了一个空的对象
var student = {
name: '路飞太郎',
height: 180,
weight: 170,
sayHello: function() {
console.log("One Piece");
}
};
- 使用{ }创建对象。
- 属性和方法使用键值对的形式来组织。
- 键值对之间使用“,”分割。最后一个属性后面的“,”可有可无。
- 键和值之间使用“:”分割。
- 方法的值是一个匿名函数。
使用对象的属性和方法:
代码语言:javascript复制// 1. 使用 . 成员访问运算符来访问属性 `.` 可以理解成 "的"
console.log(student.name);
// 2. 使用 [ ] 访问属性, 此时属性需要加上引号
console.log(student['height']);
// 3. 调用方法, 别忘记加上 ()
student.sayHello();
5.3 -> 使用new Object创建对象
代码语言:javascript复制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 = "路飞太郎"; 这样的方式来新增属性。
5.4 -> 使用构造函数创建对象
前面的创建对象方式只能创建一个对象。而使用构造函数可以很方便的创建多个对象。
例如:创建几个猫咪对象。
代码语言:javascript复制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关键字来表示当前正在构建的对象。
- 构造函数的函数名首字母一般是大写的。
- 构造函数的函数名可以是名词。
- 构造函数不需要return。
- 创建对象的时候必须使用new关键字。
this相当于”我“。
使用构造函数重新创建猫咪对象。
代码语言:javascript复制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();
5.5 -> new关键字
new的执行过程:
- 先在内存中创建一个空的对象{ }。
- this指向刚才的空对象(将上一步的对象作为this的上下文)。
- 执行构造函数的代码,给对象创建属性和方法。
- 返回这个对象(构造函数本身不需要return,由new代劳了)。
6 -> JavaScript的对象和Java的对象的区别
1. JavaScript没有“类”的概念
对象其实就是"属性" "方法"。
类相当于把一些具有共性的对象的属性和方法单独提取了出来,相当于一个"月饼模子"。
在JavaScript中的"构造函数"也能起到类似的效果。
而且即使不是用构造函数,也可以随时的通过{ }的方式指定出一些对象。
在ES6中也引入了class关键字,就能按照类似于Java的方式创建类和对象了。
2. JavaScript对象不区分"属性"和"方法"
JavaScript中的函数是"一等公民",和普通的变量一样。存储了函数的变量能够通过( )来进行调用执行。
3. JavaScript对象没有private / public等访问控制机制。
对象中的属性都可以被外界随意访问。
4. JavaScript对象没有"继承"。
继承本质就是"让两个对象建立关联"。或者说是让一个对象能够重用另一个对象的属性/方法。
JavaScript中使用"原型"机制实现类似的效果。
例如:创建一个Cat对象和Dog对象,让这两个对象都能使用animal对象中的eat方法。
通过 __proto__ 属性来建立这种关联关系(proto翻译作“原型”)。
代码语言:javascript复制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中本身就支持动态类型,程序猿在使用对象的某个方法的时候本身也不需要对对象的类型做出明确区分。因此并不需要在语法层面上支持多态。
代码语言: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的代码的时候:
代码语言:javascript复制function add(list, s) {
list.add(s)
}
add对于list这个参数的类型本身就没有任何限制。只需要list这个对象有add方法即可。就不必像Java那样先继承再重写绕一个圈子。