一、JavaScript 运行过程及组成
- 编写的代码是保存在文件中的, 也就是存储在硬盘(外存上).
- 双击 .html 文件浏览器(应用程序)就会读取文件, 把文件内容加载到内存中(数据流向: 硬盘 => 内存)
- 浏览器会解析用户编写的代码, 把代码翻译成二进制的, 能让计算机识别的指令(解释器的工作)
- 得到的二进制指令会被 CPU 加载并执行(数据流向: 内存 => CPU)
JavaScript 的组成:
:::info
ECMAScript(简称 ES):JavaScript 语法。
**DOM:**页面文档对象模型,对页面中的元素进行操作。
**BOM:**浏览器对象模型,对浏览器窗口进行操作。
:::
二、JavaScript 的书写形式
2.1 行内式
直接嵌入到 html 元素内部:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="button" value="点击我" onclick="alert('prprpr!')">
</body>
</html>
运行结果:
:::warning
注意, JS 中字符串常量可以使用单引号表示, 也可以 使用双引号表示.
HTML 中推荐使用双引号, JS 中推荐使用单引号
:::
2.2 内嵌式
写到 script 标签中:
<body>
<script>
alert('prprpr!');
</script>
</body>
运行结果:
2.3 外部式
写到单独的** .js 文件**中
alert('prprpr~~~');
<body>
<script src="demo7.js"></script>
</body>
运行结果:
:::warning
注意, 这种情况下 script 标签中间不能写代码. 必须空着(写了代码也不会执行).
适合代码多的情况.
:::
三、输入输出
3.1 输入:prompt
弹出一个输入框
<body>
<script>
prompt("请输入你的姓名:");
</script>
</body>
3.2 输出:alert
弹出一个警示对话框,输出结果:
<body>
<script>
alert("hello world!");
</script>
</body>
3.3 输出:console.log
在控制台打印一个日志(供程序员看)
<body>
<script>
console.log("这是一条日志");
</script>
</body>
注意: 在 VSCode 中直接输入 "log" 再按 tab 键, 就可以快速输入
console.log
打开开发者工具(F12)==》Console(控制台) 标签页才能看到结果:
重要概念:console
console 是一个 js 中的 "对象" .
表示取对象中的某个属性或者方法,**.**
可以直观理解成 "的"
console.log 就可以理解成: 使用 "控制台" 对象 "的" log 方法
四、语法介绍
4.1 变量的使用
JS 中创建的变量,不需要显式指定类型。
变量的实际类型,根据初始化/赋值来确定。
var name = 'zhangsan';
var age = 20;
使用变量:
console.log(age); // 读取变量的内容
age = 100; // 修改变量的内容
console.log(age);
4.2 理解动态类型
- JS 的变量类型式程序运行过程中才确定的。
var a = 10; // 数字
var b = "hello"; // 字符串
- 随着程序运行,变量的类型可能会发送改变。
var a = 10; // 数字
a = "world"; // 字符串
4.3 基本数据类型
JS 中内置的几种类型
- number: 数字. 不区分整数和小数.
- boolean: true 真, false 假.
- **string: **字符串类型.
- undefined: 只有唯一的值 undefined. 表示未定义的值.
- null: 只有唯一的值 null. 表示空值.
number 数字类型
JS 中不区分整数和浮点数, 统一都使用 "数字类型" 来表示。
数字进制表示
var a = 07; // 八进制整数,以 0 开头
var b = 0xa; // 十六进制整数,以 0x 开头
var c = 0b10; // 二进制整数,以 0b 开头
注意:
- 一个八进制数字对应三个二进制数字。
- 一个十六进制数字对应四个二进制数字. (两个十六进制数字就是一个字节)。
特殊的数字值
- Infinity: 无穷大, 大于任何数字. 表示数字已经超过了 JS 能表示的范围.
- -Infinity: 负无穷大, 小于任何数字. 表示数字已经超过了 JS 能表示的范围.
- NaN: 表示当前的结果不是一个数字.
var max = Number.MAX_VALUE;
// 得到 Infinity
console.log(max * 2);
// 得到 -Infinity
console.log(-max * 2);
// 得到 NaN
console.log('hello' - 10);
注意:
- 负无穷大 和 无穷小 不是一回事. 无穷小指无限趋近与 0, 值为
1 / Infinity
- 'hehe' + 10 得到的不是 NaN, 而是 'hehe10', 会把数字隐式转成字符串, 再进行字符串拼接.
- 可以使用 isNaN 函数判定是不是一个非数字.
console.log(isNaN(10));
console.log(isNaN('hello'-10));
string 字符串类型
var a = "hello";
var b = 'hello';
var c = hello; // 运行出错
var msg = "My name is "zhangsan""; // 出错
var msg = "My name is \"zhangsan\""; // 正确, 使用转义字符. \" 来表示字符串内部的引号.
var msg = "My name is 'zhangsan'"; // 正确, 搭配使用单双引号
var msg = 'My name is "zhangsan"'; // 正确, 搭配使用单双引号
求长度
使用 string 的 length 属性即可:
var a = 'hello';
console.log(a.length);
var b = '啊啊';
console.log(b.length);
结果如下:单位为 字符 的数量。
字符串拼接
使用 + 进行拼接:
var a = "my name is ";
var b = "zhangsan";
console.log(a + b); // my name is zhangsan
注意, 数字和字符串也可以进行拼接:
var c = "my score is ";
var d = 100;
console.log(c + d); // my score is 100
注意, 要认准相加的变量到底是字符串还是数字:
console.log(100 + 100); // 200
console.log('100' + 100); // 100100
boolean 布尔类型
Boolean 参与运算时当做 1 和 0 来看待:
console.log(true + 1); // 2
console.log(false + 1); // 1
这样的操作其实是不科学的. 实际开发中不应该这么写.
undefined 未定义数据类型
如果一个变量没有被初始化过, 结果就是 undefined, 是 undefined 类型:
var a;
console.log(a);
undefined 和字符串进行相加, 结果进行字符串拼接:
console.log(a + "10"); // undefined10
undefined 和数字进行相加, 结果为 NaN:
console.log(a + 10);
null 空值类型
null 表示当前的变量是一个 "空值".
var b = null;
console.log(b + 10); // 10
console.log(b + "10"); // null10
注意: null 和 undefined 都表示取值非法的情况, 但是侧重点不同. null 表示当前的值为空. (相当于有一个空的盒子) undefined 表示当前的变量未定义. (相当于连盒子都没有)
运算符
JavaScript 中的运算符和 Java 用法基本相同. 此处不做详细介绍了。
注意:
- 比较运算符:
**==**
比较相等,会进行隐式类型转换**===**
比较相等,不会进行隐式类型转换
var a = 10;
var b = '10'
console.log(a == b);
console.log(a === b);
**||**
运算符:
JS 中的逻辑或 和 Java 差别很大。
java || 运算返回的一定式 boolean 值
JS 的或运算,a || b
- 若 a 为 true,整个表达式的值就为 a 的值。
- 若 b 为 true,整个表达式的值就为 b 的值。
// 若 b 值为非空,就把 a 设为 b
// 若 b 值为空(null/undefined),就把 a 设为 0
let a = b || 0;
数组
创建数组
Java / C 中,要求数组中的变量是相同类型的!
但是 JS 中不要求(其他动态类型语言都不要求)。
有两种创建数组的方式:
- 通过
**new**
关键字来创建,数组在 JS 中也就是一个 “对象”。
var arr = new Array();
- 实际开发中,更常用的是,通过 字面量 的方式来创建。
let arr = [];
//也可以在创建数组的时候,填入内容
let arr2 = [1,2,'hello',true,undefined];
// 查看数组
console.log(arr);
console.log(arr2);
获取数组元素
使用下标的方式访问数组元素(从 0 开始):
var arr = ['艾希','诺克萨斯','盖伦'];
console.log(arr);
console.log(arr[0]);
console.log(arr[1]);
console.log(arr[2]);
arr[2] = '塞拉斯';
console.log(arr);
console.log(arr[2]);
注意:
- 如果尝试读取数组中不存在的下标,就会出现 undefined 的结果:
var arr = ['艾希','诺克萨斯','盖伦'];
console.log(arr[3]);
- 如果尝试写入数组中不存在的下标,就会往这个下标插入元素,同时可能就会修改数组的长度,但是中间元素的值,相当于没有定义,仍然是 undefined的:
var arr = ['艾希','诺克萨斯','盖伦'];
arr[5] = '劫';
console.log(arr);
console.log(arr[3]); // 同时如果读取元素不存在的下标,还是会 undefined
- JS 可以给数组指定一个 字符串 类型的 “下标”。此处的 “下标” 更应该理解成是 “属性”,也就相当于 “键值对”:
let arr = [];
arr['hello'] = 'world'; // 跟 arr.hello = 'world' 等价
console.log(arr);
console.log(arr['hello']);
console.log(arr.hello);
对于上例,本质上是在创建一个 hello 属性,类似的,也可以通过 **[]**
或者**.**
的方式都能访问属性!!
**注意:**不要给数组名直接赋值,此时数组中的所有元素就都没了。 相当于本来 arr 是一个数组,重新赋值后变成字符串了。
var arr = ['盖伦','艾希','光辉'];
arr = '小丑';
新增数组元素
- 通过修改 length 新增:
相当于在末尾新增元素. 新增的元素默认值为 undefined
var arr = [9, 5, 2, 7];
arr.length = 6;
console.log(arr);
console.log(arr[4], arr[5]);
- 通过下标新增
如果下标超出范围赋值元素, 则会给指定位置插入新元素
var arr = [];
arr[2] = 10;
console.log(arr);
此时这个数组的 [0] 和 [1] 都是 undefined
- 使用 push 进行追加元素(常用)
**代码示例:**给定一个数组,把数组中的奇数放到一个 newArr 中。
var arr = [1,2,3,4,5,6,7,8,9];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] % 2 != 0) {
newArr.push(arr[i]);
}
}
console.log(newArr);
删除数组中的元素
使用 splice 方法删除元素:
var arr = [1,2,3,4,5,6];
// 第一个参数表示从下标为 2 的位置开始删除,
// 第二个参数表示要删除的元素个数为 3 个。
arr.splice(2,3);
console.log(arr);
4.4 函数
语法格式
// 创建函数/函数声明/函数定义
function 函数名(形参列表) {
函数体
return 返回值;
}
// 函数调用
函数名(实参列表) // 不考虑返回值
返回值 = 函数名(实参列表) // 考虑返回值
- 函数定义并不会执行函数体内容, 必须要调用才会执行. 调用几次就会执行几次.
function hello() {
console.log("hello world!!");
}
// 如果不调用函数,则没有执行打印语句
hello();
- 调用函数的时候进入函数内部执行, 函数结束时回到调用位置继续执行. 可以借助调试器来观察.
- 函数的定义和调用的先后顺序没有要求. (这一点和变量不同, 变量必须先定义再使用)
// 调用函数
hello();
// 定义函数
function hello() {
console.log("hello");
}
参数个数
实参和形参之间的个数可以不匹配. 但是实际开发一般要求形参和实参个数要匹配
- 如果实参个数比形参个数多,则多出的参数不参与函数运算:
function add(a,b) {
return a+b;
}
console.log(add(10,20,30,40));
- 如果实参个数比形参个数少, 则此时多出来的形参值为 undefined:
function add(a,b) {
return a+b;
}
console.log(add(10));
函数表达式
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 变量来调用函数了.
作用域链
背景:
- 函数可以定义在函数内部
- 内层函数可以访问外层函数的局部变量.
内部函数可以访问外部函数的变量. 采取的是链式查找的方式. 从内到外依次进行查找.
var num = 1;
function test1() {
var num = 10;
function test2() {
var num = 20;
console.log(num);
}
test2();
}
test1();
4.5 对象
- 使用 字面量 创建对象(常用)
使用 { } 创建对象
var a = {}; // 创建了一个空的对象
var student = {
name: '蔡徐坤',
height: 175,
weight: 170,
sayHello: function() {
console.log("hello");
}
};
- 使用 { } 创建对象
- 属性和方法使用键值对的形式来组织.
- 键值对之间使用 , 分割. 最后一个属性后面的 , 可有可无
- 键和值之间使用 : 分割.
- 方法的值是一个匿名函数.
使用对象的属性和方法:
// 1. 使用 . 成员访问运算符来访问属性 `.` 可以理解成 "的"
console.log(student.name);
// 2. 使用 [ ] 访问属性, 此时属性需要加上引号
console.log(student['height']);
// 3. 调用方法, 别忘记加上 ()
student.sayHello();
- **使用 **
**new Object**
创建对象
var student = new Object(); // 和创建数组类似
student.name = "蔡徐坤";
student.height = 175;
student['weight'] = 170;
student.sayHello = function () {
console.log("hello");
}
console.log(student.name);
console.log(student['weight']);
student.sayHello();
注意, 使用 { } 创建的对象也可以随时使用 student.name = "蔡徐坤"; 这样的方式来新增属性
- 使用 构造函数 创建对象
前面的创建对象方式只能创建一个对象. 而使用构造函数可以很方便 的创建 多个对象.
例如: 创建几个猫咪对象:
function Cat(name, type, sound) {
this.name = name;
this.type = type;
this.miao = function () {
console.log(sound); // 别忘了作用域的链式访问规则
}
}
var mimi = new Cat('咪咪', '中华田园喵', '喵');
var xiaohei = new Cat('小黑', '波斯喵', '猫呜');
var ciqiu = new Cat('刺球', '金渐层', '咕噜噜');
console.log(mimi);
mimi.miao();