很早之前跟这个这个视频学习的: https://www.bilibili.com/video/BV1nb411c7mG?p=1&vd_source=c096def4d5f55f1aab46258c0a27641b
可能有空会回顾这个视频,然后会重新沉淀,可能会对笔记有所修改
这是当时整理的笔记
JavaScript
01. Web发展史、JS入门
Web发展史
- Mosaic:第一个普遍使用的能够显示图片的浏览器
- JavaScript:1996年首次出现(命名为LiveScript)
浏览器的组成
① shell部分(外壳)
② 内核部分:渲染引擎、js引擎、其他引擎
js引擎
2001年,首次出现,对js引擎进行分离;
2008年,Chrome优化,V8;
FireFox推出。
主流浏览器
- 在市场上有一定份额
- 有独立研发的内核
主流浏览器 | 内核 |
---|---|
IE浏览器 | trident |
FireFox | Gecko |
Google Chrome | Webkit/blink |
Safari | Webkit |
Opera | prosto |
JS入门
JavaScript特点(ECMAScript)
- 解释性语言(翻译一行、执行一行)
- 单线程
- ECMA标注
编译性语言 | 解释性语言 |
---|---|
优点:快(例如:C、C++) | 优点:跨平台(例如:JavaScript、PHP、Python) |
缺点:移植性不好(不能跨平台) | 缺点:稍微慢 |
JS的执行队列:轮转时间片
JS三大部分
- ECMAScript
- DOM
- BOM
如何引入JS
页面级JS
<script type="text/javascript">
//这里放JS代码
</script>
外部JS文件
<script type="text/javascript" src="xxxxx.js">//src属性放文件地址
</script>
//注:前端开发要结构(HTML)、行为(JavaScript)、样式(CSS)相分离
//因此提倡第二种方法
02. JS基础语法知识
变量
声明变量
var a;
var b = 10;
var c,
d,
e;//在开发时,声明多个变量要回车隔开
//var来声明变量
变量的命名规则
- 必须以英文字母、下划线、$开头
- 可包含英文字母、下划线、$、数字
- 不可以用系统关键字,保留字
数据类型
原始值
- Number:数字
- Boolean:逻辑值:0(假)和1(真)
- String:字符串:引号(单引号或者双引号)
- undefined:无定义的(值只有一个,就是本身)
- null:空值,起占位作用
引用值
…
注:这两种类型的赋值方式不同,原始值(Stack)赋值是拷贝的关系,引用值(heap)赋值的是地址。
JS语句基本规则
- 语句后面用分号结束;
- JS语法错误会引发后续代码终止,但不会影响其他JS代码块
错误
- 低级错误(语法解析错误)
- 逻辑错误(标准错误,情有可原)
JS运算符
- “+”:数学运算、字符串连接
注:任何数据类型+字符串=字符串
var a = 1 + "a" + 1; //a = "1a1"
var b = 1 + 1 + "a" +1; //b = "2a1"
- “-”,“*”,“/”,“%”,“=”,“()”。
注:“=”最弱,“()”最高(先计算后赋值)
var num = 1 / 0;//Infinity(无穷)
var num = 0 / 0;//NaN(Not a Number非数)
var num = -1 / 0;//-Infinity(负无穷)
var a = 1 + "a" + (1 + 1); //a = "1a2"
- “++”,“–”,“+=”,“-=”,“*=”,“/=”,“%=”
注:赋值的顺序,自右向左;计算的顺序,自左向右。
var a = 1;
document.write(a ++);//打印a=1
document.write(a);//打印a=2
var b = 1;
document.write(++ b);//打印b=2
- 比较运算符:“>”,“<”,“==”,“>=”,“<=”,“!=”
注:字符串比较的是ASCII码,比较的结果为true或者false
注:NaN不等于NaN,Infinity等于Infinity
- 逻辑运算符:&&,||,!(运算结果为真实的值)
//&&
//先看第一个表达式转换成布尔值的结果,如果结果为真,那么他会看第二个表达式转换为
//布尔值的结果,如果只有两个表达式,只看得到第二个表达式,就可以返回该表达式的值
var a = 1 && 2;//返回2
var a = 0 && 2;//返回0
var a = 1 && 2 && 3;//返回3
//undefined, null, NaN, "", 0, false ==>false;
//短路语句 data && fn(data) data有意义才执行后面语句
// ||
var a = 1 || 2;//返回1
var a = 0 || 2;//返回2
// !(自身取反)
var a = !123;//返回false
var a = !"";//返回true
var a = !!"";//返回false
03. 条件语句、循环语句
条件语句:if语句
//第一种
if(条件){
执行语句
}
//第二种
if(条件){
执行语句
}else{
执行语句
}
//第三种
if(条件){
执行语句
}else if(条件){
执行语句
}else{
执行语句
}
//if 和 && 的相互转化
//if(条件){语句} ==> 条件 && 语句
循环语句
for循环
for(var i = 0; i < 10; i++){//中间三块为执行顺序
document.write('a');
}
//for(1;2;3)
//先执行一遍1 --> 判断2,执行语句 --> 执行3 -->
//判断2,执行语句 --> 执行3......
//直到2的值为false
//执行顺序
//1、var i = 0;
//2、if(i < 10){document.write('a');}
//3、i++; --> i = 1
//4、if(i < 10){document.write('a');}
//5、i++;
//6、if(i < 10){document.write('a');}
//......
//
while循环
while(条件){
执行语句
}
//never-ending loop 死循环
//while(1){}
do while循环
do{
执行语句
}while(条件)
//不管条件成立不成立,都先执行一遍
例题
//输入
var n = parseInt(window.prompt('input'));1
//JavaScript(动态语言)是天生浮点型,可直接进行小数运算
//1、计算2的n次幂,n可输入,n为自然数
var n = parseInt(window.prompt('input'));
var mul = 1;
for(var i = 0; i < n; i ++){
mul *= 2;
}
document.write(mul);
//2、计算n的阶乘,n可输入
var n = parseInt(window.prompt('input'));
var mul = 1;
for(var i = 1; i <= n; i ++){
mul *= i;
}
document.write(mul);
//3、著名的斐波那契额数列 1 1 2 3 5 8输出第n项
var n = parseInt(window.prompt('input'));
var first = 1,
second = 1,
third;
if(n > 2){
for(var i = 0; i < n -2; i++){
third = first + second;
first = second;
second = third;
}
document.write(third);
}else{
document.write(1);
}
//4、编写一个程序,输入一个三位数的正整数,输出时反向输出
var n = parseInt(window.prompt('input'));
var a = n % 10;
var b = (n - a) % 100;
var c = (n - b - a) / 100;
var num = a * 100 + b + c;
document.write(num);
//5、输入a,b,c三四个数字,打印出最大的数字
var a = parseInt(window.prompt('input'));
var b = parseInt(window.prompt('input'));
var c = parseInt(window.prompt('input'));
if(a > b){
if(a > c){
document.write(a);
}else{
document.write(c);
}
}else{
if(b > c){
document.write(b);
}else{
document.write(c);
}
}
//6、打印出100以内的质数
var count = 0;
for(var i = 1; i < 100; i ++){
for(var j = 1; j <= Math.sqrt(i); j ++){
if(i % j == 0){
count ++;
}
}
if(count == 1){
document.write(i + " ");
}
count = 0;
}
switch case语句
switch(条件){//当条件与情况相符合时,执行语句
case 情况1:
语句1;
break;//跳出switch语句
case 情况2:
语句2;
break;
case 情况3:
语句3;
break;
}
break、continue语句
break
:终止循环,必须放在循环里面,否则会报错continue
:终止本次循环来进行下一次循环
04. 初始引用值、typeof、类型转换
初始引用值
数组
var arr = [1, 2, 3, 4, 5, 7, "abc", undefined];
//1、读取arr[0]...
//2、写入arr[0]=2...
//3、数组的遍历:arr.length数组的长度
对象object
var obj = {
//key : value
//属性名:属性值
name : "name",//用逗号隔开
age : 20,
}
//取值obj.name
//赋值obj.age=18;
编程形式的区别
- 面向过程
- 面向对象
typeof:分析数据类型,返回的是字符串类型的
//两种写法
typeof(num)
typeof num
- number:123,234,…
- string:“abc”,…
- boolean:true,false
- object:引用值返回,null返回
- undefined:undefined
- function
注:typeof中放没有定义的变量返回undefined
类型转换
显式类型转换
var num = Number('123');//把括号里的东西转换成数字
//null->0,true->1,false->0,undefined->NaN,不是数字的都转换成NaN
var num = parseInt(demo, radix);//转换成整型
//不是数字的全部为NaN,小数转换为整数
//ranix为基底,目标进制,以目标进制为基底转换为十进制,范围2-36
//从数字位往后看,看到非数字位截止
var num = parseFloat(demo);
//从数字位往后看,看到除了第一个点以外的非数字位截止
var num = String(demo);//转换为字符串
var num = Boolean(demo);//转换为布尔值
var num = demo.toString(radix);//转换成字符串,undefined和null不能用
//以十进制为基底转换为目标进制(radix)
隐式类型转换(内部调用的都是显示方法)
isNaN()
isNaN(demo)//true,false
//Number(demo) <--> NaN
- ++/–,+/-(一元正负):内部调用Number()
- +:内部调用String()
- -,/,*,%:内部调用Number()
- &&,||,!
- <,>,<=,>=
- ==,!=
undefined == null//true
NaN == NaN//false
不发生类型转换
- ===:绝对等于
- !==:绝对不等于
NaN === NaN
: false
05. 函数、递归
函数
(1)定义
- 函数声明
function 函数名(){
语句块
}
注:函数名开发规范:小驼峰(例如:theFirstName…)
- 函数表达式(忽略名字)
//1、命名函数表达式
var test = function test1(){
函数体
}//定义结束之后依旧是匿名
//test.name --> test1
//2、匿名函数表达式 ---函数表达式
var demo = function (){
函数体
}//test.name --> demo
(2)组成形式
- 函数名称
- 参数(不限制位置,天生不定参数)
function sum(a, b){//形式参数(形参)
//相当于隐式进行了以下两步
//var a;
//var b;
var c = a + b;
//arguments实参列表(出生的时候有几个就只有几个)
//arguments -- [2, 3, 4]
//实参的长度 arguments.length
//形参的长度 sum.length
}
//映射关系(你变我也变)
sum(1, 2)//实际参数(实参)
sum(2, 3, 4)
- 返回值
return;//终止函数
//返回值
(3)函数作用域
函数体里面可以访问全局变量,外面不可以访问局部变量。
var a = 123;//全局变量
function text(){
var b = 234;//局部变量
}
递归
- 找规律
- 找出口
06.预编译
js运行三部曲
- 语法分析
- 预编译
- 解释执行
预编译前奏
(函数声明整体提升,变量的声明提升)
(1)imply global
暗示全局变量:任何变量,如果未经声明就赋值,此变量就为全局对象(window)所有
a = 10;//没有声明
//相当于
window.a = 10;
function test(){
var a = b = 123;
//a声明了,b没有声明
//b归window所有
}
(2)一切声明的全局变量,全是window的属性
window就是全局的域
var a = 123;
//相当于window.a = 123
window {
a : 123
}
//console.log(a) --> window.a
预编译过程
- 创建AO对象:Activation Object(执行期上下文) 全局生成GO对象,
window == GO
- 找形参和变量声明,将变量和形参名作为AO对象的属性名,值为
undefined
- 将实参和形参统一 全局没有这一步
- 找函数体里面的函数声明,值赋予函数体
function fn(a){
console.log(a);
var a = 123;
console.log(a);
function a(){}
console.log(a);
var b = function (){}
console.log(b);
function d(){}
}//预编译发生在函数执行的前一刻
fn(1);
- 创建AO对象:Activation Object(执行期上下文)
AO{}
- 找形参和变量声明,将变量和形参名作为AO对象的属性名,值为undefined
AO{
a : undefined,
b : undefined,
}
- 将实参和形参统一
AO{
a : 1,
b : undefined,
}
- 找函数体里面的函数声明,值赋予函数体
AO{
a : function a(){},
b : undefined,
d : function d(){}
}
- 结果
function fn(a){
console.log(a);//function a(){}
var a = 123;//var a;被提升 a = 123执行 --> 123
console.log(a);//123
function a(){}//提升
console.log(a);//123
var b = function (){}//var b;提升 执行b = function (){}
console.log(b);//function (){}
function d(){}
}
fn(1);
//结果
//function a(){}
//123
//123
//function (){}
07. 作用域精解、立即执行函数
[[scope]]
- 每个JavaScript函数都是一个对象,对象中有些属性我们可以访问,但是有些不可以,这些属性仅供JavaScript引擎存取,[[scope]]就是其中一个。
[[scope]]
值得就是我们所说的作用域,其中存储了运行期上下文的集合。- 运行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行期上下文都是独一无二的,所以多次调用一个函数会导致常见多个执行期上下文,当函数执行完毕,它所产生的执行上下文被销毁。
作用域链
[[scope]]
中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。- 查找变量:从作用域的顶端依次向下 查找。
立即执行函数
- 此类函数没有函数声明,在一次执行过后即释放。
- 针对初始化功能的函数
- 执行完就被释放(和普通函数唯一的区别)
- 有执行期上下文
- 只有表达式才能被执行符号执行
- 能被执行符号执行的表达式,这个函数的函数名就会被忽略
var num = (function (a, b, c){//形参
语句块
return n;//直接接受返回值给num
}(1, 2, 3))//实参
//方式
(function (){}());//W3C建议第一种
(function (){})();
//只有表达式才能被执行符号执行
var test = function(){
语句块
}();//被执行符号执行
function test(){
语句块
}()//不能被执行
08. 闭包
- 当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄露(过多占用内存资源
闭包的作用
- 实现公有变量:函数累加器
function add(){
var num = 0;
function a(){
console.log(++num);
}
return a;
}
var myAdd = add();
myAdd(); // 1
myAdd(); // 2
myAdd(); // 3
- 可以做缓存(存储结构)
function test(){
var food = "apple";
var obj = {
eatFood : function(){
if(food != ""){
console.log("I am eating " + food);
food = "";
}else{
console.log("There is nothing!");
}
},
pushFood : function(myFood){
food = myFood;
}
}
return obj;
}
var person = test();
person.eatFood(); //I am eating apple
person.eatFood(); //There is nothing!
person.pushFood("banana"); //
person.eatFood(); //I am eating banana
- 可以实现封装,属性私有化
- 模块化开发防止污染全局变量
function test(){
var arr = [];
for(var i = 0; i < 10; i++){
arr[i] = function(){
console.log(i);
}
}
return arr;
}
var myArr = test();
for(var j = 0; j < 10; j++){
myArr[j]();
}//打印10个10
function test(){
var arr = [];
for(var i = 0; i < 10; i++){
(function(j){
arr[j] = function(){
console.log(j);//保存的是立即执行函数的劳动成果
}
}(i))
}
return arr;
}//打印0-9
09. 对象、包装类
对象的创建方法
//1.var obj = {} plainObject 对象字面量/对象直接量
//2.构造函数
// 1) 系统自带的构造函数 new Object()
// 2) 自定义 大驼峰式命名规则
function Car(color){
this.color = color;
this.name = "BMW";
this.height = "1400";
this.run = function(){
}
}
//通过参数使函数发生变化
//构造函数内部原理
//1.在函数体最前面隐式的加上this={}
//2.执行this.xxx = xxx;
//3.隐式的返回this
包装类
new String();
new Boolean();
new Number();
//原始值不能加属性
var num = 4;
num.len = 3;
//new Number(4).len = 3;
console.log(num.len);//undefined
10. 原型、继承模式、对象枚举、this
原型
- 原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。
- 利用原型特点和概念,可以提取共有属性。
- 对象如何查看原型——隐式属性
__proto__
- 对象如何查看对象的构造函数——
constructor
//Person.prototype --原型
//Person.prototype = {} 是祖先
var obj = {};
//var obj1 = new Object();
//obj1.__proto__-----> Object.prototype
原型链
绝大多数对象的最终都会继承自 Object.prototype
//var obj = Object.create(原型)
var obj = {name:"sunny", age : 123};
var obj = Object.create(obj);
可正常计算的范围:小数点前16位,后16位
//call/apply
//作用,改变this指向
//区别,后面传的参数形式不同,传参列表不一样
//call 需要把实参按照形参的个数传进去
//apply 需要传一个arguments
function test(){
}
test() --> test.call();
function Person(name, age){
this.name = name;
this.age = age;
}
var person = new Person("zhangsan", 100);
var obj = {
}
Person.call(obj, "lisi", 300);//把所有的this变成obj
function Person(name, age, sex){
this.name = name;
this.age = age;
this.sex = sex;
}
function Student(name, age, sex, tel, grade){
//var this = {} 利用person的方法实现自己
Person.call(this, name, age, sex);
this.tel = tel;
this.grade = grade;
}
var student = new Student('sunny', 123, 'male', 139, 2018);
继承模式
/**
* 1.传统形式 --> 原型链
* 过多的继承了没用的属性
* 2.借用构造函数---call/apply
* 不能继承借用构造函数的原型
* 每次构造函数都要多走一个函数
* 3.共享原型---先继承,后使用
* 不能随便改动自己的原型
* 4.圣杯模式
*/
//共享原型
Father.prototype.lastName = "Chen";
function Father(){
}
function Son(){
}
Son.prototype = Father.prototype;
var son = new Son();
var father = new Father();
//圣杯模式
// Father.prototype
//
// functionF(){}
// F.prototype = Father.prototype
//
// Son.prototype = new F();
//
// Father Son
//
//圣杯模式(继承最终写法)Target继承自Origin
//第一种写法
function inherit(Target, Origin){
function F(){};
F.prototype = Origin.prototype;
Target.prototype = new F();
Target.prototype.constuctor = Target;
Target.prototype.uber = Origin.prototype;//真正继承自谁
}
//第二种写法(建议)
var inherit = (function (){
var F = function(){};
return function (Target, Origin){
F.prototype = Origin.prototype;
Target.prototype = new F();
Target.prototype.constuctor = Target;
Target.prototype.uber = Origin.prototype;
}
}());
Trips
//命名空间---管理变量,防止污染全局,适用于模块化开发
//想实现方法的连续调用,return this
//属性表示方法 obj.prop obj["prop"]
对象的枚举
// for in
var obj = {
name :"cyq",
age : 21,
sex : 'male',
height : 150,
weight : 47
}
for (var prop in obj){
//console.log(obj.prop ---> obj['prop'])
//结果为undefined
console.log(prop + " : " + obj[prop]);
}
// hasOwnProPerty
//判断属性是不是他自己的
var obj = {
name :"cyq",
age : 21,
sex : 'male',
height : 150,
weight : 47,
__proto__ :{
lastName : "deng"
}
}
for (var prop in obj){
if(obj.hasOwnProperty(prop)){
console.log(prop + " : " + obj[prop]);//打印结果没有deng
}
}
// in 只能判断这个对象能不能访问到这个属性
// ** instanceof
// A对象 是不是 B构造函数构造出来的
// ** 看A对象的原型链上 有没有 B的原型
// A instanceof B 返回true/false
this
函数预编译过程 this --> window
全局作用域里 this --> window
call/apply 可以改变函数运行时this指向
obj.func(); func()
11. arguments、克隆、数组、类数组
arguments
//arguments.callee ---> 指向函数自身引用
//obj.caller
克隆
// 深度克隆
//遍历对象 for(var prop in obj)
//1.判断是不是原始值 typeof() object
//2.判断是数组还是对象 instanceof toString constructor
//3.建立相应的数据或对象
var obj = {
name : "cyq",
age : 18,
card : ['123', 'abc'],
wife : {
name : 'bjw',
son : {
name : 'byz'
}
}
}
var obj1 = {
}
function deepClone(origin, target){
var target = target || {},
toStr = Object.prototype.toString,
arrStr = "[object Array]";
for(var prop in origin){
if(origin.hasOwnProperty(prop)){
if(origin[prop] !== "null" && typeof(origin[prop]) == 'object'){
// if(toStr.call(origin[prop]) == arrStr){
// target[prop] = [];
// }else{
// target[prop] ={};
// }
target[prop] = toStr.call(origin[prop]) == arrStr ? [] : {};
deepClone(origin[prop], target[prop]);
}else{
target[prop] = origin[prop];//浅克隆
}
}
}
return target;
}
deepClone(obj, obj1);
数组
//数组的定义
//new Array(length/content);
//字面量 var arr = [1,2,,,3,4];
//数组的读和写
arr[num]//不可以溢出读 溢出读出undefined
arr[num] = xxx;//可以溢出写
//数组常用的方法 *es3.0 es5.0 es6.0
//改变原数组
//1.push
var arr = [];
arr.push(10);//添加数据,数组的最后一位,返回数组的长度
arr.push(1,2,3,4,5,6);
// Array.prototype.push = function(){
// for(var i = 0; i < arguments.length; i ++){
// this[this.length] = arguments[i];
// }
// return this.length;
// }
//2.pop
var num = arr.pop();//把数组最后一位剪切出去
//3.unshift在数组的前面增加数据
arr.unshift(1);
arr.unshift(1,2,3);
//4.shift
var num = arr.shift();//把数组的第一位剪切出去
//5.reverse
arr.reverse();//逆转数组,返回逆转后的数据
//6.splice (可用于往某一位中间添加数据)
//arr.splice(从第几位开始,截取多少的长度,在切口处添加新的数据);
arr.splice(1,2);//返回截取的数据
arr.splice(1,1,0,0,0,0);//在切口加数据,后面的参数为无穷个,返回截取的数组
arr.splice(-1,1);//-1为倒数第一位,负数就+length
//7.sort 排序
arr.sort();//升序 ASCII码排序
arr.sort().reverse();//降序
//必须写两个形参 看返回值
//①当返回值为负数时,那么前面的书放在前面
//②为正数 那么后面的数在前
//③为0 不动
arr.sort(function(a, b){
if(a > b){//升序 降序(a < b)
return 1;
}else{
return -1;
}
});
arr.sort(function(a, b){
return a - b;//升序 降序(b - a)
});
//乱序
arr.sort(function(a, b){
return Math.random() - 0.5;
});
//对象排序
arr.sort(function(a, b){
return a.age - b.age;
});
//不改变原数组
//1.concat
arr.concat(arr1);//把arr1拼在arr后面形成一个全新的数组
//2.slice
//slice(从该位开始截取,截取到该位)
var newArr = arr.slice(1,2);
arr.slice(1);//从第一位开始截取到最后
arr.slice();//截取全部
//3.join -- 不传参数按照,连接
arr.join("-");//返回字符串,把每一位连接起来,按照括号中的字符,例如"1-2-3-4"
//4.split--string拆分为数组
str.split('-');//"1-2-3-4" ---> ['1','2','3','4']
类数组
- 可以利用属性名模拟数组的特性
- 可以动态的增长
length
属性 - 如果强行让类数组调用
push
方法,则会根据length
属性值的位置进行属性的扩充
var obj = {
"0" : 'a',
"1" : 'b',
"2" : 'c',
"name" : 'cyq',
"age" : 18,
"length" : 3,
"push" : Array.prototype.push,
"splice" : Array.prototype.splice
}
//属性要为索引(数字)属性 必须有length属性 最好加上push
Array.prototype.push = function(target){
obj[obj.length] = target;
obj.length ++;
}
//优点:把数组和对象的方法拼到一起
12. 封装type、数组去重
封装type
// typeof([]) -- Array
// typeof({}) -- Object
// typeof(function) -- Object
// typeof(new Number()) -- number Object
// typeof(123) -- number
function type(target){
//1.分两类 原始值 引用值
//2.区分引用值
var ret = typeof(target);
var template ={
"[object Array]" :"array",
"[object Object]" : "object",
"[object Number]" : "number - object",
"[object Boolean]" : "boolean - object",
"[object String]" : "string - object"
}
if(target === null){
return "null";
}else if(ret == "object"){
//数组
//对象
//包装类Object.prototype.toString
var str = Object.prototype.toString.call(target);
return template[str];
}else{
return ret;
}
}
数据去重
//要求在原型链上编程
//数组去重,利用对象属性名不重复
Array.prototype.unique = function(){
var temp = {},
arr = [],
len = this.length;
for(var i = 0; i < len; i ++){
if(!temp[this[i]]){
//当前对象这个属性没有值,undefined
temp[this[i]] = "abc";
arr.push(this[i]);
}
}
return arr;
}
13. try…catch、es5
try…catch
try{
//在try里面发生错误,不会执行错误后的try里面的代码
}catch(e){//error error.message error.name --> error
console.log(e.message + " : " + e.name);
}
//Error.name
//1. EvalError:eval()的使用与定义不一致
//2. RangeError:数值越界
//3. ReferenceError:非法或不能识别的引用数值
//4. SyntaxError:发生语法解析错误
//5. TypeError:操作数类型错误
//6. URIError:URI处理函数使用不当
es5
//基于es3.0的 + es5.0的新增方法
//es3.0 和 es5.o产生冲突的部分
//es5.0严格模式 产生冲突的部分使用es5.0
//es5.0严格模式启动(第一行)
"use strict";
两种用法
- 全局严格模式
- 局部函数内严格模式(推荐)
规定
- 不支持with,arguments.callee,func.caller
- 变量赋值前必须声明
- 局部的this必须被赋值(赋什么就是什么)
- 拒绝重复属性和参数
14. DOM
什么是DOM
- DOM:Document Object Model
- DOM定义了表示和修改文档所需的方法。DOM对象即为宿主对象,由浏览器厂商定义,用来操作html和xml功能的一类对象的集合。也有人称DOM是对HTML以及XML的标准编程接口。
DOM基本操作
对节点的增删改查
- 查
//查看元素节点
//document代表整个文档
document.getElementById('')//元素id
.getElementsByTagName('div')[0]//标签名 类数组
.getElementsByName()//只有部分标签name可生效(表单,表单元素,img,iframe)
.getElementByClassName()//类名 -> ie8和ie8以下的ie版本中没有 可以多个class一起
//非实时
.querySelector()//(css选择器) 在ie7和ie7以下版本中没有
.querySelectorAll()//一组 在ie7和ie7以下版本中没有
//遍历节点树
// parentNode -> 父节点(最顶端的parentNode为#document);
// childNodes -> 子节点们
// firstChild -> 第一个子节点
// lastChild -> 最后一个子节点
// nextSibling -> 后一个兄弟节点
// previousSibling -> 前一个兄弟节点
// 基于元素节点树的遍历
// parentElement -> 返回当前元素的父元素节点(IE不兼容)
// children -> 只返回当前元素的元素子节点
// node.childElementCount === node.children.length当前元素节点的子元素的个数
// firstElementChild -> 返回的是第一个元素节点(IE不兼容) 9及以下
// lastElementChild -> 返回的是最后一个元素节点(IE不兼容)
// nextElementSibling/previousElementSibling -> 返回后一个/前一个兄弟元素节点
节点的类型
- 元素节点 —— 1
- 属性节点 —— 2
- 文本节点 —— 3
- 注释节点 —— 8
- document —— 9
- DocumentFragment —— 11
获取节点类型 nodeType
节点的四个属性
nodeName
:元素的标签名,以大写形式表示,只读nodeValue
:Text节点或Comment节点的文本内容,可读写nodeType
:该节点的类型,只读attributes
:Element节点的属性集合节点的一个方法
Node.hasChildNodes()
; / true / false
DOM基本操作
getElementById
方法定义在Document.prototype
上,即Element节点上不能使用getElementByName
方法定义在HTMLDocument.prototype
上,即非html中的document不能使用(xml,document,Element)getElementByTagName
方法定义在Document.prototype
和Element.prototype
上HTMLDocument.prototype
定义了一些常用的属性,body,head分别指代HTML文档中的<body>
、<head>
标签Document.prototype
上定义了documentElement
属性,指代文档的根元素,在HTML文档中,他总指代<html>
元素getElementByClassName
、querySelectorAll
、querySelector
在Document.prototype
,Element.prototype
类中均有定义
增加一个元素节点
document.createElement();//创建元素节点***
document.createTextNode();//创建文本节点
document.createComment();//创建注释节点
document.createDocumentFragment();//创建文档碎片节点
插入操作
// PARENTNODE.appendChild();
// PARENTNODE.insertBefore(a,b); 在b之前插入a
删除操作
// parent.removeChild(); 剪切
// child.remove(); 销毁
替换
// parent.replaceChild(new, origin); 拿新的替换老的 剪切
Element节点的一些属性
innerHTML
获取HTML内容,改变HTML里面的内容(覆盖原内容)innerText
取文本、写文本(覆盖结构)(火狐不兼容)/textContent
(老版本IE不好使)
Element节点的一些方法
ele.setAttribute()
ele.getAttribute()
DOM基本操作
//查看滚动条的滚动距离
window.pageXOffset//横向
window.pageYOffset//纵向
//IE8和IE8一下的浏览器 兼容性混乱
document.body.scrollLeft
document.body.scrollTop
document.documentElement.scrollTop
document.documentElement.scrollLeft
document.body.scrollLeft + document.documentElement.scrollLeft//取值同时相加
//查看可视区窗口的尺寸
window.innerWidth//宽度
window.innerHeight//高度
//IE8及以下
//标准模式下
document.documentElement.clientWidth
document.documentElement.clientHeight
//怪异模式下
document.body.clientHeight
document.body.clientWidth
//查看元素几何尺寸
getBoundingClientRect();
//兼容性很好
//返回一个对象 对象里有left top right bottom
//IE里没有height width
//非实时的
//查看元素的尺寸
dom.offsetWidth
dom.offsetHeight
//查看元素的位置
//对于无定位父级的元素,返回相对文档的坐标;对于有定位的父级,返回相对于最近的有定位的父级的坐标
dom.offsetLeft
dom.offsetTop
//返回最近的有定位的父级
dom.offsetParent
//让滚动条滚动
//window上有三个方法 将x,y传入
scroll();//让滚动条滚动到当前位置
scrollTo();
scrollBy();//累加滚动距离
DOM树结构
15. date对象、定时器
日期对象:Date() 是系统提供好的
var date = new Date();//非实时
date.getDate();//一个月中的某一天 (1 ~ 31)
date.getDay();//一周中的第几天 (周日为0) (0 ~ 6)
date.getMonth();//返回月份(0 ~ 11)
date.getFullYear();//返回年份四位数
date.getHours();//小时
date.getMinutes();//分钟
date.getSeconds();//秒钟
date.getMilliseconds();//毫秒
date.getTime();//***返回 1970 年 1 月 1 日至今的毫秒数
定时器
// 定时器
//1.
var timer1 = setInterval(function (){
//时间不准
}, 1000);//每隔1000毫秒执行一次函数
clearInterval(timer1);//唯一标识
//2.
var timer2 = setTimeout(function(){
}, 1000);//在1000毫秒之后执行函数,只执行一次
clearTimeout(timer2);
//全局对象Window上的方法,内部函数this执行window
//setInterval("func()", 1000);
16. 脚本化CSS
读写css
dom.style.prop
//可读写行间样式 没有兼容性问题 碰到float的保留字属性 在前面加上css
dom.style.cssFloat
//复合属性必须拆解,组合单词变成小驼峰式写法
查询计算样式
window.getComputedStyle(ele, null);//获取ele元素显示出来的css属性,包括默认值
//对象
//计算样式只读
//返回的计算样式的值都是绝对值 没有相对单位
// IE8及IE8以下不兼容
ele.currentStyle
//IE
17. 事件
如何绑定事件处理函数
ele.onxxx = function(event){}
- 兼容性很好,但是一个元素的同一个事件上只能绑定一个处理程序
- 基本等同于写在HTML行间上
obj.addEventListener(type, fn, false);
- IE9以下不兼容,可以为一个时间绑定多个处理程序
obj.attachEvent('on' + type, fn);
- IE独有,一个事件同样可以绑定多个处理程序
事件处理程序的运行环境
ele.onxxx = function(event){}
- 程序this指向是dom元素本身
obj.addEventListener(type, fn, false);
- 程序this指向是dom元素本身
obj.attachEvent('on' + type, fn);
- 程序this指向window
解除事件处理程序
ele.onclick = false/''/null;
ele.removeEventListener(type, fn, false);
ele.detachEvent('on' + type, fn);
- 注:若绑定匿名函数,则无法解除
事件处理模型
- 事件冒泡
结构上(非视觉上)嵌套关系的元素,会存在事件冒泡的功能,同一事件,自子元素冒泡向父元素。(自底向上) - 事件捕获
- 结构上(非视觉上)嵌套关系的元素,会存在事件捕获的功能,同一事件,自父元素捕获至子元素(事件源元素)。(自顶向下)
- IE没有捕获事件
- 触发顺序,先捕获,后冒泡
focus
,blur
,change
,submit
,reset
,select
等事件不冒泡
取消冒泡和阻止默认事件
- 取消冒泡
- W3C标准
event.stopPropagation();
但不支持IE9以下版本 - IE独有
event.cancelBubble = true;
- 封装取消冒泡的函数
stopBubble(event)
- 阻止默认事件
- 默认事件 — 表单提交,a标签跳转,右键菜单等
return false;
以对象属性的方式注册的时间才生效event.preventDefault();
W3C标准,IE9以下不兼容event.returnValue = false;
兼容IE
javascript:void()//相当于返回括号里的内容
javascript:void(0);// return 0
事件对象
// event || window.event 用于IE
//事件源对象 这俩chrome都有
event.target //火狐只有这个
event.srcElement //IE只有这个
event.target || event.srcElement
事件委托
利用事件冒泡,和事件源对象进行处理
优点:
- 性能 不需要循环所有的元素一个个绑定事件
- 灵活 当有新的子元素时不需要重新绑定事件
鼠标事件
onclick 点击
onmousedown 鼠标按下
onmouseup 鼠标弹起
contextmenu 右键产生菜单
mousemove 鼠标移动
mouseover 鼠标闯进区域
mouseout 鼠标离开区域
mouseenter 鼠标移入某元素
mouseleave 鼠标移出某元素
用button属性来区分鼠标的按键, 0左键/1/2右键 (mouseup mousedown)
click事件只能监听左键
键盘事件
keydown > keypress > keyup
keydown可以响应任意键字符 keypress只能响应字符类键盘按键
keypress返回ASCII码,可以转换成相应字符
文本操作事件
input
change
鼠标聚焦和失去焦点是否发生改变focus
聚焦blur
失去焦点
窗体操作类
scroll
滚动条滚动load
18. json、异步加载、时间线
json
JSON.parse(); //string --> json
JSON.stringify(); //json --> string
异步加载
js加载的缺点:加载工具方法没必要阻塞文档,过得js加载会影响页面效率,一旦网速不好,那么整个网站将等待js加载而不进行后续渲染等工作。有些工具方法需要按需加载,用到再加载,不用不加载。
JavaScript异步加载的三种方案
- defer异步加载,但要等到dom文档全部解析玩才会被执行,只有IE能用,也可以将代码写到内部;(执行时不阻塞页面)
- async异步加载,加载完就执行,async只能加载外部脚本,不能把js写在script标签里;(执行时不阻塞页面)
- 创建script,插入到DOM中,加载完毕后callBack(按需加载)
js加载时间线
- 创建
Document
对象,开始解析Web页面,解析HTML
元素和他们的文本内容后添加Element
对象和Text
节点到文档中。这个阶段document.readyState = 'loading'
。 - 遇到
link
外部css,创建线程加载,并继续解析文档。 - 遇到
script
外部js,并且没有一个设置async
、defer
,浏览器加载,并阻塞,等待js加载完成并执行该脚本, 然后继续解析文档。 - 遇到
script
外部js,并且设置有async
、defer
,浏览器创建线程加载,并继续解析文档。对于async
属性的脚本,脚本加载完成后立即执行。(异步禁止使用document.write()
) - 遇到
img
等,先正常解析dom结构,然后浏览器异步加载src
,并继续解析文档。 - 当文档解析完成后,
document.readyState = 'interactive'
。 - 文档解析完成后,所有设置有defer的脚本会按照顺序执行。(注意与
async
的不同,但同样禁止使用document.write()
) document
对象触发DOMContentLoaded
事件,这也标志着程序执行从同步脚本执行阶段,转化为事件驱动阶段。- 当所有
async
的脚本加载完成并执行后、img
等加载完成后,document.readyState = 'complete',window
对象触发load
事件。 - 从此,以异步响应方式处理用户输入、网络事件等。