JavaScript
1. 什么是JavaScript
JavaScript是一门弱类型的脚本语言,其源代码在发往客户端之前不需要经过编译,而是将文本格式的字符代码发送给浏览器,由浏览器解释运行。
Native 原生 JS 开发
原生 JS 开发,也就是让我们按照【ECMAScript】标准开发方式,简称 ES ,特点是所有浏览器都支持。
TypeScript 微软标准
TypeScript 是一种由微软开发和开源的编程语言,他是JavaScript 的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。
JavaScript 构建工具
- Babel:JS编译工具,主要用于浏览器不支持的ES新特性
- WebPack:模块打包器,主要作用是打包、压缩、合并和按序加载
ECMAScript
最新版本已经到了ES6版本
但是大部分浏览器还只停留在支持ES5代码上
2. 快速入门
JavaScript严格区分大小写。
2.1. 引入
内部标签
script标签内不用显示定义type,也默认就是JavaScript。
内部引入理论上可以放在任何位置,常见位置是放在head标签或者body标签内的后面。
<script> alert('Hello world'); </script>
外部引入
main.js
alert('Hello world');
index.html
<script src="./script/main.js"></script>
2.2. 注释
和Java用法相同。
2.3. 基本语法入门
// 1.定义变量
var score = 70;
// 2.条件控制
if (score > 60 && score < 70) {
alert("60~70");
} else if (score > 70 && score < 80) {
alert("70~80")
} else {
alert("other");
}
// console.log(score) 在浏览器的控制台打印变量,相当于System.out.println()
2.4. 数据类型
数值,文本,图形,音频,视频...
定义变量
变量名不能以数字开头!
var 变量名 = '变量值'; // 或者 let 变量名 = '变量值';
var和let的区别
ES6 新增了let命令,用来声明局部变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效,而且没有暂时性死区的约束。
ES6可以用let定义块级作用域变量。
let配合for循环时,变量会被固定,不受外界干扰。
没有变量提升与暂时性死区,凡在声明之前就使用这些变量就会报错。
暂时性死区:在let命令声明变量之前,该变量是不可用的。
let不允许在相同作用域内,重复声明同一个变量。
number
js不区分小数跟整数,统一用number。
123 // 整数 123.1 // 浮点数 1.23e3 // 科学技术法 -99 // 负数 NaN // not a number Infinity // 表示无限大
字符串
'abc' "abc"
布尔值
true false
算术运算符
+ - * / % ++ --
赋值运算符
= += -= *= /= %=
逻辑运算符
&& // 两个都为真,结果为真 || // 一个为真,结果为真 ! // 真即假,假即真
比较运算符
> < >= <= != = // 赋值 == // 等于(类型不相同,值相同,也会判断为true) === // 绝对等于(类型和值都一样,结果为true)
一定不要用==判断值相同。
位运算符
& | ^ >> << >>> << 左移几位就是该数据乘以2的几次方 >> 带符号位右移,高位空缺的位高位是什么就补什么 >>> 无符号右移,高位出现空缺,无论高位是什么都补0
三元运算符
A? B: C;
浮点数问题
console.log((1/3)===(1-2/3)); // false
尽量避免使用浮点数进行计算,存在精度问题,只能尽量近似
console.log(Math.abs(1/3-(1-2/3))<0.000000001); // true
null和undefined
null 空
undefined 未定义,实际上是一个常量。
var a; console.log(a); // undefined console.log(a === undefined); // true
数组[]
Java的数组必须是一系列相同类型的对象,js中不需要这样
//保证代码的可读性,尽量使用[] var arr = [1, 2, 3, 4, 5, "hello", null, true]; new Array(1, 2, 3, 4, 5, "hello");
取数组下标,如果越界了,会报undefined.
对象{}
对象是{},数组是[]
每个属性之间使用逗号隔开,最后一个不需要
var person = { name: 'rootwhois', age: 3, tags: ['Java', 'html', 'css', 'js'] }
取对象的值
person.name // 'rootwhois' person.age // 3 person.tags /* (4) ['Java', 'html', 'css', 'js'] 0: "Java" 1: "html" 2: "css" 3: "js" length: 4 [[Prototype]]: Array(0) */ person /* {name: 'rootwhois', age: 3, tags: Array(4)} age: 3 name: "rootwhois" tags: (4) ['Java', 'html', 'css', 'js'] */
补充
NaN
NaN与所有的数值都不相等,包括自己
- 只能通过isNaN(NaN)来判断这个数值是否为NaN
NaN == NaN
// false
NaN === NaN
// false
isNaN(NaN)
// true
不同类型的变量的运算
字符串减去数值会转换成两个数做减法运算。
- 字符串加上数值会转换成两个字符串进行拼接。true值为1,false值为0.
console.log('12' - 1);
// 11
console.log('12' + 1);
// 121
console.log(true + 1);
// 2
2.5. 严格检查格式
需要IDE开启支持ES6语法,才能使用严格检查模式。
'use strict';
使用严格检查模式,预防JavaScript的随意性导致产生的一些问题,必须写在JavaScript的第一行。局部变量建议使用let定义。
<script>
//严格检查模式
'use strict';
// i = 1; // 报错
//全局变量
var i=1;
//ES6 中局部变量使用let定义
let j=1;
</script>
3. 数据类型
3.1. 字符串
正常字符串使用单引号或者双引号包裹。
"123" '123'
转义字符
\' \n \t \u4e2d // \u#### Unicode /x41 // AscII
多行字符串编写(ES6)
使用`包裹。
var msg = ` hello world !`
模板字符串(ES6)
有点像EL表达式
var name = "lisi"; var age = 3; var msg = `${name} 今年 ${age} 岁了`; console.log(msg);
字符串长度
var str = "123"; console.log(str.length); // 3
字符串的不可变性
字符串不允许修改。
var name = "!23;"; name[0] = "1"; console.log(name); // !23;
大小写转换
str.toUpperCase(); str.toLowerCase();
输出指定字符的位置
str.indexOf("t");
截取子字符串
str.substring(x,y);
3.2. 数组
数组:存储数据(如何存,如何取,方法都可以自己实现!)
数组定义的两种方式:
// 1、直接定义
var arr = [];
var arr = [3,1,5,8];
// 2、使用了javascript中的Array对象来完成的定义。
var arr = new Array(); // var arr = [];
var arr1 = new Array(5); // 数组定义并长度是5.
var arr2 = new Array(5,6,7); // 定义一个数组,元素是5,6,7
alert(typeof(arr)); // 对象类型是Object
数组可以包含任意类型的数据。
indexOf 通过元素获取下标索引
var arr = [1, 2, 3, 4, 5, 6, "1"];//通过下标取值和赋值 arr[0]; arr[0] = -1 arr.indexOf(1) // 0 arr.indexOf("1") // 6
长度
arr.length;
slice
slice() 截取Array的一部分,返回一个新的数组,类似于String中的subString
push()、pop()
push:压入到尾部 pop:弹出尾部的一个元素
unshift()、shift()
unshift:压入到头部 shift:弹出头部的一个元素
排序用sort()
默认按照升序排列
arr.sort();
元素反转reverse()
arr.reverse();
concat()
此方法会将参数插入到原数组的后面并返回新的数组,数组本身并不会被修改。
arr.concat(arr2);
连接符join()
打印拼接数组,使用特定的字符串连接。
arr.join("-") // '1-2-3-4-5-6-1'
splice(),是修改Array的万能方法,可以从指定索引开始删除若干元素,然后再从该索引位置添加若干元素。
```javascript let arr = ['Microsoft', 'Apple', 'Yahoo', 'AOL', 'Excite', 'Oracle'];
// 从索引为2的位置开始的三个元素都删除,替换成后面指定的元素 ,方法会返回被删除的元素 arr.splice(2, 3, 'Google', 'Facebook'); // (3)['Yahoo', 'AOL', 'Excite']
arr // (5)['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']
// 从索引为2的位置开始的两个元素都删除,方法会返回被删除的元素 arr.splice(2, 2); // (2)['Google', 'Facebook'] arr // (3)['Microsoft', 'Apple', 'Oracle']
// 在索引为2的位置开始,不删除元素并插入后面的元素
arr.splice(2, 0, 'Facebook', 'Google')[]
arr
// (5)['Microsoft', 'Apple', 'Facebook', 'Google', 'Oracle']
```
多维数组
arr = [[1, 2], [3, 4], [5, 6]]; // (3) [Array(2), Array(2), Array(2)] arr[1][1] // 4
3.3. 对象
由若干个键值对组成
var 对象名 = {
属性名 : 属性值,
属性名 : 属性值,
属性名 : 属性值
};
var person = {
name: 'lisi',
age: 3,
email: '[email protected]',
score: 0
};
js中的对象,{...}表示一个对象,键值对描述属性xxx:xxx,多个属性之间使用逗号隔开,最后一个属性不加逗号。
JavaScript中所有的键都是字符串,值是任意对象!
对象赋值问题
person.name='rootwhois'; // "rootwhois" person // object { name: "rootwhois", age: 3, email: "[email protected]", score: 0 }
使用一个不存在的对象属性不会报错 undefined
person.haha // undefined
动态的删减属性,通过delete来删除对象的属性
delete person.name // true person // Object { age: 3, email: "[email protected]", score: 0 }
动态的添加属性,直接给新的属性添加值即可
person.haha='haha' // "haha" person // Object { age: 3, email: "[email protected]", score: 0, haha: "haha" }
判断属性值是否在这个对象中,xxx in xxx,继承而来也会返回true
'age' in person // true // toString()继承而来 'toString' in person // true
判断一个属性是否是自身拥有的hasOwnProperty,继承而来会返回false
person.hasOwnProperty('toString'); // false person.hasOwnProperty('age'); // true
3.4. 流程控制
if判断
let age = 3; if (age <= 3) { alert('age <= 3'); } else if (age > 3 && age < 5) { alert('age > 3 && age < 5'); } else { alert('others'); }
while / do while循环
while (age < 100) { age = age + 1; console.log(age); } do { age = age + 1; console.log(age); } while (age < 100)
for循环
var age = [1, 2, 3, 4, 5]; for (let i = 0; i < age.length; i++) { console.log(age[i]); } for (let number of age) { console.log(number); }
forEach循环
ES5.1引入
var age = [1, 2, 3, 4, 5]; age.forEach(function (value) { console.log(value) })
for...in遍历下标
var age = [1, 2, 3, 4, 5]; // for...in 中 遍历的是索引 // for (let index in object) { // } for (let number in age) { console.log(age[number]); }
for...of遍历值
var age = [1, 2, 3, 4, 5]; // for...of 中 遍历的是具体的值 // for (let index of object) { // } for (let number in age) { console.log(age[number]); }
3.5. Map和Set
ES6的新特性
Map:
let map = new Map([['tom', 100], ['jack', 90], ['haha', 88]]);
let name = map.get('tom'); // 通过key获得value
map.set('admin', 60); // 新增或修改
map.delete('tom'); // 删除
console.log(map);
Set:无序不重复的集合
new Set传递的参数是数组。
let set = new Set([3, 1, 1, 1, 1]); // set可以去重
set.add(2); // 添加
set.delete(3); // 删除
console.log(set.has(1)); // 判断是否包含
console.log(set);
3.6. iterator
ES6的新特性
遍历数组
for (let number of arr) {
console.log(number);
}
遍历Map
for (let mapElement of map) {
console.log(mapElement);
}
遍历Set
for (let number of set) {
console.log(number);
}
4. 函数
4.1. 定义函数
定义方式一
绝对值函数
function abs(x) {
return x > 0 ? x : -x;
}
如果没有执行return,函数执行完也会返回结果,结果为undefined。
定义方式二
var abs = function (x) {
return x > 0 ? x : -x;
}
function(x){...}这是一个匿名函数,但是可以把结果赋值给abs,通过abs就可以调用
调用函数
abs(1);
// 1
abs(-11);
// 11
abs(-1);
// 1
var a = abs;
// 相当于这个函数有两个函数名称
参数问题
JavaScript可以传任意个参数,也可以不传参数
判断参数进来是否存在的问题
var abs = function (x) {
// 手动抛出异常
if (typeof x !== 'number') {
throw 'Not a number';
}
return x > 0 ? x : -x;
}
arguments关键字
代表传进来的所有的参数,是一个数组。
var abs = function (x) {
for (let i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
return x > 0 ? x : -x;
}
rest
rest参数只能写在最后面,必须用...标识
ES6新特性
代表传进来的已明切定义形参以外的所有参数,是一个数组。
var abs = function (x, ... rest) {
rest.forEach(value => console.log(value));
return x > 0 ? x : -x;
}
4.2. 变量作用域
var定义的变量实际时有作用域的。
假设在函数体内用var声明,那么在函数体外就不可以使用。(若要实现可以使用闭包)。
"use strict"; function f() { var x = 1; x += 1; } x += 1; // ReferenceError: x is not defined
如果在两个函数内使用了相同的变量名,只要都是定义在函数内部,就不会产生冲突。
内部函数可以访问外部函数的成员,反之则不行。
function f() { var x = 1; // 内部函数可以访问外部函数的成员,反之,则不行 function f1() { var y = x + 1; } var z = y + 1; // ReferenceError: y is not defined }
内部函数可以访问外部函数的成员,反之,则不行。
假设内部函数变量和外部函数变量重名,函数查找变量从自身函数开始,由“内”向“外”查找,假设外部存在这个同名的函数变量,则内部函数会屏蔽外部函数的变量。
提升变量的作用域
function f() { var x = 'x' + y; console.log(x); var y = 'y'; } // xundefined // y为undefined
y为undefined,说明js执行引擎自动提升了y的声明,不会提升y的赋值,等价于
function f() { var y; var x = 'x' + y; console.log(x); y = 'y'; }
全局函数
// 全局变量 x = 1; function f() { console.log(x); } f(); console.log(x);
全局对象window
var x = 'xxx'; alert(x); alert(window.x); // 默认所有的全局变量都会自动绑定在window对象下
alert()这个函数本身也是一个
window
变量var x = 'xxx'; window.alert(x); var old_alert = window.alert; //old_alert(x); window.alert = function () { }; // 发现alert失效了,原函数已被改写 window.alert(111); // 恢复 window.alert = old_alert; window.alert(222);
JavaScript实际上只有一个全局作用域,任何变量(函数也可视为变量),假设没有在函数作用范围内找到,就会向外查找,如果在全局作用域都没有找到,就会报
ReferenceError
规范
由于所有的全局变量都会绑定到Windows上,如果不同的js使用了相同的全局变量,冲突->如何减少冲突?
// 唯一全局变量,用来装自己定义的全局变量 var jq={}; // 定义全局变量 jq.name='lisi'; jq.add=function(a,b){ return a+b; }
把自己的代码全部放入自己定义的唯一空间名字中,降低全局命名冲突问题。
局部作用域let
使用var定义的时候
function aaa() { for (var i = 0; i < 100; i++) { console.log(i); } console.log(i+1); // 101 }
i出了作用域还可以使用。
ES6使用let关键字,解决局部作用域冲突的问题。
function aaa() { for (let i = 0; i < 100; i++) { console.log(i); } console.log(i+1); // ReferenceError: i is not defined }
建议使用
let
去定义局部作用域的变量。常量const
在ES6之前定义常量:只要用全部大写字母命名的变量就是常量,建议不要修改这样的值。
var PI=3.14; console.log(PI); PI='123'; // 可以改变这个值 console.log(PI);
在ES6引入了常量关键字
const
const PI=3.14; // 只读变量 console.log(PI); PI=354; // TypeError: invalid assignment to const `PI'
4.3. 方法
定义方法
方法就是把函数放在对象里面,对象只有两个东西:属性跟方法。
var a = {
name: 'zhangsan',
birth: 2000,
// 方法
age: function () {
// 今年
let now = new Date().getFullYear();
return now - this.birth;
}
}
this是无法修改指向的对象的,默认指向调用他的那个对象。
let now = new Date().getFullYear();
return now - this.birth;
}
var a = {
name: 'lisi',
birth: 2000,
// 指向外面的方法,值得注意的是不用加括号
age: getAge
};
// a.age() ok
// getAge() NaN 此时this调用的是window对象
// 属性
a.name
// 方法调用时,一定要带()
a.age()
apply关键字
在js中可以控制this的指向,自Object类。
function getAge() {
let now = new Date().getFullYear();
return now - this.birth;
}
var a = {
name: 'lisi',
birth: 2000,
//方法
age: getAge
};
getAge.apply(a,[]); // this指向了a这个对象,参数为空 想要获取谁就指向谁
5. 内部对象
5.1. 标准对象
typeof 123
// "number"
typeof '123'
// "string"
typeof true
// "boolean"
typeof NaN
// "number"
typeof []
// "object"
typeof {}
// "object"
typeof Math.abs
// "function"
typeof undefined
// "undefined"
5.2. Date
基本使用
let date = new Date(); // Date Tue Jun 09 2020 10:49:38 GMT+0800 (中国标准时间)
console.log(date);
date.getFullYear(); // 年
date.getMonth(); // 月 0-11 代表月
date.getDate(); // 日
date.getDay(); // 星期
date.getHours(); // 时
date.getMinutes(); // 分
date.getSeconds(); // 秒
date.getMilliseconds(); // 毫秒
date.getTime();// 时间戳 全世界统一 1970.1.1 00:00:00 毫秒数
console.log(new Date(1630637425646));// 时间戳转时间
转换
var now=new Date(1630637425646);
console.log(now);
// Fri Sep 03 2021 10:50:25 GMT+0800 (中国标准时间)
now.toLocaleString();
// '2021/9/3 上午10:50:25'
now.toGMTString()
// 'Fri, 03 Sep 2021 02:50:25 GMT'
5.3. Math
var num1 = Math.ceil(12.34); // 返回大于等于指定参数的最小整数
var num2 = Math.floor(12.34); // 返回小于等于指定数据的最大整数
var num3 = Math.round(12.54); // 四舍五入
var num4 = Math.pow(10,2); // 平方
5.4. JSON
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。
简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
在JavaScript中,一切皆为对象,任何js支持的类型都可以用 JSON 来表示
格式:
- 对象都用 {}
- 数组都用 []
- 所有的键值对都使用 key:value
JSON 字符串和 JavaScript 对象的转换
var user = {
name: 'lisi',
age: 3,
sex: '男'
};
// 对象转换为JSON
let jsonUser = JSON.stringify(user);
// {"name":"lisi","age":3,"sex":"男"}
// JSON字符串转换为对象,参数为JSON字符串
let object = JSON.parse(jsonUser);
// Object { name: "lisi", age: 3, sex: "男" }
JSON和JS对象的区别
var object = {a: 'hello', b: 'hellob'};
var json = '{"a":"hello","b":"hellob"}';
6. 面向对象编程
6.1. 原型对象
类:模板 原型
对象:具体的实例
var Person = {
name: 'lisi',
age: 3,
run: function () {
console.log(this.name + ' run...');
}
}
var xiaoming = {
name: 'xiaoming'
}
// xiaoming.run() // 无法调用
// 将小明的原型指向Student(大概理解成xiaoming继承Student)
xiaoming.__proto__ = Person;
xiaoming.run();
// xiaoming run...
var Brid = {
fly: function () {
console.log(this.name + ' fly...');
}
}
xiaoming.__proto__ = Brid;
xiaoming.fly();
// xiaoming fly...
6.2. class继承
ES6以前:
// 自创构造器函数
function Person(name) {
this.name = name;
}
// 给Person类新增一个方法,需要找到原型增加。
person.prototype.hello = function() {
console.log('hello');
}
class
关键字是在ES6之后引入的。
定义一个类、属性、方法
class Person { constructor(name) { this.name = name; } hello() { console.log('hello'); } } var person = new Person("xiaoming"); person.hello() // hello
继承
class Person { constructor(name) { this.name = name; } hello() { console.log('hello'); } } var person = new Person("xiaoming"); person.hello() // hello class Student extends Person { constructor(name, sno) { super(name); this.sno = sno; } say() { console.log(this.sno + ',' + this.name); } } var student = new Student("zhangsan", 10); student.say();
原型链:
__proto__
7. 操作BOM元素
BOM:Browser Object Model(浏览器对象模型)
浏览器内核:
- IE 6-11
- Chrome
- Safari
FireFox
window
window代表浏览器窗口
window.innerHeight // 859 window.outerHeight // 938 window.outerHeight // 938 window.outerWidth // 1510
window对象的一些方法
```javascript <!DOCTYPE html>
<meta charset="UTF-8"> <title>Title</title> <script> var timeid; // 全局变量,如果写在某个方法的话别的方法就不能使用 function windowMethodDemo() { var b = confirm("你真的确定要点击吗?"); // 这里的方法都省略了window. alert("b=" + b); // 上面confirm方法会弹出一个窗口,点击按钮会返回值 true or false setTimeout("alert('time out run')", 4000); // 设置多少毫秒弹出 timeid = setInterval("alert('interval run')", 3000); // 返回的Integer对象clearInterval方法用,该方法的作用是每多少毫秒就弹出 } function stopTime() { clearInterval(timeid); //取消setInterval方法的调用 } function windowMove() { // moveBy(10,10); 窗口移动多少像素 // moveTo(40,40); 窗口移动到哪个坐标 for (var x = 0; x < 700; x++) { //该代码段就是抖动窗口的功能 moveBy(20, 0); moveBy(0, 20); moveBy(-20, 0); moveBy(0, -20); } } function windowOpen() { open("ad.html", "_blank", "height=400,width=400,status=no,toolbar=no,menubar=no,location=no"); // 第一个参数是打开的链接,第二个参数窗口target属性,第三个参数设置窗口的其他属性 // status(状态栏) // toolbar(工具栏) // menubar(菜单栏) // location(地址栏) // close(); 弹出窗口后关闭该窗口 } </script>
</head>
</body> </html>
window对象的一些事件
```javascript
onunload = function () { // 窗口关闭后弹出
alert("onunload run");
}
onload = function () { // 窗口加载后弹出
window.status = "啊!,加载完毕啦"; // 设置窗口加载后状态栏的信息
alert("onload run");
}
onbeforeunload = function () { // 窗口关闭时弹出
alert("onbeforeunload run");
}
navigator
navigator封装了浏览器的信息
navigator.appName // 'Netscape' navigator.appVersion // '5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36' navigator.userAgent // 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36' navigator.platform // 'MacIntel'
大多数时候不会使用
navigator
对象,因为会被人为修改,建议使用这些属性来判断和编写代码screen
获得当前屏幕的尺寸(单位:px)
screen.height // 1080 screen.width // 1920
location
获得当前页面的url信息
location.host // 'www.baidu.com' location.href // 'https://www.baidu.com/' location.protocol // 'https:'
刷新页面
location.reload()
设置自动跳转到新的地址
Location.assign() 方法会触发窗口加载并显示指定的URL的内容。
location.assign('https://blog.rootwhois.cn')
Document
Document代表当前页面,HTML DOM文档树。
document.title // '百度一下,你就知道' document.title="rootwhois" // 'rootwhois'
获取具体的文档树节点
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <dl id="app"> <dt>Title</dt> <dd>1</dd> <dd>2</dd> <dd>3</dd> </dl> <script> let app = document.getElementById('app'); console.log(app); </script> </body> </html> <-- <dl id="app"> <dt>Title</dt> <dd>1</dd> <dd>2</dd> <dd>3</dd> </dl> -->
值得注意的是,由于网页加载的顺序是从上到下,如果上述脚本放到dl代码块前,将会回去不到指定的内容。
获取cookie
document.cookie // 'BAIDUID=61586B4CC3FB379F7A2F301F8769D146:FG=1; BAIDUID_BFESS=61586B4CC3FB379F7A2F301F8769D146:FG=1; PSTM=1630297476; BD_UPN=123253; BIDUPSID=BEAA576F838E15E8C85E3769E554E3BA; BD_HOME=1; H_PS_PSSID=34436_34440_34496_31660_34004_34524_34092_34504_26350_34427; BA_HECTOR=0k25al8h24048l00qg1gj3kfu0q'
cookie容易遭到劫持。服务器端需要对cookie设置httpOnly属性。
history
记录浏览器的历史记录
history.forward(); // 前进 history.back(); // 后退
8. 操作Dom对象
DOM:Document Object Model(文档对象模型)
DOM用来将标记型文档封装成对象,并将标记型文档中的所有的内容(标签,文本,属性等)都封装成对象。封装成对象的目的是为了更为方便的操作这些文档以及文档中的所有内容。因为对象的出现就可以有属性和行为被调用。
文档对象模型
- 文档:标记型文档。
- 对象:封装了属性和行为的实例,可以被直接调用。
- 模型:所有标记型文档都具备一些共性特征的一个体现。
标记型文档(标签,属性,标签中封装的数据),只要是标记型文档,DOM这种技术都可以对其进行操作。常见的标记型文档:html xml
DOM技术的解析方式:将标记型文档解析一棵DOM树,并将树中的内容都封装成节点对象。
简介另一种解析方式:SAX:是由一些组织定义的一种民间常用的解析方式,并不是w3c标准,而DOM是W3C的标准。
浏览器网页就是一个Dom树形结构
要操作一个DOM节点,就要先获得这个DOM节点。
8.1. 获得DOM节点
获取节点的方法:
- getElementById():通过标签的id属性值获取该标签节点。返回该标签节点。一般容器型节点都有ID属性,所以就用这个获取。
- getElementsByName(): 通过标签的name属性获取节点,因为name有相同,所以返回的一个数组。
- getElementsByTagName(): 通过标签名获取节点。因为标签名会重复,所以返回的是一个数组。
let byTagName = document.getElementsByTagName("h1");
console.log(byTagName);
let byId = document.getElementById('p1');
console.log(byId);
let byClassName = document.getElementsByClassName('p2');
console.log(byClassName);
let father = document.getElementById('father');
let children = father.children; // 获取父节点下的所有子节点
let child = father.children[index]; // 获取第index个子节点
let firstChild = father.firstChild; // 第一个子节点
let lastChild = father.lastChild; // 最后一个子节点
8.2. 更新DOM
<div id="id1"></div>
<script>
let id1 = document.getElementById('id1');
id1.innerText = '123';
id1.innerHTML = '<strong>123</strong>'
id1.style.fontSize = '100px'; // 下划线转驼峰命名问题
id1.style.padding = '2em';
id1.style.color = 'red'; // 属性使用字符串
</script>
8.3. 删除DOM
删除节点的步骤:先获取父节点,再通过父节点删除自己
注意:删除多个节点的时候,children的位置是时刻变化的。
<div id="father">
<h1>标题1</h1>
<p id="p1">p1</p>
<p class="p2">p2</p>
</div>
<script>
let self = document.getElementById('p1');
let father = self.parentElement;
father.removeChild(self);
father.removeChildren(father.children[0]);
</script>
8.4. 插入DOM
当获得了某个Dom节点,假设这个Dom节点是空的,通过innerHTML就可以增加一个元素,但是如果这个Dom节点已经存在元素了,就不能这么干,会覆盖。
将已有的标签追加到后面
<p id="js">JavaScript</p> <div id="list"> <p id="me">JavaME</p> <p id="ee">JavaEE</p> <p id="se">JavaSE</p> </div> <script> let js = document.getElementById('js'); let list = document.getElementById('list'); list.append(js); // 追加到后面 </script>
// 通过js创建一个节点
let newP = document.createElement('p');// 创建一个p标签
newP.id = 'newP';
newP.innerText = 'hello';
list.append(newP);
// 创建一个标签节点
let myScript = document.createElement('script');
myScript.setAttribute('type', 'text/javascript');
list.appendChild(myScript);
// 可以创建一个style标签
let myStyle = document.createElement('style');// 创建了一个空style标签
myStyle.setAttribute("type", 'text/css');// 设置type为text/css
myStyle.innerHTML = 'body{background: antiquewhite;}';// 设置标签内容
let head = document.getElementsByTagName('head');// 将style追加到头部
head[0].appendChild(myStyle);// head的第0个才是head
插入到前面
// insertBefore(newNode,targetNode) let js = document.getElementById('js'); // 新的节点 let list = document.getElementById('list'); // 包含的父节点 let ee = document.getElementById('ee'); // 目标节点 list.insertBefore(js,ee);
9. 操作表单
9.1. 获得要提交的信息
<form action="#" method="post">
<span>用户名</span>
<input type="text" id="username">
<p>
<span>性别</span>
<input type="radio" name="gender" value="man" id="boy">男
<input type="radio" name="gender" value="woman" id="girl">女
</p>
</form>
<script>
let username = document.getElementById('username');
let boy = document.getElementById('boy');
let girl = document.getElementById('girl');
</script>
// 得到输入框的值
username.value;
// 修改输入框的值
username.value = '123';
// 对于单选框,多选框等固定的值,用.value只能取到当前的值
boy.value;
boy.checked;// 查看返回的结果是否为true,如果为true,则为选中
boy.checked = true;// 赋值
9.2. 提交表单
使用md5进行密码加密
md5在线cdn:https://www.bootcdn.cn/blueimp-md5/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--表单绑定提交事件
onsubmit 绑定一个提交检测函数 true false
将这个结果返回表单,使用onsubmit接收
onsubmit="return check()"-->
<form action="https://baidu.com" method="post" onsubmit="return precheck()">
<p>
<span>用户名</span>
<input type="text" name="username" id="username">
</p>
<p>
<span>密码</span>
<input type="password" id="password">
<!--隐藏域作用:如果直接把input-password加密,在提交表单的一瞬间密码会变长,
加隐藏域可以保持密码长度不变,服务器也可以获取的数据为md5后的数据-->
<input type="hidden" name="md5pwd" id="md5pwd">
</p>
<input type="submit" value="提交">
</form>
<script src="https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.18.0/js/md5.min.js"></script>
<script>
function precheck() {
var password = document.getElementById("password");
var md5pwd = document.getElementById("md5pwd");
md5pwd.value = md5(password.value);
// 可以检验表单内容,true通过,false阻止
return true;
}
</script>
</body>
</html>
10. TypeScript
TypeScript是一种由微软开发的自由和开源的编程语言。它是JavaScript的一个超集, 而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。由安德斯·海尔斯伯格(C#、Delphi、TypeScript之父; .NET创立者) 主导。
该语言的特点就是除了具备ES的特性之外还纳入了许多不在标准范围内的新特性,所以会导致很多浏览器不能直接支持TypeScript语法, 需要编译后(编译成JS) 才能被浏览器正确执行。
11. JavaScript框架
- JQuery:JavaScript库,优点就是简化了DOM操作,缺点就是DOM操作太频繁,影响前端性能;在前端眼里使用它仅仅是为了兼容IE6,7,8;
- Angular:Google收购的前端框架,由一群Java程序员开发,其特点是将后台的MVC模式搬到了前端并增加了模块化开发的理念,与微软合作,采用了TypeScript语法开发;对后台程序员友好,对前端程序员不太友好。
- React:Facebook 出品,一款高性能的JS前端框架;特点是提出了新概念 【虚拟DOM】用于减少真实 DOM 操作,在内存中模拟 DOM操作,有效的提升了前端渲染效率;缺点是使用复杂,因为需要额外学习一门【JSX】语言;
- Vue:一款渐进式 JavaScript 框架,所谓渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等新特性。其特点是综合了 Angular(模块化)和React(虚拟 DOM) 的优点;
- Axios:前端通信框架;因为 Vue 的边界很明确,就是为了处理 DOM,所以并不具备通信能力,此时就需要额外使用一个通信框架与服务器交互;当然也可以直接选择使用jQuery 提供的AJAX 通信功能;
12. JavaScript构建工具
详见这里。
- Babel:JS编译工具,主要用于浏览器不支持的ES新特性,比如用于编译TypeScript。
- WebPack:模块打包器,主要作用就是打包、压缩、合并及按序加载。