快速入门
代码书写
HTML+CSS+JavaScript三件套
在编辑器VS Code中直接键入doc可以快速创建html结构
在html中嵌入CSS样式:
在<head>中
1  | <link href="./chatroom.css" rel="stylesheet" type="text/css" />  | 
在html中嵌入js脚本:
一般在<body>末尾
1  | <script src="test1.js"></script>  | 
直接嵌入
将JavaScript代码放在<head>的<script>中,将直接被浏览器执行
1  | <html>  | 
引用外部文件
把JavaScript代码放到一个单独的.js文件,然后在HTML中通过<script src="..."></script>引入这个文件,这样,/static/js/abc.js就会被浏览器执行
如果是DOM无关的,可以放在
head里如果要操作DOM,放在
body的末尾jQuery没有直接操作DOM,放哪都行
1  | <html>  | 
把JavaScript代码放入一个单独的.js文件中更利于维护代码,并且多个页面可以各自引用同一份.js文件。
可以在同一个页面中引入多个.js文件,还可以在页面中多次编写,浏览器按照顺序依次执行。
代码调试
使用chrome浏览器,点击菜单“查看(View)”-“开发者(Developer)”-“开发者工具(Developer Tools)”,快捷键F12
在Elements可以查看页面源代码,在Console可以输入js指令。
基本语法
| 代码 | 功能 | 
|---|---|
; | 
结束语句 | 
{…} | 
语句块 | 
// | 
注释单行 | 
/*...*/ | 
注释多行语句 | 
JavaScript是大小写敏感的
数据类型
Number
JavaScript不区分整数和浮点数,统一用Number表示,以下都是合法的Number类型:
| Number | 类型 | 
|---|---|
| 123; | 整数123 | 
| 0.456; | 浮点数0.456 | 
| 1.2345e3; | 科学计数法表示1.2345x1000,等同于1234.5 | 
| -99; | 负数 | 
| NaN; | NaN表示Not a Number,当无法计算结果时用NaN表示 | 
| Infinity; | Infinity表示无限大,当数值超过Number所能表示的最大值时,就表示为Infinity | 
Number可以直接做四则运算+,-,*,/,%(求余) 
字符串
字符串是以单引号'或双引号"括起来的任意文本
转义字符\,\n换行,\t制表符,\\表示\,\x##可以表示ASCII码
多行字符串…
字符串连接+
模板字符串…${varname}…用变量替换${}的内容
1  | var name = '小明'; var age = 20;  | 
常用属性/函数
| 属性/函数 | 解释 | 用例 | 
|---|---|---|
| length | 字符串长度属性 | var s = 'Hello, world!'  s.length; // 13 | 
| [] | 字符串索引 | s[12]; // '!'  s[13]; // undefined | 
| toUpperCase() | 全部变为大写 | s.toUpperCase() // "HELLO, WORLD!" | 
| toLowerCase() | 全部变为小写 | s.toLowerCase() // "hello, world!" | 
| indexOf() | 搜索指定字符串出现的位置 | s.indexOf(“world”) //7 | 
| substring() | 返回指定索引区间的子串 | s.substring(0, 5); // 从0到5(不包括5),返回'hello' | 
布尔值
有true、false两种值
布尔运算:&&与运算,||或运算,!非运算
比较运算符
当我们对Number做比较时,可以通过比较运算符得到一个布尔值,<,>,<=,>=,==,===,!==
JavaScript允许对任意数据类型做比较,注意:
==和===
1
2false == 0; // true
false === 0; // false==,它会自动转换数据类型再比较,很多时候,会得到非常诡异的结果;===,它不会自动转换数据类型,如果数据类型不一致,返回false,如果一致,再比较。- 由于JavaScript这个设计缺陷,不要使用
==比较,始终坚持使用===比较。 
NaN与所有其他值都不相等,包括它自己:
唯一能判断NaN的方法是通过isNaN()函数:1
isNaN(NaN); // true
浮点数的相等比较
要比较两个浮点数是否相等,只能计算它们之差的绝对值,看是否小于某个阈值Math.abs<阈值:1
Math.abs(1 / 3 - (1 - 2 / 3)) < 0.0000001; // true
null和undefined
null表示一个“空”的值,辨析:0是一个数值,''表示长度为0的字符串
undefined表示值未定义。
区分两者的意义不大。大多数情况下,我们都应该用null。undefined仅仅在判断函数参数是否传递的情况下有用。
另,在变量前加!!判断可以将null和undefined都变成布尔值false
数组
https://www.runoob.com/jsref/jsref-obj-array.html
数组是一组按顺序排列的集合,集合的每个值称为元素。JavaScript的数组可以包括任意数据类型。
数组的创建
法一:数组用[]表示,元素之间用,分隔。1
[1, 2, 3.14, 'Hello', null, true];
法二:通过Array()函数实现
1
new Array(1, 2, 3); // 创建了数组[1, 2, 3]
然而,出于代码的可读性考虑,强烈建议直接使用[]。
数组元素的访问
数组的元素可以通过索引来访问。索引的起始值为0:1
2
3
4var arr = [1, 2, 3.14, 'Hello', null, true];
arr[0]; // 返回索引为0的元素,即1
arr[5]; // 返回索引为5的元素,即true
arr[6]; // 索引超出了范围,返回undefined常用属性/方法
length 数组长度 arr.length []数组索引 arr[0]indexOf()搜索指定元素位置 arr.indexOf(10)slice()截取数组的部分元素 arr.slice(0,3) //从索引0开始到3,不包括3
arr.slice() //复制arrpush()向数组末尾添加若干元素 返回数组长度 arr.push(1,2)pop()删除数组的最后一个元素 返回删除的元素 arr.pop()unshift()向数组头部添加若干元素 返回数组长度 arr.unshift(‘a’,’b’)shift()删除数组的第一个元素 返回删除的元素 arr.shift()sort()对数组排序,默认顺序 arr.sort()reverse()反转数组 arr.reverse()splice()从指定索引开始删除,添加元素 返回删除的元素 var arr=[1,2,3,4,5]; arr.splice(2, 3, 'a', 'b'); // 返回[3,4,5]arr; // [1,2,’a’,’b’]concat()连接两个数组,返回新的数组 arr.concat(1.2.[3,4]); //在arr后面连接1,2,3,4join()把数组元素用指定字符连起来 返回字符串 arr.join(‘-‘)多维数组
如果数组的某个元素又是一个Array,则可以形成多维数组
练习:1)如何通过索引取到500这个值 2)打印数组元素1
2
3
4
5
6
7
8
9//1
;
var arr = [[1, 2, 3], [400, 500, 600], '-'];
//2
;
var arr = ['小明', '小红', '大军', '阿黄'];
arr.sort();
console.log(`欢迎${arr[0]},${arr[1]},${arr[2]}和${arr[3]}同学`);
//console.log(`欢迎${arr.sort().slice(0,-1)}和${arr.sort().slice(-1)}同学!`);
对象
JavaScript的对象是一组由键-值组成的无序集合,例如:
1  | var person = {  | 
对象的键都是字符串类型,值可以是任意数据类型。
其中每个键又称为对象的属性,要获取一个对象的属性,用对象变量.属性名:
1  | person.name; // 'Bob'  | 
判断一个对象是否包含某个属性
| 方法 | 解释 | 用例 | 
|---|---|---|
in  | 
返回true/false,对于变量继承的属性也会判为真 | ‘name’ in person;  // true ‘toString’ in person; // true | 
hasOwnProperty() | 
判断属性是否是变量自身拥有的而不是继承的 | person.hasOwnProperty(‘name’); //true person. hasOwnProperty(‘toString’); //false | 
变量
变量名规范:大小写英文、数字、$和_的组合,且不能用数字开头,不能是JavaScript的关键字,一般是驼峰式命名
- 申明变量用
var语句,只能申明一次let和const都是块级声明,不同点在于const声明后值无法修改- 详见var, let, const异同
 
 - 变量赋值用
=,JavaScript是动态语言,可以把任意数据类型赋值给变量,同一个变量可以反复赋值,可以是不同类型的变量 
1  | var a; // 申明了变量a,此时a的值为undefined  | 
要显示变量的内容,可以用console.log(x)
strict模式
JavaScript中,如果一个变量没有通过var申明就被使用,那么该变量就自动被申明为全局变量:
strict模式下,强制通过var申明变量,未使用var申明变量就使用的,将导致运行错误。
启用strict模式的方法是在JavaScript代码的第一行写上:
1  | ;  | 
这是一个字符串,不支持strict模式的浏览器将报错
条件和循环
条件判断
1  | if () {  | 
For
1  | for (i=1; i<=100; i++) {  | 
For in
遍历对象、数组、字符串的key
遍历对象,可以用hasOwnProperty()过滤继承的属性
1  | var o = {  | 
遍历数组,索引就是key,可以通过索引循环访问
1  | var a = ['A', 'B', 'C'];  | 
for of
遍历对象、数组、字符串的value,比较快捷
1  | var myArray = [1, 2, 4, 5, 6, 7];  | 
While
1  | while () {…}  | 
Iterable:Map & Set
JavaScript的对象有个小问题,就是键必须是字符串。但实际上Number或者其他数据类型作为键也是非常合理的。
Map
Map是一组key-value键值对结构,具有极快的查找速度。对一个key多次赋不同的value会覆盖之前的值
| 方法 | 解释 | 用例 | 
|---|---|---|
new Map() | 
创建Map | var m = new Map(); // 空Map | 
set(key,value) | 
添加键值对 | m.set('Adam', 67); // 添加新的key-value | 
has(key)  | 
检验key是否存在 | m.has('Adam'); // 是否存在key 'Adam': true | 
get(key)  | 
访问key对应的值 | m.get('Adam'); // 67 | 
delete(key)  | 
删除元素 | m.delete('Adam'); // 删除key 'Adam' | 
Set
Set和Map类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key,重复的元素会自动被过滤。
| 方法 | 解释 | 用例 | 
|---|---|---|
new Set() | 
创建Set | var s1 = new Set(); // 空Set var s2 = new Set([1, 2, 3]); // 含1, 2, 3 | 
add(key) | 
添加元素,可以重复添加,但不会有效果 | s.add(4); | 
delete(key) | 
删除元素 | s.delete(3); | 
Iterable
ES6标准引入了新的iterable类型,Array、Map和Set都属于iterable类型。
在for … in循环中,它遍历的是对象的属性,所以如果给Array对象手动增加属性,会导致属性也被遍历。
通过新的for ... of循环来遍历,可以解决这个问题
1  | var a = ['A', 'B', 'C'];  | 
此外,iterable还内置了forEach()方法
Array
1  | var a = ['A', 'B', 'C'];  | 
Set
1  | var s = new Set(['A', 'B', 'C']);  | 
Map
1  | var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);  | 
函数
函数基础
函数定义
function 函数名(参数) {函数体}
return语句返回结果,没有return返回undefined
var 函数名=function(参数) {函数体};
注意第二种定义最后要加分号;
函数调用
函数名(输入参数),按顺序输入参数,参数比定义的多或少都不会报错,但会因为参数为undefined不能完成功能,可以在函数中进行参数检查
1  | function abs(x) {  | 
arguments
只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数,即使函数没有定义形参也能获取实参,常用于判断传入参数
1  | function foo(x) {  | 
rest参数
指向除了函数内已定义参数的其他输入参数
1  | function sum(...rest) {  | 
测试:
1  | var i, args = [];  | 
由于JavaScript引擎会自动在句末添加分号,可能会导致语句无法执行,正确的写法是把return {写在一行
1  | function foo() {  | 
变量作用域与结构赋值
作用域
函数内部声明的变量作用域为整个函数
嵌套的函数内部可以访问外部函数的变量
JavaScript编译时会先扫描函数体把所有声明的变量提升到函数顶部,所以通常首先声明所有变量
1  | function foo() {  | 
不在函数内部声明的变量就是全局变量,默认绑定到全局对象window
名字空间
全局变量会绑定到window上,不同的js文件如果使用了相同的全局变量,或者定义了相同名字的顶层函数,都会造成命名冲突
减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中。例如:
1  | // 唯一的全局变量MYAPP:  | 
局部作用域
用关键字let替代var声明变量,可以使for循环等语句中定义的变量具有块级(函数)作用域
1  | for (**let** i=0; i<100; i++) {...}  | 
常量
const定义常量,具有块级作用域
解构赋值
直接对多个变量同时赋值
1  | var [x, y, z] = ['hello', 'JavaScript', 'ES6'];  | 
从一个对象中取出若干属性,对象中嵌套的属性也可以
1  | var person = {  | 
解构赋值还可以使用默认值
1  | var {name, single=true} = person;  | 
如果变量已经被声明了,使用{}批量赋值会报错,可以用小括号括起来
1  | ({x, y} = { name: '小明', x: 100, y: 200});  | 
实例
交换两个变量的值:[x,y]=[y,x]
快速获取当前页面的域名和路径:var {hostname:domain, pathname:path} = location;
如果函数把对象作为参数,可以直接把对象属性绑定到变量上,如输入Date对象
function buildDate({year, month, day, hour=0, minute=0, second=0}){...}
方法
绑定到对象上的函数称为方法,在一个方法内部,this是一个特殊变量,它始终指向当前对象
用var that = this;,
1  | var xiaoming = {  | 
apply
要指定函数的this指向哪个对象,可以用函数本身的apply方法,它接收两个参数,第一个参数就是需要绑定的this变量,第二个参数是Array,表示函数本身的参数。
1  | function getAge() {  | 
call
与apply()类似,区别是:
apply()把参数打包成Array再传入;
call()把参数按顺序传入。
比如调用Math.max(3, 5, 4),分别用apply()和call()实现如下:
1  | Math.max.apply(null, [3, 5, 4]); // 5  | 
对普通函数调用,我们通常把this绑定为null。
修饰器
利用apply(),我们还可以动态改变函数的行为。JavaScript的所有对象都是动态的,即使内置的函数,我们也可以重新指向新的函数。
1  | var count = 0;  |