一、数据类型的转换
1.自动数据类型转换
其他数据类型转换为字符串:
var result = “你” + “好” //结果 你好 类型是string
var result = “1” + 1; //结果 11 类型是string
var result = “1” + true //结果 1true 类型是string
var result = “1” + undefined ; //结果 1undefined 类型是string
var result = “1” + null; //结果 1null 类型是string
//总结:任何类型的数据和字符串类型的数据做相加(+)操作时,其他数据类型会自动的转换为字符串类型。此时的相加(+)不再是数学意义上的加法,而是表示“拼接”的意思。
其他数据类型转换为数字:
var result = 1 - “2”; //结果 -1 类型是 number
var result = 1 - “我”; //结果 NaN 类型是 number
【注】NaN是一个值,这个值的类型是(number)。表现的意思是“不是一个数字”;
//规则:任何数据除了和字符串做相加运算外,与NaN做算术运算的结果始终都是NaN。包括NaN本身和NaN做运算的结果也是NaN。
//字符串是数值会自动的转换为数字,否则会转换为NaN
var result = 1 * “1”; //结果 1 类型是 number
var result = 1 / “1”; //结果 1 类型是 number
var result = 1 + true; //结果 2 类型是number
var result = 1 * false; //结果 0 类型是 number
true会自动的转换为1 false会自动的转换为0
var result = 1 + null ; //结果是1 类型是number
var result = 1 + undefined //结果是NaN 类型是number
null会自动的转换为0, undefined会自动的转为NaN
// 总结:任何其他数据除了和字符串做相加操作外,与数字类型做算术运算时,其他数据会自动的转换为数字。
// 其他数据转换布尔:Boolean(数据);数字转Boolean非0数字->true;0 --> false;字符串转Boolean非空字符串(包含空格)-> true;空字符串 -->falsenull和undefined转换Boolean都是false
2.强制数据类型转换
//字符串转换数字类型:parseInt()、parseFloat()
parseInt() 是把其它类型转换为整型;
parseFloat();是把其它类型转换为浮点型(小数)
Number(数据); 数字
//认识NaN:他是一种特殊的Number类型结果,代表意外转换的数字,NaN和任何东西都是不等的。
3.隐式类型转换
+号有两种含义:数学中的+号运算符;字符串的拼接。优先字符串拼接,所以在检测到+号左右两边存在字符串的时候,会自动将另一边不是字符串的数据,转成字符串,再进行操作
除了+号有两层意义为外,-/%号只有数学意义,所以当进行-/%的时候,默认将运算符两边的数据类型隐式转换成数字类型再进行运算
if()中只需要布尔值,那么在if判断中,会把括号内所有的数据类型,都隐式转换成布尔型。 在if()中,非零数字都会转成true,非空字符串都会转成true;这是两条基础规则
二、js预编译
function fn(){
console.log(a); //undefined
var a = 10;
console.log(a); // 10
}
上面代码等价于下面代码
function fn(){
var a;
console.log(a);
a = 10;
console.log(a);
}
fn();
console.log(b); // undefined
var b = 20;
console.log(b); // 20
// 找到所有的var关键字,把var的声明,提升到作用域最开始的位置(程序一开始的位置)
// var声明的变量会提升,但赋值会在原本的位置
脚本语言
弱类型
解释型
先解释(编译)
声明提升
var声明的变量
提前声明,原位赋值
function声明的函数
整体提升
提升到当前作用域的开始的位置
再执行
执行
整体提升
fn();
function fn(){
console.log("admin") // admin
}
// 找到所有function关键字,把function声明的函数整体提升到作用域最开始的位置
fn(); // 报错 fn is not defined
console.log(fn); // undefined
var fn=function(){
console.log("admin");
}
console.log(fn); // 123
fn();
// 提升的是var 函数并没有提升
console.log(fn)
function fn(){
console.log("123");
}
f,h,h,1,w
console.log(a); // f
var a = "hello";
console.log(a); // h
function a(){};
console.log(a); // h
var a = 123;
console.log(a); // 123
a = "world";
console.log(a); // w
上面代码等价于下面代码
var a;
var a;
function a(){};
console.log(a); // f
a = "hello";
console.log(a); // h
console.log(a); // h
a = 123;
console.log(a); // 123
a = "world";
console.log(a); // w
三、数组方法概括
方法 | 功能 | 参数 | 返回值 | 是否改变原数据 |
---|---|---|---|---|
push() | 最后位置新增 | 要增加的数据(可多个) | 数组增加之后的长度 | Y |
unshift() | 开始位置新增 | 要增加的数据(可多个) | 数组增加之后的长度 | Y |
pop() | 删除最后一位 | 无 | 删除的数据 | Y |
shift() | 删除第一位 | 无 | 删除的数据 | Y |
join() | 将数组转成字符 | 转成字符后,每个数据之间的间隔 | 转换结果 | N |
splice() | 删除并替换指定位置的数据 | 2个参数: 1:起始索引 2:删除个数 2个以上: 1:起始索引 2:个数 3:插入的数据 不插入数据只删除 | 删除了的数据 | Y |
slice() | 截取并拷贝出子数组 | 1个:指定位置开始截取到结束 2个:指定位置到结束位置的前一个 | 截取并拷贝出的新数组 | N |
concat() | 将数据合并到新数组并返回 | 任何数据,如果是数组,会被展开再合并进去 | 合并之后的新数组 | N |
reverse() | 翻转数据 | 无 | 翻转之后的数组,就是修改之后的原数组 | Y |
sort() | 排序,默认排序规则是字符的比较规则(升序)逐位比较 | 函数:function(m,n){return n-m} m-n, 升序 n-m,降序 | 排序之后的数组 | Y |
indexOf() | 返回指定数据所在索引 | 1:要查找的数据 2:起始位置(可选) | 索引或-1 | N |
forEach() | 遍历数组 | 函数:该函数自带三个形参 1:数据;2:索引;3:数组自身 | undefined | N |
map() | 遍历数组,修改数据 | 同forEach | 数组(数据是每次遍历到数组中数据时的返回值) | N |
filter() | 遍历数组,过滤数据 | 同 forEach | 数组(数据是每次遍历到数组中数据时的返回值为true的值 | N |
some() | 遍历数组,检测所有数据 | 同forEach | 布尔值(遍历数组时,只要有一个返回true,即为true,停止遍历) | N |
every() | 遍历数组,检测所有数据 | 同forEach | 布尔值(遍历数组中数据时,必须全部返回true,才为true,只要有一个false就是false,停止遍历) | N |
reduce() | 遍历数组 归并 | 函数:自带4个形参:上一个值;数据;索引;数组自身 指定默认情况下的上一个值未指定:默认找数组第一个数据 | 最后一个遍历的返回值 | N |
reduceRight() | 遍历数组 反向归并 | 同reduce | 同reduce | N |
方法详解
1.concat()
**功能:**用于连接两个或多个数组,该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
**参数:**concat(data1,data2,…);所有参数可选,要合并的数据;data为数组时,将data合并到原数组;data为具体数据时直接添加到原数组尾部;省略时创建原数组的副本。
var arr1 = [1,2,3]
var arr2 = arr1.concat();
console.log(arr1); //[1,2,3]---原数组
console.log(arr1 === arr2); //false
console.log(arr2); //[1,2,3]---原数组的副本
console.log(arr1.concat("hello","world")); //[1,2,3,"hello","world"]
console.log(arr1.concat(["a","b"],[[3,4],{"name":"admin"}])); //[1,2,3,"a","b",[3,4],{"name":"admin"}]
console.log(arr1); //[1,2,3]---原数组未改变
2.join()
**功能:**根据指定分隔符将数组中的所有元素放入一个字符串,并返回这个字符串。
**参数:**join(str);参数可选,默认为","号,以传入的字符作为分隔符。
var arr = [1,2,3];
console.log(arr.join()); //1,2,3
console.log(arr.join("-")); //1-2-3
console.log(arr); //[1,2,3]---原数组未改变
3.pop()
**功能:**方法用于删除并返回数组的最后一个元素。
**参数:**无
var arr = [1,2,3];
console.log(arr.pop()); //3
console.log(arr); //[1,2]---原数组改变
4.shift()
**功能:**方法用于删除并返回数组的第一个元素。
**参数:**无
var arr = [1,2,3]
console.log(arr.shift()); //1
console.log(arr); //[2,3]---原数组改变
5.unshift()
**功能:**向数组的开头添加一个或更多元素,并返回新的长度。
**参数:**unshift(newData1, newData2, …)
var arr = [1,2,3];
console.log(arr.unshift("hello")); //4
console.log(arr); //["hello",1,2,3]---原数组改变
console.log(arr.unshift("a","b")); //6
console.log(arr); //["a","b","hello",1,2,3]---原数组改变
6.push()
**功能:**向数组的末尾添加一个或更多元素,并返回新的长度。
**参数:**push(newData1, newData2, …)
var arr = [1,2,3];
console.log(arr.push("hello")); //4
console.log(arr); //[1,2,3,"hello"]---原数组改变
console.log(arr.push("a","b")); //6
console.log(arr); //[1,2,3,"hello","a","b"]---原数组改变
7.reverse()
**功能:**颠倒数组中元素的顺序。
**参数:**无
var arr = [1,2,3];
console.log(arr.reverse()); //[3,2,1]
console.log(arr); //[3,2,1]---原数组改变
8.slice()
**功能:**可从已有的数组中返回选定的元素。该方法接收两个参数slice(start,end),strat为必选,表示从第几位开始;end为可选,表示到第几位结束(不包含end位),省略表示到最后一位;start和end都可以为负数,负数时表示从最后一位开始算起,如-1表示最后一位。
**参数:**slice(startIndex, endIndex)
var arr = ["Tom","Jack","Lucy","Lily","May"];
console.log(arr.slice(1,3)); //["Jack","Lucy"]
console.log(arr.slice(1)); //["Jack","Lucy","Lily","May"]
console.log(arr.slice(-4,-1)); //["Jack","Lucy","Lily"]
console.log(arr.slice(-2)); //["Lily","May"]
console.log(arr.slice(1,-2)); //["Jack","Lucy"]
console.log(arr); //["Tom","Jack","Lucy","Lily","May"]---原数组未改变
9.sort()
**功能:**对数组中的元素进行排序,默认是升序。
var arr = [6,1,5,2,3];
console.log(arr.sort()); //[1, 2, 3, 5, 6]
console.log(arr); //[1, 2, 3, 5, 6]---原数组改变
但是在排序前,会先调用数组的toString方法,将每个元素都转成字符之后,再进行排序,此时会按照字符串的排序,逐位比较,进行排序。
var arr = [6,1024,52,256,369];
console.log(arr.sort()); //[1024, 256, 369, 52, 6]
console.log(arr); //[1024, 256, 369, 52, 6]---原数组改变
**参数:**sort(callback)
如果需要按照数值排序,需要传参。sort(callback),callback为回调函数,该函数应该具有两个参数,比较这两个参数,然后返回一个用于说明这两个值的相对顺序的数字(a-b)。其返回值如下:
若 a 小于 b,返回一个小于 0 的值。
若 a 等于 b,则返回 0。
若 a 大于 b,则返回一个大于 0 的值。
var arr = [6,1024,52,256,369];
console.log(arr.sort(fn)); //[6, 52, 256, 369, 1024]
console.log(arr); //[6, 52, 256, 369, 1024]---原数组改变
function fn(a,b){
return a-b;
}
10.splice()
**功能:**向数组中添加,或从数组删除,或替换数组中的元素,然后返回被删除/替换的元素。
**参数:**splice(start,num,data1,data2,…); 所有参数全部可选。
1>不传参时:无操作
var arr = ["Tom","Jack","Lucy","Lily","May"];
console.log(arr.splice()); //[]
console.log(arr); //["Tom","Jack","Lucy","Lily","May"]---无操作
2>只传入start:表示从索引为start的数据开始删除,直到数组结束
var arr = ["Tom","Jack","Lucy","Lily","May"];
console.log(arr.splice(2)); //["Lucy", "Lily", "May"]
console.log(arr); //["Tom", "Jack"]---原数组改变
3>传入start和num:表示从索引为start的数据开始删除,删除num个
var arr = ["Tom","Jack","Lucy","Lily","May"];
console.log(arr.splice(2,2)); //["Lucy", "Lily"]
console.log(arr); //["Tom", "Jack", "May"]---原数组改变
4>传入更多:表示从索引为start的数据开始删除,删除num个,并将第三个参数及后面所有参数,插入到start的位置
var arr = ["Tom","Jack","Lucy","Lily","May"];
console.log(arr.splice(2,2,"a","b")); //["Lucy", "Lily"]
console.log(arr); //["Tom", "Jack", "a", "b", "May"]---原数组改变
5>传入更多:表示从索引为start的数据开始删除,删除num个,并将第三个参数及后面所有参数,插入到start的位置
var arr = ["Tom","Jack","Lucy","Lily","May"];
console.log(arr.splice(2,0,"a","b")); //[]
console.log(arr); //["Tom", "Jack", "a", "b", "Lucy", "Lily", "May"]---原数组改变
11.toString()
**功能:**转换成字符串,类似于没有参数的join()。该方法会在数据发生隐式类型转换时被自动调用,如果手动调用,就是直接转为字符串。
**参数:**无
var arr = [1,2,3];
console.log(arr.toString()); //1,2,3
console.log(arr); //[1,2,3]---原数组未改变
12.valueOf()
**功能:**返回数组的原始值(一般情况下其实就是数组自身),一般由js在后台调用,并不显式的出现在代码中
**参数:**无
var arr = [1,2,3];
console.log(arr.valueOf()); //[1,2,3]
console.log(arr); //[1,2,3]
//为了证明返回的是数组自身
console.log(arr.valueOf() == arr); //true
13.indexOf()
**功能:**根据指定的数据,从左向右,查询在数组中出现的位置,如果不存在指定的数据,返回-1。该方法是查询方法,不会对数组产生改变。
**参数:**indexOf(value, start);value为要查询的数据;start为可选,表示开始查询的位置,当start为负数时,从数组的尾部向前数;如果查询不到value的存在,则方法返回-1
var arr = ["h","e","l","l","o"];
console.log(arr.indexOf("l")); //2
console.log(arr.indexOf("l",3)); //3
console.log(arr.indexOf("l",4)); //-1
console.log(arr.indexOf("l",-1)); //-1
console.log(arr.indexOf("l",-3)); //2
14.lastIndexOf()
**功能:**根据指定的数据,从右向左,查询在数组中出现的位置,如果不存在指定的数据,返回-1。该方法是查询方法,不会对数组产生改变。
**参数:**lastIndexOf(value, start);value为要查询的数据;start为可选,表示开始查询的位置,当start为负数时,从数组的尾部向前数;如果查询不到value的存在,则方法返回-1
var arr = ["h","e","l","l","o"];
console.log(arr.lastIndexOf("l")); //3
console.log(arr.lastIndexOf("l",3)); //3
console.log(arr.lastIndexOf("l",1)); //-1
console.log(arr.lastIndexOf("l",-3)); //2
console.log(arr.lastIndexOf("l",-4)); //-1
15.forEach()
**功能:**ES5新增方法,用来遍历数组,该方法没有返回值。forEach接收的回调函数会根据数组的每一项执行,该回调函数默认有三个参数,分别为:遍历到的数组的数据,对应的索引,数组自身。
**参数:**forEach(callback);callback默认有三个参数,分别为value,index,self。
var arr = ["Tom","Jack","Lucy","Lily","May"];
var a = arr.forEach(function(value,index,self){
console.log(value + "--" + index + "--" + (arr === self));
})
// 打印结果为:
// Tom--0--true
// Jack--1--true
// Lucy--2--true
// Lily--3--true
// May--4--true
console.log(a); //undefined---forEach没有返回值
//该方法为遍历方法,不会修改原数组
16.map()
**功能:**1.同forEach功能;2.map的回调函数会将执行结果返回,最后map将所有回调函数的返回值组成新数组返回。
**参数:**map(callback);callback默认有三个参数,分别为value,index,self。
//功能1:同forEach
var arr = ["Tom","Jack","Lucy","Lily","May"];
var a = arr.map(function(value,index,self){
console.log(value + "--" + index + "--" + (arr === self))
})
// 打印结果为:
// Tom--0--true
// Jack--1--true
// Lucy--2--true
// Lily--3--true
// May--4--true
//功能2:每次回调函数的返回值被map组成新数组返回
var arr = ["Tom","Jack","Lucy","Lily","May"];
var a = arr.map(function(value,index,self){
return "hi:"+value;
})
console.log(a); //["hi:Tom", "hi:Jack", "hi:Lucy", "hi:Lily", "hi:May"]
console.log(arr); //["Tom", "Jack", "Lucy", "Lily", "May"]---原数组未改变
17.filter()
**功能:**1.同forEach功能;2.filter的回调函数需要返回布尔值,当为true时,将本次数组的数据返回给filter,最后filter将所有回调函数的返回值组成新数组返回(此功能可理解为“过滤”)。
**参数:**filter(callback);callback默认有三个参数,分别为value,index,self。
//功能1:同forEach
var arr = ["Tom","Jack","Lucy","Lily","May"];
var a = arr.filter(function(value,index,self){
console.log(value + "--" + index + "--" + (arr === self))
})
// 打印结果为:
// Tom--0--true
// Jack--1--true
// Lucy--2--true
// Lily--3--true
// May--4--true
//功能2:当回调函数的返回值为true时,本次的数组值返回给filter,被filter组成新数组返回
var arr = ["Tom","Jack","Lucy","Lily","May"];
var a = arr.filter(function(value,index,self){
return value.length > 3;
})
console.log(a); //["Jack", "Lucy", "Lily"]
console.log(arr); //["Tom", "Jack", "Lucy", "Lily", "May"]---原数组未改变
18.every()
**功能:**判断数组中每一项是否都满足条件,只有所有项都满足条件,才会返回true。
**参数:**every()接收一个回调函数作为参数,这个回调函数需要有返回值,every(callback);callback默认有三个参数,分别为value,index,self。
**功能1:**当回调函数的返回值为true时,类似于forEach的功能,遍历所有;如果为false,那么停止执行,后面的数据不再遍历,停在第一个返回false的位置。
//demo1:
var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
var a = arr.every(function(value,index,self){
console.log(value + "--" + index + "--" + (arr == self))
})
// 打印结果为:
// Tom--0--true
//因为回调函数中没有return true,默认返回undefined,等同于返回false
//demo2:
var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
var a = arr.every(function(value,index,self){
console.log(value + "--" + index + "--" + (arr == self))
return value.length < 4;
})
// 打印结果为:
// Tom--0--true
// abc--1--true
// Jack--2--true
//因为当遍历到Jack时,回调函数到return返回false,此时Jack已经遍历,但是后面数据就不再被遍历了
//demo3:
var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
var a = arr.every(function(value,index,self){
console.log(value + "--" + index + "--" + (arr == self))
return true;
})
// 打印结果为:
// Tom--0--true
// abc--1--true
// Jack--2--true
// Lucy--3--true
// Lily--4--true
// May--5--true
//因为每个回调函数的返回值都是true,那么会遍历数组所有数据,等同于forEach功能
**功能2:**当每个回调函数的返回值都为true时,every的返回值为true,只要有一个回调函数的返回值为false,every的返回值都为false
//demo1:
var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
var a = arr.every(function(value,index,self){
return value.length > 3;
})
console.log(a); //false
//demo2:
var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
var a = arr.every(function(value,index,self){
return value.length > 2;
})
console.log(a); //true
19.some()
**功能:**判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回true。
**参数:**some()接收一个回调函数作为参数,这个回调函数需要有返回值,some(callback);callback默认有三个参数,分别为value,index,self。
**功能1:**因为要判断数组中的每一项,只要有一个回调函数返回true,some都会返回true,所以与every正好相反,当遇到一个回调函数的返回值为true时,可以确定结果,那么停止执行,后面都数据不再遍历,停在第一个返回true的位置;当回调函数的返回值为false时,需要继续向后执行,到最后才能确定结果,所以会遍历所有数据,实现类似于forEach的功能,遍历所有。
//demo1:
var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
var a = arr.some(function(value,index,self){
console.log(value + "--" + index + "--" + (arr == self))
return value.length > 3;
})
// 打印结果为:
// Tom--0--true
// abc--1--true
// Jack--2--true
//demo2:
var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
var a = arr.some(function(value,index,self){
console.log(value + "--" + index + "--" + (arr == self))
return true;
})
// 打印结果为:
// Tom--0--true
//demo3:
var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
var a = arr.some(function(value,index,self){
console.log(value + "--" + index + "--" + (arr == self))
return false;
})
// 打印结果为:
// Tom--0--true
// abc--1--true
// Jack--2--true
// Lucy--3--true
// Lily--4--true
// May--5--true
**功能2:**与every相反,只要有一个回调函数的返回值都为true,some的返回值为true,所有回调函数的返回值为false,some的返回值才为false
//demo1:
var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
var a = arr.some(function(value,index,self){
return value.length > 3;
})
console.log(a); //true
//demo2:
var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
var a = arr.some(function(value,index,self){
return value.length > 4;
})
console.log(a); //false
19.reduce()
**功能:**从数组的第一项开始,逐个遍历到最后,迭代数组的所有项,然后构建一个最终返回的值。
**参数:**reduce()接收一个或两个参数:第一个是回调函数,表示在数组的每一项上调用的函数;第二个参数(可选的)作为归并的初始值,被回调函数第一次执行时的第一个参数接收。
reduce(callback,initial);callback默认有四个参数,分别为prev,now,index,self。
callback返回的任何值都会作为下一次执行的第一个参数。
如果initial参数被省略,那么第一次迭代发生在数组的第二项上,因此callback的第一个参数是数组的第一项,第二个参数就是数组的第二项。
//demo1:不省略initial参数,回调函数没有返回值
var arr = [10,20,30,40,50];
arr.reduce(function(prev,now,index,self){
console.log(prev + "--" + now + "--" + index + "--" + (arr == self))
}, 2019)
// 打印结果为:
// 2019--10--0--true
// undefined--20--1--true
// undefined--30--2--true
// undefined--40--3--true
// undefined--50--4--true
// 此时回调函数没有return,所以从第二次开始,prev拿到的是undefined
//demo2:省略initial参数,回调函数没有返回值
var arr = [10,20,30,40,50];
arr.reduce(function(prev,now,index,self){
console.log(prev + "--" + now + "--" + index + "--" + (arr == self))
})
// 打印结果为:第一次,回调函数的第一个参数是数组的第一项。第二个参数就是数组的第二项
// 10--20--1--true
// undefined--30--2--true
// undefined--40--3--true
// undefined--50--4--true
// 此时回调函数没有return,所以从第二次开始,prev拿到的是undefined
//demo3:不省略initial参数,回调函数有返回值
var arr = [10,20,30,40,50];
arr.reduce(function(prev,now,index,self){
console.log(prev + "--" + now + "--" + index + "--" + (arr == self));
return "hello";
}, 2019)
// 打印结果为:
// 2019--10--0--true
// hello--20--1--true
// hello--30--2--true
// hello--40--3--true
// hello--50--4--true
// 此时回调函数有return,所以从第二次开始,prev拿到的是回调函数return的值
//demo4:省略initial参数,回调函数有返回值
var arr = [10,20,30,40,50];
arr.reduce(function(prev,now,index,self){
console.log(prev + "--" + now + "--" + index + "--" + (arr == self));
return "hello";
})
// 打印结果为:第一次,回调函数的第一个参数是数组的第一项。第二个参数就是数组的第二项
// 10--20--1--true
// hello--30--2--true
// hello--40--3--true
// hello--50--4--true
// 此时回调函数有return,所以从第二次开始,prev拿到的是回调函数return的值
//demo5:使用reduce计算数组中所有数据的和
var arr = [10,20,30,40,50];
var sum = arr.reduce(function(prev,now,index,self){
return prev + now;
})
console.log(sum); //150
// 回调函数的最后一次return的结果被返回到reduce方法的身上
//demo6:使用reduce计算数组中所有数据的和
var arr = [10,20,30,40,50];
var sum = arr.reduce(function(prev,now,index,self){
return prev + now;
}, 8)
console.log(sum); //158
// 回调函数的最后一次return的结果被返回到reduce方法的身上
// 因为reduce有第二个参数initial,在第一次执行时被计算,所以最终结果被加上8
20.reduceRight()
功能:(与reduce类似)从数组的最后一项开始,向前逐个遍历到第一位,迭代数组的所有项,然后构建一个最终返回的值。
**参数:**同reduce。
**demo:**同reduce
四、字符串方法概括
方法 | 功能 | 参数 | 返回值 | 是否改变原字符 |
---|---|---|---|---|
indexOf() | 根据指定子串,从左向右查询字符,查询索引 | 1:要查询的子串; 2:从哪个索引开始查询(可选) | 索引或-1(没查到) | N |
slice() | 截取 | 1:开始的位置; 2:结束的位置(不包括在内,可选) | 截取到的子串 | N |
substr() | 截取 | 1:开始的位置; 2:个数(可选) | 截取到的子串 | N |
substring() | 截取 | 1:开始的位置; 2:结束的位置(不包括,可选) | 截取到的子串 | N |
split() | 分割字符成数组 | 按照什么字符分割 | 分割后的数组 | N |
charAt() | 根据索引取字符 | 索引 | 取到的字符;没取到就是空字符 | N |
concat() | 合并字符 | 要合并的字符 | 合并后的字符 | N |
toUpperCase() | 转大写 | 无 | 转换后的字符 | N |
toLowerCase() | 转小写 | 无 | 转换后的字符 | N |
replace() | 替换 | 1:老字符; 2:新字符; | 替换后的字符 | N |
lastIndexOf() | 从右向左查询字符,查询索引 | 要查找的子串 | 索引或-1 | N |
padstart() | 用于头部补全 | 1:要添加的个数 2:要添加的字符 | 如果原字符串的长度,等于或大于指定的最小长度,则返回原字符串。如果用来补全的字符串与原字符串,两者的长度之和超过了指定的最小长度,则会截去超出位数的补全字符串。如果省略第二个参数,默认使用空格补全长度。 | N |
codePointAt() | 字符转u编码 | 要转的字符 | ||
fromCodePoint() | u编码转字符 | 要转的u编码 | ||
repeat() | 重复当前字符 | 重复的次数 | 返回新字符 | Y |
includes() | 查询子串是否存在 | 要查询的子串 | 返回布尔值 | N |
startsWith() | 查询是否以指定子串开头 | 要查询的子串 | 返回布尔值 | N |
endsWith() | 查询是否以指定子串结尾 | 要查询的子串 | 返回布尔值 | N |
五、严格模式
1.如何开启严格模式
严格模式
- 优势:...
- 如何开启严格模式:
- "use strict"
- 作用域的第一行,当前作用域就是严格模式
- 利用匿名函数生成一个独立的作用域,在这个作用域中开启严格模式,书写严格代码
2.严格模式下的变更
1. 变量必须先声明再使用
2. 不允许参数名重复
3. arguments保存的实参,不被形参的改变影响
4. arguments.callee不允许被使用
5. 没有明确隶属对象的函数中的this,指向undefined
6. with被禁止使用
7. 严格模式不允许使用八进制
3.严格模式的优点
消除不安全,不严谨,不合理之处,放代码更安全,更合理,更严谨,标志了js更好的发展方向,提升代码的执行速度
六、Es6新增
1.Set
var s1 = new Set([4,5,4,3,3,3,3,3]);
s1.add("hello"); //add是Set中的方法,用来想Set中添加数据
console.log(s1); // {4,5,3,hello} 不接收重复数据
console.log(typeof s1); // object
// // console.log(s1[0]) //undefined 不存在索引
// // console.log(s1.length) //undefined
for(var i of s1){
console.log(i) //使用 for...of 遍历拿到Set中的数据(值)
}
//数组去重
var arr = [3,4,5,6,5,4,3,2];
// var s1 = new Set(arr);
// var a=[];
// for(var i of s1){
// a.push(i)
// }
|| 数组快速去重
var a = [...new Set(arr)];
console.log(a)
2.Map
var m = new Map();
m.set("abc","admin"); //Map的方法,用来向map中添加数据
m.set("abc","root"); //修改map中的数据
m.set("age",18);
m.set("sex",1);
console.log(m);
console.log(typeof m); //obj
console.log(m.get("abc")) //获取map中相对应的值
for(var i of m){
console.log(i) //遍历map,取出对应的键和值
}
console.log(m.keys()); //取出键
for(var i of m.keys()){
console.log(i) //遍历获取相对应的键 map中的方法
}
console.log(m.values()); //获取值 map中的方法
for(var i of m.values()){
console.log(i) //遍历,获取值
}
console.log(m.entries()); //其本身 map中的方法
for(var i of m.entries()){
console.log(i)
}
3.箭头函数
基础语法:
var sayHello = (name)=>"hello"+name;
sayHello("张三");
语法:()=>{}
- 概念:类似于无名函数,不能直接存在,只能作为值使用
- 特征:
1. 有且仅有一个参数时,可以省略小括号
2. 有且仅有返回值时,可以省略花括号和return
- 如果要返回对象,要给对象加一层小括号
3. 箭头函数自动绑定上层函数的this
4. 箭头函数不能被new执行
5. 简洁方便,但语义化不好,伤害代码可读性
- 使用场景:
1. 不建议大范围使用
2. 小范围使用,如:回调函数,返回值
- arr.sort((a,b)=>a-b);
- function fn(a){a()};
- fn(()=>{})
特点:
1) 类似于无名函数,只能作为值使用
2) 没有自己的this
3) 有且只有一个参数时,可以省略小括号()
4) 有且直接返回数据时可以省略花括号{}和return
// var fn5 = a=>"hello "+a;
5) 当,有且直接返回对象时,并省略花括号和return时,需要将对象使用小括号括起来
// var fn = ()=>({name:"Admin"});
4.展开运算符(…)
var arr = ["a","b","c",123];
console.log(arr);
console.log(arr[0], arr[1], arr[2], arr[3]);
console.log(...arr);
var arr2 = ["hello","world", ...arr];
console.log(arr2)
// 只有在能接受多个数据的位置才能使用展开运算符展开数组
var obj = {
name:"admin",
age:18
}
var obj2 = {
sex:1,
link:"ball",
...obj
}
var obj2 = {...obj};
obj2.age ++ ;
console.log(obj)
console.log(obj2)
// 只有在能接受键值对的位置才能使用展开运算符展开对象
5.解构赋值
// 数组,对象,字符
// 数组:从左向右顺序解构,超出的变量为undefined
var arr = [2,3,4,5,6];
var a = arr[0];
var b = arr[1];
var c = arr[2];
var d = arr[3];
var e = arr[4];
var [w,e,r,a,s,d,f,g] = arr;
console.log(w);
console.log(e);
console.log(r);
console.log(g);
// 对象:按照key一一对应,不存在的key为undefined
var obj = {
name:"admin",
age:18,sex:1
}
var name = obj.name
var age = obj.age
var sex = obj.sex
var {name,sex,age,like} = obj;
console.log(name);
console.log(age);
console.log(sex);
console.log(like);
// 字符:从左向右顺序解构,超出的变量为undefined
var str = "hello world";
var [a,b,c,d,e,f,g,h,i,j,k,l,m,n] = str;
console.log(a,b,c,d,e,f,g);
console.log(n);
// 参数的解构
function fn([a,b,c,d,e]){
}
var arr = ["hello", 3,4,5, "world"]
fn(arr);
// 快速交换两个变量的值
var a = 10;
var b = 20;
var [a,b] = [b,a];
console.log(a);
console.log(b);
function fn(){
return [4,5,6,7]
}
var [a,b,c] = fn();
6.声明关键字(let,const)
console.log(a);
var a = 10;
console.log(a);
// 1.没有提升
console.log(a);
let a = 20;
console.log(a);
var a = 10;
var a = 20;
console.log(a);
// 2.不允许重名
let a = 10;
let a = 20;
console.log(a)
if(true){
var a = 10;
}
console.log(a);
// 3.块级作用域:花括号就是一个作用域
if(true){
let a = 10;
console.log(a);
}
var a = 10;
console.log(a);
console.log(window.a);
// 4.不会绑定到window对象
let a = 10;
console.log(a);
console.log(window.a);
console.log(a); //undefined
if(true){
console.log(a); //undefined
var a = 10;
}
// 5.暂时性死区
console.log(a);
if(true){
console.log(a);
let a = 10;
}
let a = 10;
a = 20;
console.log(a);
const a = 10;
a = 20;
console.log(a);
const obj = {};
obj.name = "admin";
console.log(obj)
obj.name = "root";
console.log(obj)
obj = {};
//总结:
- let,const与var的区别
- 没有提升
- 不允许重复声明
- 块级作用域
- 全局变量不会绑定到window
- 暂时性死区
- let和const的区别
- let声明的是变量
- const声明的是常量
- 本质上,const要求不允许修改的是地址,没有规定值的修改
- 基本数据和复杂数据的区别
7.Symbol
- 数据类型的一种,类似于字符
- 用来做标记,恒定的量
- 用来约束行为的数据,只能和自己相等,不和任何数据相等
- 字典量
var s1 = Symbol("a");
var s2 = Symbol("a");
console.log(s1);
console.log(s1 == s2);
// s1();
console.log(typeof s1);
// 标记的量:不允许修改,不允许出错,不允许有误
var size = {
s:"s",
m:"m",
l:"l"
}
var size = {
s:Symbol("s"),
m:Symbol("s"),
l:Symbol("s")
}
switch(size.l){
case size.s:console.log("小");break;
case size.m:console.log("中");break;
case size.l:console.log("大");break;
}
8.反引号-字符串拼接(cssText批量设置样式)
- 好处:
- 字符支持换行
- 使用${}拼接变量
//eg:
this.bFire.style.cssText=`width: 10px;
height:10px;
position: absolute;
bottom: 0;
background-color:${this.randomColor};
left:${this.x}px;
`;
CSSText会覆盖初始设置的所有样式
七、Math数学对象
1.Math属性
Math.PI //圆周率
console.log(Math.PI )
2.Math方法
console.log(Math.abs(-5)); // 5 取绝对值
console.log(Math.round(3.0001)); // 3 取最近的整数(四舍五入)
console.log(Math.ceil(3.0001)) // 4 向上取整
console.log(Math.floor(3.999999)) // 3 向下取整
console.log(Math.max(34,67,25,28,19)); // 67 最大值 参数是多个数字
console.log(Math.max([34,67,25,28,19])); // NaN
console.log(Math.min(34,67,25,28,19)); // 19 最小值
console.log(Math.pow(3,4)); // 81 求幂
console.log(Math.sqrt(9)); // 3 开根号
console.log(Math.random()); // 随机数:(0,1)
Math.sin(弧度) //正弦 (角度转换弧度:deg*PI/180)
Math.cos(弧度)
var arr=[2,3,45,67,89,98];
console.log(Math.max.apply(null,arr)); //获取数组最大值
console.log(Math.min.apply(null,arr)); //获取数组最小值
随机颜色
"#"+Math.floor(Math.random()*0x1000000).toString(16).padStart(6,'0');
八、Date方法
1.创建日期对象
var d = new Date(); //用来获取当前系统日期
2.单独获取日期对象中某个部分的方法
console.log(d.getYear());
console.log(d.getFullYear());
console.log(d.getMonth());
console.log(d.getDate());
console.log(d.getDay());
console.log(d.getHours());
console.log(d.getMinutes());
console.log(d.getSeconds());
console.log(d.getMillseconds());
3.获取时间戳
var d=new Date();
console.log(d.getTime()); // 获取到的是1970年0:00:00到当前的毫秒数
4.设置日期对象
1)直接设置(发生在创建日期对象时(new Date()),直接传参,星期无法设置,自动计算
var d=new Date("2020/12/23"); //一个参数,直接设置,不允许日期溢出,否则会产生无效日期,未设置的部分为0
var d=new Date(2004,3,4); //多个参数,直接设置,月份从0开始,日期溢出,向前进1,未设置的部分为0
2)单独设置
var d=new Date();
d.setFullYear(2009);
d.setMonth(4);
d.setDate(4);
d.setHours(3);
d.setMinutes(12);
d.setSeconds(45);
d.setMilliSeconds(666);
5.利用时间戳直接设置日期
var d=new Date();
d.setTime()
九、move的封装
function move(ele, data, cb) {
// 清除计时器
clearInterval(ele.t);
// console.log(111);
// 开启计时器
ele.t = setInterval(function () {
// console.log(222);
// 设置计时器开启状态
var onoff = true;
for (var attr in data) {
// 设置当前样式
var iNow = attr === 'opacity' ? getStyle(ele, attr) * 100 : parseInt(getStyle(ele, attr));
// 设置步长
var speed = (data[attr] - iNow) / 10;
speed=speed > 0 ? Math.ceil(speed) : Math.floor(speed);
// console.log(speed);
// 判断是否有元素未到达终点
if (data[attr] !== iNow) onoff = false;
// 设置属性
ele.style[attr] = attr === 'opacity' ? (iNow + speed) / 100 : iNow + speed + 'px';
}
// 所有元素都到达终点,清除计时器
if (onoff) {
clearInterval(ele.t);
// console.log(3333);
cb && cb();
}
}, 30);
}
function getStyle(ele, attr) {
if (ele.currentStyle) {
return ele.currentStyle[attr];
} else {
return getComputedStyle(ele, false)[attr];
}
}
//使用
var obox = document.querySelector('.box');
console.log(getStyle(obox,'width'));
var obox1 = document.querySelector('.box1');
obox.onclick = function () {
move(obox, { width: 300, height: 300 });
}
十、JSON
——是一种文本数据,用于服务器端和客户端数据交互时,存储数据
——json语法
- 符合js中的对象或数组的格式
- json中的key部分,必须使用双引号,json中不支持单引号
- 数据中不允许出现没有意义的逗号
- json中不允许出现函数,undefined,NaN
- json数据,自身的类型,是字符!!!
- (json文件中的内容自身就是字符,如果是json文件可以忽略此条)
——js对象和json的转化
——json字符转对象
—JSON.parse(str);
——对象转json字符
—JSON.stringify(obj);
——php中json和数组的转化
——把数组转成json
—json_encode();
——把json转成数组
—json_decode();
十一、面向对象(OO)
// 1.基本介绍:面向对象的分析(OOA) 面向对象的设计(OOD):高内聚,低耦合 面向对象的编程(OOP)
1.面向对象的编程
// 1.语法
function Fn(n){
this.abc = n;
}
var f = new Fn("admin");
console.log(f);
//- 面向对象的语法:
//- 构造函数方式创建对象:
// - 属性写在构造函数内的this身上
//- 方法写在构造函数的原型(prototype)上
//- 原型身上的方法在被实例执行时,其内部的this依然指向实例
2.原型
//- 构造函数的prototype(显示原型)
- 是当前构造函数身上的一个属性,自身是对象类型
- 专门作为将来的实例的__proto__的指向
- 所有添加给prototype的属性和方法,都能被将来的实例使用
- 实例的__proto__(隐示原型)
- 所有对象都具有的默认属性,自身是对象类型
- 指向了:构造自身的构造函数的原型prototype
- 当实例身上没有某个方法或属性时,默认查找__proto__的方法或属性
- 实例读取属性的规则:原型链
- 先在自身查找,找到就使用,没找到就顺着__proto__依次向上查找,找到就使用并停止,到顶层还没找到,抛出undefined
- 就近原则
function Fn(n){
this.name = n;
}
Fn.prototype.show = function(){
console.log(this.name)
}
var f1 = new Fn("admin");
f1.show();
var f2 = new Fn("admin");
f2.show();
console.log(f1.show == f2.show); // true
3.new 的原理
1. 创建了一个新对象
2. 修改了函数中的this指向,指向第一步创建的新对象
3. 并将新对象中的__proto__指向了当前函数的prototype
4. 检测原函数中是否主动返回对象,如果没有,那么返回第1~3步创建的这个对象
4.面向对象的编程的特点
//1. 封装
- 比函数更大的封装,函数的封装实现的是功能,对象的封装,在多个功能的基础上继续封装成实例
- 忽略细节
- 选择使用
- 重复使用
//2. 继承
- 构造函数的protoytpe,相对于,实例的__proto__
- 所有的实例的__proto__,继承了,构造函数的protoytpe
- 实例可以使用构造函数的protoytpe身上的方法
- 节省空间,减少冗余代码
//3. 多态
- 多种形态
- 来源
- 使用
- 更方便的扩展
--------------------
//4. 抽象
- 将现有的,具体的事物,的特征,表述出来,形成规范或模版
十二、static
——static 表示声明的是静态资源 ,普通的方法就是属于实例化之后的对象
静态方法
—— 永远只属于类的,实例化之后的对象没法调用,直接使用类名进行调用
十三、中括号语法[ ]
——变量直接使用 对象.调用,就会被当成属性 (console.log(obj.str))
——当对象的属性是变量,就用[],这样才能解析
十四、事件操作
1.事件的组成
a.事件源:绑定事件的元素
—— 必然可以通过this拿到
b.事件类型
c.事件处理函数
2.事件对象
定义:是一个JavaScript自定义的对象,这个对象中存储与事件相关的数据信息
语法:标签对象.事件类型=function (e){
e=e||window.event
}
3.事件目标
——触发事件的元素
——必然可以通过事件对象拿到
——var target = e.target || e.srcElement
4.鼠标点击的坐标
1)事件源边框线内,左上角为坐标原点
offsetX / offsetY
2)坐标原点是可视窗口的左上角
clientX / clientY
3)坐标原点是HTML文档的左上角
pageX / pageY
注:client和page的区别
页面滚动时,两个数值有区别;页面没有移动,两个数值相同
注:获取元素尺寸类信息
// 尺寸类:只能获取不能设置
console.log(obox.clientWidth); // width + padding
console.log(obox.clientHeight);
console.log(obox.offsetWidth); // width + padding + border
console.log(obox.offsetHeight);
console.log(obox.scrollWidth); // width + padding + 可滚动的距离
console.log(obox.scrollHeight);
// 位置
console.log(obox.offsetLeft); // margin + position
console.log(obox.offsetTop);
// 滚动位置
document.onclick = function () {
// 即可获取,又可设置
// console.log(obox.scrollTop);
// console.log(obox.scrollLeft);
obox.scrollTop = 233;
}
//获取文档总高度推荐使用:document.documentElement.scrollHeight
//获取视口高度推荐使用:document.documentElement.clientHeight或者window.innerHeight
5.鼠标点击的内容
鼠标点击对象的信息,存储在target属性中
——innerText: 点击标签文本内容
——tagName: 点击标签的标签名称(标签名称是大写字符)
——id: id属性值
——className: class属性值
6.事件传播
点击子级标签会触发父级标签上相同类型的事件
2)获取机制
——事件冒泡:一个元素的事件被触发后,会依次向上触发**所有** **父**元素的**相同**事件
- 微软提出:页面上的元素关系,既然是包含关系,那么在触发某个元素的事件时,应该像:飞镖扎中靶子 时,如果扎中的是十环,那么九环也相当于被扎中了,依次向上,八环,七环....整个靶子,都被扎 中了
——根据需要,阻止事件冒泡
function stopBubble(e){
if(e.stopPropagation){
e.stopPropagation();
}else{
e.cancelBubble = true;
}
}
——事件捕获:从父级开始获取事件类型,直到子级元素
——一般不会被主动触发,也不会被默认绑定,而且,IE浏览器没有捕获状态,IE只有冒泡
——所以如果想实现事件捕获,需要配合事件监听式绑定方法(addEventListener)
3)执行机制
——执行时都是从子级开始执行程序
:捕获——> 目标 ——> 冒泡
7.阻止事件传播
function stopBuble(e){
if(e.stopPropagation){
// 普通浏览器
}else{
// 低版本IE浏览器
e.cancelBUble=true;
}
}
8.事件委托
将多个子元素的相同事件利用事件冒泡委托给共同的页面现存的父元素,通过事件目标找到真正触发事件的子元素,完成事件处理。的过程,叫事件委托
事件委托的好处:
1. 节省内存
2. 给页面上暂时不存在的元素绑定事件(给动态的html绑定事件)
9.事件监听/注册
一个标签,相同的事件类型,默认只能绑定最后一个事件处理函数
——如果要给一个标签,相同的事件类型,添加多个事件处理函数,必须使用事件的监听语法
function myAddEvent(ele,type,fun){
//判断addEventListener这个方法是否存在
if(ele.addEventListener){
ele.addEventListener(type,fun); //普通浏览器
}else{
ele.attachEvent('on'+type,fun);
}
}
10.事件的移除
1)语法: 标签对象.removeEventListener('事件类型',事件处理函数)
2)只能移除绑定的是一个传参的函数名称
//绑定事件,绑定的事件函数是fun
odiv.addEventListener('click',fun);
//清除事件,清除的事件处理函数是fun
odiv.removeEventListener('click',fun)
——兼容性封装
function delFun(ele,type,fun){
if(ele.removeEventListener){
ele.removeEventListener(type,fun); //普通浏览器
}else{
ele.detachEvent('on'+type,fun);
}
}
11.阻止默认事件执行
1)普通浏览器: e.preventDefault();
2)低版本IE浏览器: e.returnValue=false;
3) return false; //并不能阻止所有的执行
4)兼容性封装:
function stopDefault(){
if(e.preventDefault){
e.preventDefault(); //普通浏览器
}else{
e.returnValue=false; //低版本IE浏览器
}
}
十五、节点的操作
1.概念
——文档中的所有内容,都是节点、标签、文本、注释、属性等
——通过DOM操作和通过节点操作,获取到的对象实际上是相同的对象
2.获取
——选择器
1)元素节点选择器(只有元素节点)
-
直接选择器
- id选择器:document.getElementById(“id名”)
- class选择器:document.getElementsByClassName(“class名”)
- tag选择器:document.getElementsByTagName(“tag名”)
- name选择器:document.getElementsByName(“name名”)
- HTML文件根节点获取:document.documentElement
- ES5新增选择器:
- querySelector选择器:document.querySelector(“css选择器”)
- querySelectorAll选择器:document.querySelectorAll(“css选择器”)
- 总结:
- 返回单个元素:
- id,querySelector
- 返回数组:
- class,tag,name,querySelectorAll
- 返回单个元素:
2)关系选择器:先有基准元素
-
父子关系(母女关系)
-
父选子:先拿到父
// 父选子:先拿到父 var olist = document.querySelector(".list"); // var olist = document.getElementsByClassName("list")[0]; console.log(olist); // 第一个子: console.log(olist.firstElementChild); // 最后一个子: console.log(olist.lastElementChild); // 所有子: console.log(olist.children); // 其他的子: // console.log(olist.children[索引]);
-
子选父:先拿到子
// var oEm = document.querySelector("em"); var oEm = document.getElementsByTagName("em")[0]; // 子选父:一个!直接的父级! console.log(oEm.parentNode); console.log(oEm.parentNode.parentNode);
-
-
兄弟关系(姐妹关系)
// 先选择当前 var olist = document.querySelector(".list");
- 哥:谁的哥(上一个兄弟)
// 上一个(哥): console.log(olist.previousElementSibling);
- 弟:谁的弟(下一个兄弟)
// 下一个(弟): console.log(olist.nextElementSibling);
3 )节点选择器(元素,属性,注释,文本)
- 元素,注释,文本,参与了父子或兄弟关系
- 利用关系选择
- 父元素节点.childNodes
- 当前元素.previousSibling
- 当前元素.nextSibling
- 节点的过滤属性:见1.3
- 属性,没有参与这种家族关系,更像是元素身上的衣服
- 单独选择器
- 当前元素.attributes
- 节点的过滤属性:见1.3
- 节点选择器和节点的过滤属性,一般只用来做选择或过滤,不用来做修改等操作,有单独的操作方法
3.节点的过滤属性
nodeType | nodeName | nodeValue | |
---|---|---|---|
元素 | 1 | 大写标签名 | null |
文本 | 3 | #text | 文本内容 |
注释 | 8 | #comment | 注释内容 |
属性 | 2 | 属性名 | 属性值 |
根document | 9 | #document | null |
十六、标签属性操作
1.setAttribute()
作用:设置标签属性的属性值
注: 设置的属性,只能通过getAttribute()方法来获取
语法:
标签对象.setAttribute('参数1','参数2')
参数:
参数1:添加的属性
参数2:属性值
2.getAttribute()
作用:获取标签的属性及属性值
语法:
标签对象.getAttribute('参数')
参数: 需要获取的属性
3.removeAttribute()
作用:删除标签属性
语法:
标签对象.removeAttribute('参数')
参数:需要删除的属性
4.总结
在标签对象中原生存在的属性,可以使用点语法或者[]中括号语法,直接操作标签对象获取,也可以使用点语法和[]中括号语法之直接进行设置
自定义属性最好用setAttribute()设置,通过getAttribute()来获取
十七、浏览器常见事件
1.浏览器弹窗事件
1)window.alert( ) //提示框
-
window.prompt( ) //输入框
-
window.confirm( ) //确认框
2.浏览器事件
1)window.onload
2)window.onscroll
3) window.onresize
4) window.location
5)window.navigator
6) window.history
7) window.open
8)window.close
- 浏览器事件:window
- 加载完成:load
- 改变大小:resize
- 滚动滚动条:scroll
3.鼠标事件
- 左键单击:click
- 左键双击:dblclick
- 右键单击:contextmenu
- 鼠标按下:mousedown
- 鼠标移动:mousemove
- 鼠标抬起:mouseup
- 鼠标进入:mouseover/mouseenter
- 鼠标离开:mouseout/mouseleave
// onmouseenter/onmouseleave 不支持冒泡
4.键盘事件
- 键盘按下:keydown
- 键盘抬起:keyup
- 键盘按下并抬起:keypress
5.表单事件
- 内容改变:change
- 获取焦点:focus
- 失去焦点:blur
- 输入内容:input
- 提交:submit
- 重置:reset
6.触摸事件
7.特殊事件
十八、this指向
1.默认绑定
当一个没有明确隶属对象的函数,被直接调用时。该函数内部的this
指向window。
function fn(){
console.log(this.a);
}
var a = 10;
fn(); //10
// 这里的this指全局对象window
当然要注意,在ES5的严格模式下,没有明确隶属对象的函数在默认执行时,其内部的this
指向undefined
.
2 隐式绑定
所谓隐式绑定,就是将没有明确隶属对象的函数,归属到某个对象,通过该对象执行函数。
此时函数内部的this指向该对象。
function fn(){
console.log(this.a);
}
var obj = {
a:10,
fn:fn
}
obj.fn(); // 10
// 这里的this指obj
隐式绑定会遇到隐式丢失的情况:
- 当对象的方法被变量引用时,如果该变量没有从属对象,通过该变量执行函数,那么this会丢失,捕获到window。
- 当对象的方法,作为回调函数,传入另一个函数内执行时,this会丢失,捕获到window。
function fn(){
console.log(this.a);
}
var a = 20;
var obj = {
a:10,
fn:fn
}
obj.fn(); // 10
// 隐式丢失:虽然 f 是 obj.fn 的引用,但是 f 的执行,并没有归属对象
var f = obj.fn;
f(); // 20
setTimeout(obj.fn, 100); // 20
隐式丢失,不好,也好,关键看如何应用。
但,隐式丢失是可以被修复的,这就要使用下一种绑定方式:显示绑定
3 显示绑定
所谓显示绑定,就是使用函数的方法,如:call
,apply
,bind
等,可以强制改变this的指向。
此处以call
方法举例:
function fn(){
console.log(this.a);
}
var a = 20;
var obj = {
a:10
};
fn.call(obj); // 10
// 这里的this指obj
可以利用显示绑定的方式,修复隐式丢失问题:
function fn(){
console.log(this.a);
}
var a = 20;
var obj = {
a:10
};
// 隐式丢失被解决
fn.call(obj); // 10
setTimeout(fn.bind(obj),100); // 10
注意:通过修复隐式绑定,我们发现,显示绑定 的优先级要高于 隐式绑定。
4 构造函数绑定
构造函数绑定,又叫new
绑定,主要用于面向对象编程。
这里还需要掌握new
关键字的原理:
- 创建一个新对象
- 将函数中的
this
指向这个新对象 - 将这个新对象的
__proto__
指向函数的prototype
- 检查函数中是否主动返回对象,如果没有,则返回前三步处理好的对象
function fn(){
this.a = 10;
}
var f = new fn();
console.log(f.a); // 10
// 这里的this指创建出来的对象f
其实,只需要记住,凡是被new
执行的函数,默认情况下,其内部的this
都被new
强行指向new
出来的对象,也叫实例。
5.箭头函数
无法绑定this,找上层函数的this
6.总结
1.默认绑定 -----------------------------------> 严格模式绑定到undefined,否则为全局对象window
2.隐式绑定(在上下文中调用) --------------> 绑定到当前函数的执行上下文对象
3.显示绑定(由call或apply或bind调用) ----> 绑定到指定的对象
4.构造函数绑定(由new调用) ---------------> 绑定到新创建的对象
———谁执行了this,this就指向谁
十九、call,apply, bind的用法
1.call
// 功能:改变当前执行时的this指向
// 参数:参数1:要改变的this的指向,参数...:作为正常的实参传入到当前执行的函数中
// 返回值:原函数的返回值
// 是否改变原数据:否
function fn(){
console.log(this);
console.log(arguments);
return "hahahahha";
}
// fn(); // window
// fn.call("hello") // hello
var res = fn.call("hello",10,20,30,40);
console.log(res);
2.apply
// 功能:改变当前执行时的this指向
// 参数:参数1:要改变的this的指向,参数2:数组,数组的内容是所有实参
// 返回值:原函数的返回值
// 是否改变原数据:否
function fn(){
console.log(this);
console.log(arguments);
return "hahahahha";
}
// fn(); // window
// fn.apply("hello") // hello
var res = fn.apply("hello",[10,20,30,40]);
console.log(res);
3.bind
// 功能:改变当前执行时的this指向
// 参数:参数1:要改变的this的指向,参数...:作为正常的实参传入到当前执行的函数中
// 返回值:改变了this指向之后的新函数
// 是否改变原数据:否
function fn(){
console.log(this);
console.log(arguments);
return "hahahahha";
}
var res = fn.bind("hello",10,20,30,40);
res();
console.log(res);
console.log("-------上面是新函数-------")
console.log(res === fn); // f
console.log("-------下面是老函数-------")
console.log(fn)
fn();
二十、正则
1.概念和意义
- 概念:
- 正则表达式,正则对象,正确的规则,描述字符串的规则
- 正则一般都是配合字符串使用
- 可以对字符串进行:验证,替换,查询
- 意义:
- 快速的验证,查询,替换字符
- 除非极端情况,正则既可以节省操作,又可以节省性能
- 证明:6正则的意义.html
2.如何创建正则
-
字面量
var reg1 = /正则的内容/;
-
构造函数
var reg2 = new RegExp();
-
字面量正则中不允许出现变量,构造函数可以,但是使用都是一致的
3.如何使用
- 验证,替换,查询
- 正则的方法
- 验证:reg.test(str) ***
- 默认验证局部字符串(是否包含)
- 只要字符串中,有一部分符合,就符合
- 整体验证,需要标记开头和结尾
- 从第一位开始验证,验证到最后一位
- ^:开始
- $:结束
- 查询:reg.exec(str)
- reg.exec(str)
- 每次查询时,会在上次查询结束的位置继续查询
- 直到查询到最后,返回null
- 继续回到初始位置,开始查询
- 但其实,正则开始验证的位置,是可修改的
- 正则的属性:reg.lastIndex
- 表示查询到字符的某个位置的索引
- 字符的方法
- 替换:str.replace(reg,"newStr") ***
- 替换
- 查询:str.match(reg) ***
- 根据指定规则,查询字符串中符合的子串,放在一个数组中
- 查询:str.search(reg)
- 第一次出现的位置的索引
4.如何写
- "乱码"该怎么写,有什么含义
- 修饰符
- g:全局匹配
- i:忽略大小写
- 量词
- +:一个或以上
- *:零个或以上
- ?:零个或一个
- {n}:固定n次
- {n,}:至少n次,以上
- {n,m}:至少n次,最多m次
- 或:|
- 子集:()
- 范围符:-
- 中元符:[],用来标记范围,内部所有组成都是或的关系
- 转义符:
- \d,表示所有的数字,等同于[0-9]
- \w,表示所有的数字字母下划线,等同于[0-9a-zA-Z_]
- \s,表示空格,等同于:
- \D,表示除了数字,等同于[^0-9]
- \W,表示除了数字字母下换线,等同于[^a-z0-9A-Z_]
- \S,表示除了空格,[^\s]
- 非:^,必须在中元符内使用
5.正则的应用
- 表单验证
- 敏感词过滤
- 查询指定字符,返回成数组
二十一、php
1.变量
1)概念:php是一门弱类型语法,变量的类型可以随意改变。
变量其实就是存储数据的容器
2)变量的命名规则
//1. 不需要关键字进行声明,变量在第一次赋值的时候被创建。
//2. 必须以$符号开始
//3. $后面的命名规则与js的变量命名规则一致。
$name = "vae";
echo $name;
2.输出方式
//1. echo 输出简单数据类型
//2. print_r 输出数据结构,一般用于输出复杂类型。
print_r($arr);//print_r是一个函数,不要忘记小括号
//3. var_dump 输出完整的数据结构,包括类型,一般用于精准调试
var_dump($arr);
3.简单数据类型
1)字符串
$str = "峰峰";
echo $str;
2)整数
$num = 100;
echo $num;
3)浮点型
$float = 11.11;
echo $float;
4)布尔类型
$flag = true;
//当布尔类型值为true时,输出1
echo $flag;
$flag = false;
//当布尔类型为false时,输出空字符串
echo $flag;
字符串连接符
//1. 在php中,+号只有算数的功能,并不能拼串
//2. 在php中,拼串使用.
$name = "峰峰";
echo "大家好,我是" . $name . ",今年18岁";
php中的单引号与双引号
//1. 字符串的定义可以使用单引号,也可以使用双引号
$name = "峰峰";
$desc = '很帅';
//2. 双引号可以解析变量
//3. 单引号的性能会高于双引号(了解)
$str = '$name 很帅';//$name 很帅
echo $str;
$str = "$name 很帅";//峰峰 很帅
echo $str;
5)数组
在php中,数组分为两种,索引数组和关联数组
计算数组长度的方法: count(数组名);
索引数组(类似与JS中的数组)
js中只有一个索引数组
$arr=array('hello',123,true,'world');
print_r($arr); //Array ( [0] => hello [1] => 123 [2] => 1 [3] => world )
echo '<br>';
echo $arr[0];
echo '<br>';
echo $arr[1];
echo '<br>';
echo count($arr); //索引从0开始,count方法获取数组长度
// 遍历
for($i=0;$i<count($arr);$i++){
echo $arr[$i];
echo '<br>';
}
关联数组(类似于jS中的对象)
//属性名必须用引号引起来
$arr=array('name'=>'vae','age'=>18);
var_dump($arr);
echo '<br>';
echo $arr['name'];
echo '<br>';
echo count($arr);
echo '<br>';
foreach($arr as $a=>$b){
echo $a;
echo '<br>';
echo $b;
echo '<br>';
}
二维数组
数组中的每个元素又是一个数组
二维数组的存取元素,需要两次访问,依次确定行和列$arr[x][y]
;
//索引数组
$arr=[
[1,2,3],
[4,5,6],
[7,8,9]
];
//取值
echo $arr[2][2];
//存储一个人信息
$info=[
"name"=>"zs",
"age"=>100
];
//存储一个班信息
$infos=[
[
"name"=>"zs",
"age"=>100
],
[
"name"=>"ls",
"age"=>100
],
[
"name"=>"ww",
"age"=>100
]
];
//取值
echo $infos[1]["name"];
6)对象
class Obj{
var $name='vae';
function showName(){
return 'hello '.$this->name;
}
}
$o=new Obj();
var_dump($o);
echo '<br>';
print_r($o);
echo '<br>';
echo $o->showName();
echo '<br>';
echo json_encode($o);
作用域
$a=10;
function fn(){
global $a; //global 声明全局关键字
echo $a;
}
fn();
echo $a;
function fn(){
static $a=10; //加 static 关键字下次执行会在原来的基础上执行
$a++;
echo $a;
echo '<br>';
}
fn(); //11
fn(); //12
4.分支,循环,函数,与js没有区别
$a=8;
if($a<10){
echo "0".$a;
}else{
echo $a;
}
$num=10;
for($i=0;$i<$num;$i++){
echo $i;
echo '<br>';
}
function fn($str){
return $str . ' root';
};
$v=fn('hello');
echo $v;
5.php接收前端数据(表单)
- php接收前端数据
- 表单方式发送get数据:数据在地址栏上拼接
- http://localhost/ws2007/php/login.php?user=admin&pass=123
- 协议:http://
- 域名:localhost
- 路径:/ws2007/php/login.php
- 查询数据:user=admin&pass=123
- 字段名=字段值&字段名=字段值
- 字段名:表单的name值
- 字段值:表单的value值
- 表单方式发送post数据:没有在地址栏上拼接
- 在发送报文的头部信息中
<!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>
<form action="login.php" method="POST">
用户名: <input type="text" name="user" value=""><br>
密码: <input type="text" name="password" value=""><br>
<input type="submit">
</form>
</body>
</html>
<?php
header("content-Type:text/html;charset=utf-8");
// $v=$_GET['user'];
// $e=$_GET['password'];
// $v=$_POST['user'];
// $e=$_POST['password'];
$v=$_REQUEST['user'];
$e=$_REQUEST['password'];
$a='vae';
$b='123456';
echo '这是要接受的php文件的数据:'.$v.'-------'.$a;
if($v===$a && $e===$b){
echo '登录成功';
}else{
echo'登录失败';
}
?>
二十二、mysql
-- insert into 表名 (字段列表) values (值列表)
insert into book(name,author,category,price) values ('天龙八部','金庸','文学',20)
2.修改数据update
如果没有where条件就会修改表中所有数据
-- update 表名 set 字段名称1=值1,字段名称2=值2,... where 条件
update book set name='倚天屠龙记',price=22 where id=4;
3.删除数据delete
-- delete from 表名 where 条件
delete from book where id=4
4.查询数据select
- and表示两边的条件都满足,并且成立
-- select * from 表名 where 条件
select * from book where author='金庸' and price>20*
*获取所有的字段
想获取指定字段 select name,price from book
二十三、php操作数据库
$link=mysqli_connect('localhost','root','root','sh 2007',8080);
// var_dump($link);
if(!$link){
die(mysqli_connect_error());
}
2.数据的增删改查
// 增
$sql="insert student (name,age,sex,job) values('许嵩','34','男','程序员')";
$q=mysqli_query($link,$sql);
if($q){
echo "连接成功";
}else{
echo '连接失败';
}
// 删
$sql="delete from student where id=8";
$q=mysqli_query($link,$sql);
if($q){
echo "success";
}else{
echo 'falied';
}
// 改
$sql="update student set name='vae' where id=7";
$q=mysqli_query($link,$sql);
if($q){
echo "success";
}else{
echo "failed";
}
// 查
if($q){
//从mysql查询到的数据,需要解析之后才能使用
//每次执行只能解析一条数据
while(true){
$res=mysqli_fetch_array($q);
print_r($res);
echo '<br>';
if(!$res){
break;
}
}
//返回索引数组
while(true){
$res=mysqli_fetch_row($q);
// print_r($res);
echo $res[1];
echo '<br>';
if(!$res){
break;
}
}
//返回关联数组 好用
while(true){
$res=mysqli_fetch_assoc($q);
if(!$res){
break;
}
// print_r($res);
// echo $res['name'];
echo json_encode($res);
echo '<br>';
}
//返回对象,好用
while(true){
$res=mysqli_fetch_object($q);
if(!$res){
break;
}
// print_r($res);
echo $res->name;
// echo json_encode($res);
echo '<br>';
}
}else{
echo 'select no ok';
}
3.关闭数据库
mysqli_close($link);
二十四、ajax
一)同步和异步
1.同步
- 不同时执行:一次执行一个程序
- 大部分代码
- alert()
2. 异步
- 同时执行
- 计时器,事件,ajax,promise
// 编程中:异步程序代码执行时不会阻塞其它程序代码执行,从而提升整体执行效率。
二)js 的宏任务和微任务
异步的程序,会触发微任务
- 微任务上所有程序的执行,都需要等待宏任务结束后,才会开始
- 如:哪怕延时器的时间是0毫秒,也不会立即执行
三)程序、进程、线程
1.程序:功能
2.进程:一个功能从开始执行到执行结束
3.线程:执行一个功能的过程中开启的多个分支
//总结:
- js单线程的编程语言
- 但是:js使用异步模拟了多线程的执行方式
1.ajax概念
- 前后端交互的重要手段
- ajax可以实现在不中断浏览器其他任务(无刷新)的情况下,向后台请求数据,并更新页面
- 无刷新加载新数据
- ajax是异步的程序过程
2.ajax特点
无刷新加载新数据
- 提升用户体验
- 提升页面首屏打开速度
- 减轻服务器带宽
- 破坏了浏览器的历史记录(不能使用前进或后退找到历史数据)
- 破坏了搜索引擎对关键字的检索(搜索爬虫爬不到ajax请求的数据)
- 无兼容,只要支持js,就执行ajax。(IE5不支持)
3.ajax组成
- 是一组技术的集合。
- a:异步,j:js,a:和,x:服务端的数据
- 异步的js和服务端的数据
- 组成:
- 前后端交互的载体:xhr(XMLHttpRequest)
- 异步的js:事件
- 其他js:数据的解析,数据的渲染,数据的处理
- 服务端的数据:json,xml,txt,html,文本文件
- 前后端交互,**只能**交互**字符**
4.get请求的创建与发送
// 1.实例化xhr对象
let xhr = new XMLHttpRequest();
// 2.打开资源请求(‘请求方式’,‘请求地址’)
xhr.open('get', 'http://localhost/2003/ajax/data/test.txt');
// 3.监听状态
xhr.onreadystatechange = function () {
// 判断当前状态和服务器状态 状态等于4时表示响应内容解析完成,状态码为200时表示客户端请求成功
if (xhr.readyState === 4 && xhr.status === 200) {
// 接收服务器返回数据
console.log(xhr.responseText);
} else if (xhr.readyState === 4 && xhr.status !== 200) {
console.log("请求失败");
}
}
// 4.发送请求
xhr.send();
补充.get方式的封装
<!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>
<button id="btn">提交</button>
<textarea id="res" disabled></textarea>
</body>
<script>
let obtn=document.getElementById("btn");
let ores=document.getElementById("res");
obtn.onclick=function(){
let url='http://localhost/2003/ajax/data/test.txt';
getAjax(url,function(res){
ores.value+=res;
})
}
// 封装
function getAjax(url,cb,data){
let str='';
data=data||{};
for(let i in data){
str+=`${i}=${data[i]}&`;
}
url+="?"+str+"collette="+Date.now();
console.log(url);
let xhr=new XMLHttpRequest();
xhr.open("get",url);
xhr.onreadystatechange=function(){
if(xhr.readyState===4 && xhr.status===200){
cb(xhr.responseText);
}
}
xhr.send();
}
</script>
</html>
5.post方式的封装
function ajaxPost(url, cb, data) {
data=data||{};
let str='';
for(let i in data){
str+=`${i}=${data[i]}&`;
}
let xhr = new XMLHttpRequest();
xhr.open('post', url);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
cb(xhr.responseText);
}else if(xhr.readyState ===4 && xhr.status===200){
cb("error:"+xhr.status);
}
}
xhr.send(str);
}
6.get 和 post 的区别
- 数据位置:get在url后拼接,post没有
- 安全性:post更安全
- 数据量:get小,post大
- 常用场景:get请求,post发送
// 前后端各自的收发技术或方式有哪些
- 前端:
- 收:浏览器默认接收,ajax
- 发:form发送,ajax
- 后端:
- 收:$_GET["字段名"]/$_POST["字段名"]/$_REQUEST["字段名"]
- 发:echo/print/die()
二十五、jsonp(解决Ajax不能跨域的问题)
1.Ajax 跨域问题
1)问题表现
- 现象:当发起请求源地址的服务器和要请求地址的服务器不一致
- 报错提示:
- `No 'Access-Control-Allow-Origin' header is present on the requested resource.`
- 翻译版:请求的资源上不存在“访问控制允许源”的头部信息
- 白话版:对方没有明确允许请求
2)原因
- 浏览器:为了安全着想,提出同源策略,只要非同源,且对方没有明确允许,都是不允许
- 同源策略:
- 同协议:http、https
- 同域名:baike.baidu.com / map.baidu.com
- 同端口:localhost:80 / localhost:81
- 跨域:不符合同源策略
- ajax不允许跨域
2.解决跨域问题的方式
1) 修改成同源
2) 设置目标允许请求(后台)(CORS)
- header('Access-Control-Allow-Origin:*');//允许所有来源访问
- header('Access-Control-Allow-Method:POST,GET');//允许访问的方式
3)绕过同源策略 - 不用ajax
- jsonp:程序猿在和浏览器的安全策略做斗争的过程中发明的(前端)
4)绕过同源策略 - 不用浏览器
- 服务器代理
3.jsonp解决跨域问题
1)原理:利用浏览器不会阻止html标签的跨域请求,实现跨域请求数据
2)解决方式:
- 利用script标签可以引入外部资源文件
- 只要通过script引入的文本,都会作为js代码执行
- 在前端定义函数,在后端资源中执行函数,时,传参,参数是数据
- 如果后端资源是php文件(必须是php文件),php返回给前端的数据,会被script作为js代码解析
4.jsonp 的封装
<!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>
document.onclick = function(){
var url = "http://127.0.0.1/ws2007/jsonp/data/jsonp5.php";
jsonp(url,function(res){
alert(res)
},{
a:10,
name:"admin",
b:"hello",
// jsonp必传参数:
// 将后台接收的函数名所在的字段名,作为key使用,对应的value是后台要拼接的函数名
callback:"ajgs",
// columnName用来将 后台接收的函数名所在的字段名 传给封装的jsonp函数
columnName:"callback"
});
}
//封装
function jsonp(url,cb,data){
let str = "";
for(var i in data){
str += `${i}=${data[i]}&`;
}
// 创建script
let script = document.createElement("script");
// 设置src为要请求的地址
// 因为jsonp只能是get,所以会产生缓存,要注意拼接时间戳
script.src = url + "?" + str + "__qft=" + Date.now();
// 插入页面
document.body.appendChild(script);
// 定义函数
// 假设data.columnName解析出:abc
// window[data["abc"]]
// 假设data["abc"]解析出:hfhasd
// window["hfhasd"]
window[data[data.columnName]] = function (res){
cb(res);
// 请求成功后,删除没用的script
script.remove();
// 删除使用之后的全局函数
window[data[data.columnName]] = null;
}
}
</script>
</body>
</html>
/**jsonp只能通过get方式发送数据**/
二十六、本地存储
1.本地存储的特点
1)只能存储在本地
2)只能存文本(字符)
3) 大小限制(寄生于浏览器的缓存中)
4) 数量限制(寄生于浏览器的缓存中)
2.cookie
(1) cookie的特点
a. 比较老的本地存储技术
b. 随着http请求,发往服务器
c. 大小限制:10K~
d. 数量限制:50条~
e. 时间限制:没有永久,指定过期时间,不指定时间,会话级(当前会话被关闭)
f. 不允许跨域:服务,域名,端口,路径
(2)cookie的使用
(2)cookie的使用
a. 是DOM的一个属性:document.cookie
- 增:document.cookie赋值
- 删:document.cookie赋值,修改有效期
- 改:document.cookie赋相同的名字,不同的值
- 查:document.cookie
- 查询所有cookie
(3)cookie的格式要求
1) key=val的格式
//- 一条代码只能存储一条cookie
document.cookie = "sex=男; like=ball"; // 错误演示
//- cookie的配置信息
- 只能在设置cookie时指定配置信息,使用分号隔开每组信息
- 路径:path
- 父路径不可以获取子路径中的cookie,反之可以
document.cookie = "b=20;path=/ws2007";
- 有效期:expires
var d = new Date();
d.setDate(d.getDate() + 3);
document.cookie = "c=30;path=/;expires="+d;
(4) cookie的高级使用(封装)
// 设置cookie
function setCookie(key, val, ops) {
ops = ops || {};
let p = ops.path ? ";path=" + ops.path : "";
let exp="";
if (ops.expires) {
let d = new Date();
d.setDate(d.getDate() + ops.expires);
exp = `;expires=` + d;
}
document.cookie = `${key}=${val}` + p + exp;
}
// 获取cookie
function getCookie(key){
let arr=document.cookie.split("; ");
for(let i=0;i<arr.length;i++){
if(arr[i].split("=")[0]===key){
return arr[i].split("=")[1];
}
}
return "";
}
// 删除cookie
function removeCookie(key,ops){
ops=ops||{};
ops.expires=-1;
setCookie(key,"1",ops);
}
3.storage( localstorage / sessionstorage )
(1)特点
- 5M~
- 时间:永久(l)/会话级(s)
- 只是在做存储,不会发往服务器
- 必须是字符
- 有安全限制
(2)使用
// - localstorage,sessionstorage都是window的子对象
// - 将自身作为对象,进行,属性或方法操作,实现storage数据的增删改查
console.log(window.localStorage);
console.log(localStorage);
console.log(localStorage === window.localStorage); //t
// 属性:不推荐使用
localStorage.a = 10;
localStorage.a = 20;
console.log(localStorage.a);
delete localStorage.a;
localStorage.a = "";
// 方法:推荐使用方式
localStorage.setItem("name","admin"); //设置
localStorage.setItem("name","root");
console.log(localStorage.getItem("name")); //获取
localStorage.removeItem("name") //删除
localStorage.clear(); // 清空
// 获取有几个数据
console.log(localStorage.length)
sessionStorage等同于localStorage的操作
// 只有有效期的区别
sessionStorage.setItem("name","admin");
二十七、promise
1.介绍
- Promise:承诺
- 承诺开启时,就可以预置成功和失败的处理
- 正在进行时:承诺正在进行,没有拿到结果
- 将来:得到结果
- 成功:成功的处理
- 失败:失败的处理
-promise自身也是异步程序
-自身有三个状态,pedding,resolve,reject
- resolve和reject只能执行一个,不能并存
2.语法
var p = new Promise(function(resolve,reject){
// 正在进行时.....
console.log("hello...");
setTimeout(()=>{
// 成功...
resolve();
},Math.random()*1000);
setTimeout(()=>{
// 失败...
reject();
},Math.random()*1000);
});
p.then(()=>{
console.log("成功");
}, ()=>{
console.log("失败");
});
3.回调地狱
ajax(url1,()=>{
ajax(url2,()=>{
ajax(url3,()=>{
ajax(url4,()=>{
ajax(url5,()=>{
ajax(url6,()=>{
// 可以拿到所有数据
})
})
})
})
})
})
4.promise 的连缀语法
当then的回调函数中有返回一个新的promise对象,then的返回值就是这个promise对象,可以在then处理之后继续使用then处理内部的promise对象的状态
5.promise 的批量处理
- Promise.all([p1,p2,p3,...])
- 所有结束,才会拿到结果。成功找then或失败catch
- Promise.race([p1,p2,p3,...])
- 拿到最先结束的promise的状态。成功找then或失败catch
二十八、闭包和继承
1.闭包:
1)概念
通过作用域的嵌套,将原本的局部变量,进化成私有变量(自由变量)的环境
2)原理
- 函数在执行时,可以拿到自身的定义作用域内的变量
- 触发了垃圾回收机制
- 将暂时不用的数据,暂存起来,如果需要使用,可以再次调出,除非真正不用了,再进行删除
3)特点
- 占内存
- 可以在外部操作作用于内部的数据
- 内存泄漏(IE低版本浏览器)
- 减少全局变量的声明
4)应用场景
// - 事件委托的封装
function eveEnt(child, cb){
return function(eve){
var e = eve || window.event;
var tar = e.target || e.srcElement;
for(var i=0;i<child.length;i++){
if(tar === child[i]){
cb.call(tar);
}
}
}
}
// - 循环绑定事件,事件中使用循环的计数器
for(var i=0;i<ali.length;i++){
(function(index){
ali[index].onclick = function(){
console.log(index);
}
})(i)
}
for(var i=0;i<ali.length;i++){
ali[i].onclick = (function(index){
return function(){
console.log(index);
}
})(i)
}
//- 内置函数的回调函数传参
setTimeout(fn("hello"),1000);
function fn(a){
return function(){
console.log(a);
}
}
2.继承
1) 改变 this 指向的继承
function Parent(){
this.skill = "敲代码";
this.abc = 123;
this.show = function(){
console.log(this.skill)
}
}
Parent.prototype.init = function(){
console.log("hello")
}
function Tea1(){
this.s1 = "语文";
}
function Tea2(){
this.s2 = "数学";
}
function Tea3(){
this.s3 = "英语";
}
function Child(){
// Parent(); // this指向window
// 改变成将来Child的实例
// 在Child的函数中的this,就是将来Child的实例
// 将Parent的this改成Child的this
Parent.call(this);
Tea1.apply(this);
Tea2.bind(this)();
Tea3.call(this);
}
// var p = new Parent();
// console.log(p);
// console.log(p.skill);
var c = new Child();
console.log(c)
console.log(c.skill)
c.show();
c.init();
// 改变this指向继承:
//- 对象之间的继承
//- 类与类之间
// 特点
// 简单方便易操作,可以实现多继承
// 只能继承构造函数中的内容,不能继承原型上的内容
2) 原型继承
function Parent(){
this.skill = "敲代码";
}
Parent.prototype.init = function(){
console.log("hello");
}
function Child(){
}
// Child.prototype = Parent.prototype;
for(var i in Parent.prototype){
Child.prototype[i] = Parent.prototype[i];
}
// Child.prototype.init = function(){
// console.log("world")
// }
var p = new Parent();
p.init()
console.log(p)
var c = new Child();
c.init();
console.log(c)
// - 可以继承原型上所有内容,但是不能继承构造函数
3) 原型链继承
function Parent(s){
this.skill = s;
}
Parent.prototype.init = function(){
console.log(this.skill);
}
function Child(){
}
Child.prototype = new Parent("hello");
// Child.prototype.init = function(){
// console.log("world")
// }
var p = new Parent("敲代码");
p.init()
console.log(p)
var c1 = new Child();
c1.init();
console.log(c1)
var c2 = new Child();
c2.init();
console.log(c2);
// 原型继承-原型链继承:
// 可以继承原型,可以继承构造函数
// 不利于传参
4) 混合继承
function Parent(s){
this.skill = s;
}
Parent.prototype.init = function(){
console.log(this.skill);
}
function Tea1(){
this.s1 = "语文"
}
Tea1.prototype.show = function(){
console.log(this.s1);
}
function Child(s){
Parent.call(this, s);
Tea1.call(this);
}
for(var i in Parent.prototype){
Child.prototype[i] = Parent.prototype[i];
}
for(var i in Tea1.prototype){
Child.prototype[i] = Tea1.prototype[i];
}
// Child.prototype.init = function(){
// console.log("world")
// }
var p = new Parent("敲代码");
p.init()
console.log(p)
// p.show()
var c1 = new Child("敲键盘");
c1.init();
console.log(c1)
c1.show();
// 混合继承特点:
// 可以继承构造函数,可以继承原型,还可以实现多继承
5) class 继承
class Parent{
/ constructor(s){
this.skill = s;
}
init(){
console.log(this.skill)
}
}
/ class Child extends Parent{
/ constructor(s){
/ super(s);
}
init(){
console.log("hello")
}
}
var p = new Parent("敲代码");
p.init();
console.log(p);
var c = new Child("敲键盘");
c.init();
console.log(c);
// - ES6对混合继承的封装
6) Object.create() Array.from() 方法
var obj = {
name:"admin"
}
var obj2 = Object.create(obj);
// console.log(obj2 === obj); // f
var arr1 = [1,2,3]
var arr2 = Array.from(arr1);
console.log(arr1 === arr2); //f
// 伪数组:有索引,有长度,但是不能使用数组的方法
// arguments
// 选择器选择到的数组
var aspan = document.querySelectorAll("span");
// 伪转真
// 1.逐个遍历,拷贝到新数组
// var arr = [];
// for(var i=0;i<aspan.length;i++){
// arr.push(aspan[i])
// }
// arr.push("hello")
// console.log(arr)
// 2.利用Array的方法from
var arr = Array.from(aspan);
arr.push("world");
console.log(arr);
3.原型的补充
1)函数的prototype
原型对象,对象类型,显示原型;用来给当前所在函数被new出来的实例,做父级使用;函数的prototype内的属性和方法,作为将来所有被new出来的实例的公共属性和方法
2)对象的__proto__
原型对象,对象类型,隐示原型;用来指向构造当前对象的函数的prototype;就可以访问构造当前对象的函数的prototype身上的属性和方法
-
每个原型对象内都有一个属性:constructor。用来指向当前所在的原型属于哪个构造函数
-
每个原型对象内都有一个属性:constructor。用来指向当前所在的原型属于哪个构造函数
3) 每个原型对象内都有一个属性:
——constructor,用来指向当前所在的原型属于哪个构造函数
4)对象的属性的读写原则(默认情况)
- 读:先在自身查找,找不到,顺着__proto__向上级查找,找到就使用,同时停止继续查找,找不到,继续向上级,直到 顶层,找不到,抛出undefined
- 写:直接添加或修改到自身
二十九、设计模式
1.单例模式
(单例模式的核心是确保只有一个类一个实例,并提供全局访问.)
function Fn(){
if(!Fn._lyObj_){
Fn._lyObj_ = {};
}
Fn._lyObj_.name = "admin";
return Fn._lyObj_;
}
var f1 = new Fn();
var f2 = new Fn();
console.log(f1 === f2); // true
console.log(f1.name)
console.log(f1)
console.log(f2)
弹出框的实现
<!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>
function Dialog(){
if(!Dialog._obj_){
Dialog._obj_ = {};
Dialog._obj_.ele = document.createElement("dialog");
document.body.appendChild(Dialog._obj_.ele);
}
Dialog._obj_.ele.innerHTML = "这是一个弹出框";
Dialog._obj_.ele.style.display = "block";
clearTimeout(Dialog._obj_.t);
Dialog._obj_.t = setTimeout(()=>{
Dialog._obj_.ele.style.display = "none";
},2000);
return Dialog._obj_;
}
document.onclick = function(){
new Dialog();
}
</script>
</body>
</html>
// - 应用场景
- 只有一个实例需要被使用时
- 解决大量的个人变量或函数的问题
- 组团开发,命名冲突,或命名管理
单例模式的好处:
1.在全局中只生成一个变量,减少全局变量的污染,同时也很好的解决了命名冲突。
2.只需新创建一次对象,减少对内存资源的占用。
一般:对数据库进行操作的时候用,第一次调用mysql的操作函数,执行连接,把连接对象进行保存.后续再调用时,直接使用保存的连接对象.
2.组合模式
组合模式:
——很多需要执行的命令或者方法,放到一个总命令中,可以一次性执行
1 将对象组合成树形结构以表示"部分-整体"的层次结构。
2.组合模式使得用户对单个对象和组合对象的使用具有一致性。
3.无须关心对象有多少层,调用时只需在根部进行调用;
组合模式主要有三个角色:
(1)抽象组件(Component):抽象类,主要定义了参与组合的对象的公共接口
(2)子对象(Leaf):组成组合对象的最基本对象
(3)组合对象(Composite):由子对象组合起来的复杂对象
<script>
// 组合模式的使用
class MarcoCommand {
constructor() {
this.lists = [];
}
// 添加任务的方法
add(task) {
this.lists.push(task);
}
// 执行任务的方法
execute() {
this.lists.forEach((v, k) => {
var taskObj = new v;
taskObj.init();
})
}
}
// 任务1
class task1 {
init() {
console.log('打开空调.....')
}
}
class task2 {
init() {
console.log('电脑打开......');
}
}
class task3 {
init() {
console.log('召唤女仆....');
}
}
//添加任务
let command = new MarcoCommand();
command.add(task1);
command.add(task2);
command.add(task3);
command.execute();
</script>
组合模式的好处
1 它主要解决的是单一对象和组合对象在使用方式上的一致性问题。
2 如果对象具有明显的层次结构并且想要统一地使用它们,这就非常适合使用组合模式。
3.观察者模式
又称发布-订阅模式。意思是让一个人不停的监控某件东西,当这个东西要发生某种行为的时候,这个人就通知一个函数执行这个行为的操作。
例:当事件的代码写好以后,其实这个事件就不停的监控用户在页面中的行为,一旦用户触发这个事件的时候,就调用函数处理这个事件。
div.addEventListener("click",function(){});
// 这个事件写好以后,就一直在页面中监控用户行为,用户点击这个元素的时候,就调用函数
//目标:给obj绑定abc事件
class Watch {
//事件存储
obj = {};
//绑定事件
bind(type, handle) {
if (this.obj[type]) {//该事件已经绑定
this.obj[type].push(handle);
} else {
this.obj[type] = [handle];
}
}
//触发事件
touch(type, ...arr) {//arr代表触发事件时传递的参数
//...是ES6的展开运算符,用于对变量,数组、字符串、对象等都可以进行解构赋值
//判断是否是该类型事件
if (!this.obj[type]) return false;
//模拟event对象
var e = {
type: type,
args: arr
}
// console.log(this.obj[type]);
this.obj[type].forEach(ele => {
ele(e); //调用事件中的每一个函数
});
}
//解绑事件
unbind(type, handle) {
if (!this.obj[type]) return false;
// 解绑指定函数
this.obj[type].forEach(function (ele, key) {
if (ele == handle) {
this.obj[type].splice(key, 1);
}
});
}
//删除事件对应的所有函数
clear(type) {
//判断是否存在
if (!this.obj[type]) return false;
else {
delete this.obj[type];
}
}
}
//进行事件绑定
let w = new Watch();
w.bind('abc', a);
w.bind('abc', b);
// console.log(w.obj);
w.bind('abc', c);
function a() {
console.log('我是a');
}
function b() {
console.log('我是b');
}
function c(e) {
console.log('我是c,打印:姓名' + e.name + ',年龄' + e.age);
}
w.touch('abc ','zs',18);
async的使用
<!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>
</body>
<script>
// async函数返回一个Promise对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到出发的异步操作完成,再接着执行函数体内后面的语句。
async function fn() {
return 'hello world';
}
var res = fn();
console.log(res); //Promise
var res = fn().then(data => {
// 使用async修饰的,直接返回promise对象
console.log(data); //后执行,结果为hello world
})
console.log(res); //先执行 结果为 Promise
// await的使用
// async中的函数出现await时,当前代码暂停执行,等待promise执行完成,再向下执行
async function fn() {
const data = await 'hello world';
console.log(data, 111); //后执行,执行结果为 hello world 111
return data;
}
console.log(fn(), 666); //先执行,执行结果为Promise 666
function say() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
let age = 34;
resolve(`hello, vae,我知道你今年 ${age}岁`)
}, 1000)
});
}
async function vae() {
const v = await say(); // 输出结果:hello, vae,我知道你今年 26岁 等待这个say 的异步,如果成功把回调 resolve 函数的参数作为结果
console.log(v);
}
vae();
// 1 async 告诉程序这是一个异步,awiat 会暂停执行async中的代码,等待await 表达式后面的结果,跳过async 函数,继续执行后面代码
// 2 async 函数会返回一个Promise 对象,那么当 async 函数返回一个值时,Promise 的 resolve 方法会负责传递这个值;当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值
// 3 await 操作符用于等待一个Promise 对象,并且返回 Promise 对象的处理结果(成功把resolve 函数参数作为await 表达式的值),如果等待的不是 Promise 对象,则用 Promise.resolve(xx) 转化
</script>
</html>
jquery
1.使用jquery的优点
- )获取元素的方式非常的简单,而且非常的丰富
- )jQuery的隐式迭代特性,不再需要书写for循环语句。
- )使用jQuery完全不用考虑兼容性问题。
- )jQuery提供了一系列动画相关的函数,使用非常方便。
2.Jquery的引入
<script src="jquery-2.2.4.js"></script>
3.入口函数
//第一种写法
$(document).ready(function() {
});
//第二种写法
$(function() {
});
4.DOM对象转换成jQuery对象
// 将dom对象放入,$()中,就可以进行转化
var $obj = $(domObj);
// $(document).ready(function(){});就是典型的DOM对象转jQuery对象
5.jQuery对象转换成DOM对象
var $li = $(“li”);
//第一种方法(推荐使用)
$li[0]
//第二种方法
$li.get(0)
6.jquery 选择器
1)css选择器
名称 | 用法 | 描述 |
---|---|---|
类选择器 | $(’.class’) | 获取同一类class的元素 |
标签选择器 | $(“div”); | 获取同一类标签的所有元素 |
ID选择器 | $(’#id’) | 获取指定ID的元素 |
并集选择器 | $(“div,p,li”); | 使用逗号分隔,只要符合条件之一就可。 |
交集选择器 | $(“div.redClass”); | 获取class为redClass的div元素 |
子代选择器 | $(“ul>li”); | 使用>号,获取儿子层级的元素,注意,并不会获取孙子层级的元素 |
后代选择器 | $(‘ul li’) | 使用空格,代表后代选择器,获取ul下的所有li元素,包括孙子等 |
gulp
let gulp=require('gulp');
gulp.task('vae',function(done){
console.log('vae');
done();
});
gulp.task('xs',function(done){
console.log('许嵩');
done();
});
// 默认执行任务,输出内容
gulp.task('default',function(done){
console.log('独揽月下萤火,照亮一纸寂寞');
done();
});
// 复制多个后缀名的图片到指定目录
gulp.task('copyImg',function(){
return gulp.src('./images/*.{jpg,png,gif}').pipe(gulp.dest('./js/images'));
});
// 复制vae.html到指定目录
gulp.task('copyHtml',function(){
return gulp.src('./vae.html').pipe(gulp.dest('./js'));
});
// 压缩js文件 uglify
var uglify=require('gulp-uglify');
gulp.task('uglify',function(){
return gulp.src('./jquery-2.2.4.js').pipe(uglify()).pipe(gulp.dest('./js'));
})
// 合并js文件 concat
var concat=require('gulp-concat');
gulp.task('concat',function(){
return gulp.src('./js/{v.js,a.js,e.js}').pipe(concat('vae.js')).pipe(gulp.dest('./js'));
});
// 多任务处理
// 顺序 series
gulp.task('default',gulp.series(['vae','xs'],function(done){
console.log('全世界最好的XX');
done();
}));
// 并行 parallel
gulp.task('default',gulp.parallel(['vae','xs'],));
// 即时刷新 connect
var connect=require('gulp-connect');
gulp.task('load',function(done){
gulp.src('./html/index.html').pipe(gulp.dest('./js')).pipe(connect.reload());
done();
});
// gulp创建服务器 connect.server
gulp.task('server',function(){
connect.server({
root:'./html',
port:8080,
livereload:true
})
})
gulp.task('vae',function(done){
console.log('vae');
done();
});
// watch监听文件
var watch=require('gulp-watch');
gulp.task('watch',function(done){
watch('./html/*.html',gulp.series('vae'));
done();
})
// 工作中文件即时刷新
// // 指定需要刷新的文件 connect.reload()
gulp.task('html',function(done){
gulp.src('./html/index.html').pipe(connect.reload());
done();
})
// // // 创建服务器
gulp.task('server',function(done){
connect.server({
root:'./html',
port:8080,
livereload:true
})
done();
})
// // // 指定监听 watch
var watch=require('gulp-watch');
gulp.task('watch',function(done){
watch('./html/*.html',gulp.series('html'));
done();
})
// // // 合并所有任务 parallel
gulp.task('default',gulp.parallel('server','html','watch'),function(done){
console.log('success');
done();
});
// // ES6转ES5 babel
const babel=require('gulp-babel');
gulp.task('minijs',function(done){
gulp.src('./js/index.js').pipe(babel({presets:['es2015']})).pipe(gulp.dest('./js/dest'));
done();
})
// gulp4的新任务方式
function vae(done){
console.log('vae有很多烦恼');
done();
}
exports.vae=vae;
// -------------------------------------------------------
// // 相当于下面
gulp.task('vae',function(done){
console.log('vae有很多烦恼');
done();
})
// 多个任务的执行
let{series}=require('gulp');
function xs(done){
console.log('因为他长得太帅了');
done();
}
function xb(done){
console.log('去年的家书两行,读来又热了眼眶');
done();
}
exports.default=series(xs,xb);
// ------------------------------------------------------------
// 相当于以下代码
gulp.task('xs',function(done){
console.log('因为他长得太帅了');
done();
})
gulp.task('xb',function(done){
console.log('去年的家书两行,读来又热了眼眶');
done();
})
gulp.task('default',gulp.series(['xs','xb']));
// 默认任务 default
exports.default=function(done){
console.log('独揽月下萤火,照亮一纸寂寞');
done();
}
gulp.task('default',function(done){
console.log('独揽月下萤火,照亮一纸寂寞');
done();
});
sass
// 变量测试
$bgColor:blue;
$fontColor:red;
$pColor:yellow;
$pSize:20px;
h1{
color: $fontColor;
}
p{
color: $pColor;
font-size:$pSize;
}
// @debug 10px+20px 用来调试错误
// 变量 变量镶嵌在字符中,必须#{}
$radius:radius;
.rounded{
border-#{$radius}:10px;
border:1px solid $bgColor;
}
// 使用nth()调取变量的值
$linkColor:green red pink!default; //!default表示当前项为默认值
div{
// background: $bgColor;
color:nth($linkColor,1);
&:hover{
color: nth($linkColor,2);
}
}
// sass中的map 获取$btnColor中map的e的值 map-get
$btnColor:(v:red,
a:yellow,
e:blue);
.btn{
background-color: map-get($btnColor,e );
}
// // map-has-key
@if map-has-key($btnColor,a){
.btn-e{
background-color: map-get($btnColor,a );
}
}
$border-style:(
text:#f44,
link:#f67,
border:#ef0,
backgroud:#ccc
);
// map-remove 删除$border-style中的text
// $border-style:map-remove($border-style,text);
// map-values 返回集合中的value值
$list:map-values($border-style);
@debug $list;
// // @if的使用
$bacolor:true;
.btn-a{
@if $bacolor{
background: #f44;
}
}
// 根据传入的值判断不同的状态,显示不同颜色
$status:success;
h3{
@if $status == login{
color: #6ff;
}@else if $status == erro{
color:yellow;
}@else if $status==success{
color:#33f;
}@else{
color:#3f7;
}
}
// sass 中的循环
// for 循环 $i表示变量,start表示起始值,end表示结束值,这两个的区别是关键字through表示包括end这个数,而to则不包括end这个数。
ul {
list-style: none;
}
@for $i from 1 through 6 { //包含最后一个
li:nth-child(#{$i}){
background-color: pink;
// background-image: url(../../day13/images/10.jpg);
float: left;
width: 100px;
height: 200px;
margin: 0 30px 10px 10px;
}
}
@for $i from 1 to 6 { //不包含最后一个
li:nth-child(#{$i}){
background-color: pink;
// background-image: url(../../day13/images/10.jpg);
float: left;
width: 100px;
height: 200px;
margin: 0 30px 10px 10px;
}
}
// each 循环 就是去遍历一个列表,然后从列表中取出对应的值
$link:(h1:20px, h2:10px, h3:5px);
@each $h,
$s in $link {
#{$h} {
font-size: #{$s}; //遍历html中的标签,设置相应属性
}
@debug #{$h};
}
// mixin的基本使用
@mixin button {
font-size: 20px;
padding: 10px 20px;
color: yellowgreen;
background-color: red;
}
.btn{
@include button;
}
.btn-e{
@include button;
}
// mixin 接收参数的使用 使用@include调用
@mixin button($bgColor) {
font-size: 20px;
padding: 10px 20px;
color: yellowgreen;
background-color:$bgColor;
}
.btn{
@include button(green);
}
.btn-e{
@include button(pink);
}
// 自定义函数
@function getWidtn($w){
@return $w*2;
}
.rounded{
max-width: #{getWidtn(20)}px;
}
// mixin 和function的区别
// 函数可以由多个语句组成,但是必须设定返回值(return)。但是混合(mixin)就可以不用设置返回值即可操作。函数(function)传入的值也可以带有变量
觉得博主汇总的不错的,可以收藏
支持一波~ 😊