- A+
基本概念
script标签
defer:脚本延迟到文档被解析和显示之后再执行 ! defer属性只适用于外部脚本文件
async:表示立即下载脚本,页面其他操作不影响 ! async属性只适用于外部脚本文件
<!-- 标记async的脚本不保证加载的先后顺序,第二个脚本可能会在第一个先执行 -->
<script src="js1.js" async></script>
<script src="js2.js" async></script>
// 不能再任何地方出现</script>,浏览器遇到</script>时会认为这是结束的标签
<!-- 解决方法 通过转义字符 解决这个问题 -->
alert("</script>");
严格模式
"use strict"; //函数体 告诉支持JavaScript引擎切换到严格模式
1.全局变量声明 必须加var。 必须先声明再使用。
2.函数内重名属性
3.arguments对象不被允许修改,只会是传进来的数值
fn.caller arguments.callee 不可用
4、函数本身不能使用this.关键字
5、eval()里存在作用域
6、新增保留字:implements, interface, let, package, private, protected, public, static, yield。
运算的问题
// 8进制 以0开头 代表8机制
var n4 = 070;// 56
// 16进制 以0x开头 代表16进制
var n5 = 0x1f;// 31
// NaN Not a Number 不是一个数字
console.log(typeof NaN);//number
console.log('我' + 10);//'我10'
console.log('wo' - 20);//NaN
console.log(0 / 20);//0
console.log(20 / 0);//infinity 无限
//浮点运算的问题
console.log(0.1 + 0.2);//0.30000000000000004
// console.log(0.1 + 0.2 == 0.3);//false
console.log(0.07 * 100);//7.00000000001
数值转换
数据类型 |
转换为true的值 |
转换为false的值 |
Boolean |
True |
False |
String |
非空字符串 |
'' |
Number |
非0数字 |
0和NaN |
Object |
任何对象 |
null |
Undefined |
n/a(不适用) |
Undefined |
isNaN()
不能被number转换为数字 ----> true
能被number转换为数字 ----> false
isNaN(NaN) //true
isNaN("blue") //true (不能被转换为数字)
isNaN(10) //false
isNaN("10") //false (10可以被转换成数值10)
isNaN(true) //false(可以被转换成1)
isFinite()
除NaN与Infinity 都返回true
console.log(isFinite(NaN)); // false
console.log(isFinite(Infinity)); // false
Number()
转换为为数值 无法转换 ---> NaN(不是一个数字
Number("hello") //NaN
Number("0011") //11
Number("") //0
Number(true) //1
parseInt()
转换为整数
参数1:要转换的变量
参数2:以什么进制来转换这个数值 默认10进制,0也是10进制
parseInt("234blue") //234
parseInt("blue234") //NaN
parseInt("") //NaN
parseInt("44.5") //44
parseInt("070") //56(8进制)
parseInt("0xf") //15(16进制)
parseInt("070" , 10) // ,后面告诉浏览器这是10进制
parseFloat()
转换为小数,只解析10进制,没有小数点或小数点后面都是0会返回整数
parseFloat('1234blue') //1234 整数
parseFloat('0xA') // 0
parseFloat('22.54.5') // 22.54
toString()
转换为字符串 不能转换 null 和 undefined
11.toString() // '11' 字符串
true.toString() // 'true' 字符串
toString()是对象下的方法,所以不能使用
String()
转型函数 能转换 null 和 undefined
String(null) //"null"
String(undefined) // "undefined"
+'' 拼接也可以转换为string
11 += ""; // "11" 字符串
数据类型检测
typeof
基本数据类型适用,引用数据类型会检测成object
String ----> string
Number ----> number
NaN ----> number
Boolean ----> boolean
undefined----> undefined
null -----> object
Object -----> object
Array -----> object
function-----> function
typeof typeof 123 //string
instanceof
根据原型链来识别返回 true 或 false
person instanceof Object //变量person是Object吗
person instanceof Array //变量person是Array吗
判断是否是数组
let arr = [];
console.log(arr instanceof Array); // true
console.log(arr.constructor === Array); // true
console.log(arr.__proto__ === Array.prototype); //true
console.log(Array.isArray(arr)); // true
console.log(Object.prototype.toString.call(arr)); // '[object Array]'
console.log(Array.prototype.isPrototypeOf(arr));// true
toString
Object.prototype.toString.call([])// [object Array]
Object.prototype.toString.call(2)// [object Number]
Object.prototype.toString.call(Function)// [object Function]
利用顶级对象toString方法改变this指向判断数据类型
运算符
一元运算符
++n 先自增1 再运算
n++ 先运算 再自增1
--n n-- 同理
! 转换为 Boolean 值
算术运算符
+ 加法比较特殊
两边都是数字时,做数学运算
一边为字符串,进行字符串连接
一边为对象类型object,将对象使用toString方法转换为字符串 进行连接
- * / % 只能数学运算 隐式用Number转换 不能转 ---> NaN
alert([10] + 10); //'1010'
alert([1,2,3] + 10); //'1,2,310'
alert({name:'joth'} + 10); //'[object Object]10'
alert(null + 10); //10
alert(undefined + 10); //NaN
alert(true + 10); //11
alert(null - 10); //-10
alert(undefined * 10); //NaN
alert([10,20] / 10); //NaN
alert(1 % 0); //NaN
alert(100 % null); //NaN
比较运算符
大于 > 小于 < 大于等于 >= 小于等于 <= 等于 == 全等 === 不等于 != 不全等 !==
== 等于时 只需要值相等 不用管数据类型 实际上也是通过Number进行类型转换
=== 全等时 不会进行数据类型转换 那么需要两边的数据类型和值都相等
特例 undefined == null 为真(js真理)
console.log('10' == 10);//true
console.log('10' === 10);//false
console.log(undefined == null);//true
console.log(undefined === null);//false 数据类型不同
逻辑运算符
非 ! 取反 非真为假 非假为真
与 && 与运算见假则假
或 || 或运算见真则真
console.log(!false);//true
console.log(!!false);//false
// 与运算 与运算见假则假
console.log(true && false);//false
console.log(false && true);//false
console.log(false && false);//false
console.log(true && true);//true
// 或运算 或运算见真则真
console.log(true || false);//true
console.log(false || true);//true
console.log(true || true);//true
console.log(false || false);//false
console.log(10 > 3 && '10' > '3');//false
短路运算
短路与: 第一个值为true 返回第二个值, 第一个值为false,则返回第一个值
短路或: 第一个值为true 返回第一个值, 第一个值为false,则返回第二个值
// 短路与
console.log(10 && null);//null
console.log(undefined && 'abc');//undefined
// 短路或
console.log(10 || null);//10
console.log(undefined || 'abc');//'abc'
三目运算符
方法: ? : ---> 判断条件 ? 当条件为真时 返回的值 : 当条件为假时返回的值
var y = -20 > 0 ? 1 : -20 == 0 ? 0 : -1;
赋值运算符
= 赋值 += -= *= /= %=
a += 5; 等价于 a = a + 5;
a -= 10; 等价于 a = a - 10;
a *= 3 等价于 a = a * 3
a /= 2 等价于 a = a / 2
a %= 2 等价于 a = a % 2
隐式类型转换
+ - * / %
+ 转换方式比较多
- * / % 都是使用Number转数字 能转数字就运算 不能转数字就NaN
括号运算符
var a = (1,2,2,1,0) //0 返回最后一项
语句
if
if( i > 1){
alert("yes");
}else {
alert ("no");
}
do-while
语句最少执行一次
var i = 0;
do {
i += 2;
} while (i < 10);
while
var i = 0;
while ( i < 10){
i += 2;
}
for
var a = 0;
for (var i = 0; a < 10; i++){
a += 1;
}
for in
遍历数组/对象
var arr= ["Saab","Volvo","BMW"]
for (var x in arr){
document.write(arr[x] + "<br />")
}
break;停止循环
continue;停止这次循环
with
改变代码块的作用域,查找变量会先找obj里面的
大量使用with会导致性能下降 不建议使用
with( obj ){
// 代码块
}
switch
switch (i){
case "0" :
alert(“1”)
break;
}
数据类型
- 变量声明分为字面量创建 和 构造函数(实例化)创建
- 构造函数创建 typeof 检测数据类型都为object
- 原生对象:String,Number,Boolean,Function,object,Array,Date,Error,RegExp,global,Math
- 内置对象:global,Math
- 宿主对象:DOM,BOM
- 全局对象:window(document)
String
取值
str.charAt(1);// 返回下标
str[1];// 返回下标
str.charCodeAt(1);// 返回下标对应Unicode编码
String.fromCharCode(97,99);// 'ac' 返回对应Unicode码对应字符
截取
不会对原始字符串修改,返回值的副本
只有一个参数,截取到字符结束
str.substring(0,2);
起始下标,结束下标-1
起始大于结束,会互换
起始为负数,默认变0
str.slice(0,3);
起始下标,结束下标-1
起始大于结束,不换位,返回空字符串
出现负值,为倒数 = length + 负数
str.substr(1,3);
起始下标,截取位数
出现负值,为倒数 = length + 负数
位置查询
str.indexOf("o") // 查询字符下标 没有返回 -1
str.lastIndexOf("o")// 从末尾查询 下标还是从左开始 没有返回 -1
str.indexOf("o",6) // 下标6 开始查询
str.lastIndexOf("2",3)// 下标3 向下标0 倒序搜
str.search("ol");// 下标0开始查找 indexOf 但可以传正则
分隔/拼接
分隔
str.split(",",2);
参数1: 以 , 分隔 返回数组,可以传正则
参数2 : 可选,返回数组的length,后面多余的不会有
拼接
str.concat("!");//拼接字符串
编辑/替换
// trim()
str.trim(); // 删除前后的空格,中间的空格不会删除,返回副本
// replace 查找字符,要替换字符
str.replace("at","oo");//coo, bat, sat 只会替换第一个
str.replace(/at/g,"oo");//coo, boo, soo 全局替换要正则表达式
大小写转换
str.toUpperCase();// AAA BB 大写
str.toLocaleUpperCase();// AAA BB 大写
str.toLowerCase();// aaa bb 小写
str.toLocaleLowerCase();// aaa bb 小写
URI编码方法
encodeURI("https://www.baidu.com /") //https://www.baidu.com%20/
只有空格替换成%20
encodeURIComponent("https://www.baidu.com /") //https%3A%2F%2Fwww.baidu.com%20%2F
除字母数字符号 替换成 对应的编码
decodeURI("https://www.baidu%23.com%20") // https://www.baidu%23.com
%20会变成空格
%23是decodeURIComponent的字符不会被转换
decodeURIComponent(url1); //https://www.baidu#.com
所有的字符变成原来的(但这个字符不是一个有效的URL
eval()
解析字符串js代码
eval("function hi(){console.log('hi');}")
hi();// eval 可以将字符串直接当做完整的js代码解析运行
eval("var a = 'hello world'");// 不会有变量提升,因为包含在字符串中,只有eval运行的时候才会被解析
localeCompare()
比较字符串在字母表的前后
在前面返回 1
在后面返回 -1
var str = "yellow";
str.localeCompare("brick") // 1
str.localeCompare("yellow") // 0
str.localeCompare("zoo") // -1
// 姓名比较 sort姓名排序
"张".localeCompare("啊","cn");// 1 张Z 的字母表 在 啊A 的后面
// 中文的比较方法 ---- 可以比较任何文字
var arr = [
{ name: '武丽昕', num: 78 },
{ name: '汤文博', num: 38 },
{ name: '卢文博', num: 58 },
{ name: '付秋萍', num: 79 }
];
// 中文名 进行排序
arr.sort(function(a, b){
return a.name.localeCompare(b.name, 'zh');
})
Number
var num = 10;
num.toString() // '10'
num.toString(2) // 2进制转换
num.toFixed(2) // 保留几位小数
num.toExponential(1) // 1.0e+1 科学计数法
var num1 = 99;
num1.toPrecision(1)// 1e+2 向上舍入为100
num1.toPrecision(2)// 99
num1.toPrecision(3)// 99.0
Number.isFinite()
没有隐式的 Number() 类型转换,所有非数值都返回 false
检查一个数值是否为有限的( finite ),即不是 Infinity
Number.isFinite(1); // true
Number.isFinite(0.1); // true
Number.isFinite(NaN); // false 不是有限的
Number.isInteger()
Number.isInteger(0); // true
// JavaScript 内部,整数和浮点数采用的是同样的储存方法,因此 1 与 1.0 被视为相同的值
Number.isInteger(1); // true
Number.isInteger(1.0); // true
Array
创建
new Array(10);// 一个值是数组的长度,值为empty(空
new Array('1','3');//多个值与字面量一样
利用length 可以在末尾添加一项
as[as.length] = "red";
as[99] = "green"; //下标99添加,3到98都是undefined
转换方法
var color = ['red','pink','green'];
console.log(color.toString()) //red,pink,green
console.log(color.valueOf()) //(3) ["red", "pink", "green"] 返回数组对象的原始值
改变原数组(7个方法
arr.push();//末尾添加 一个/多个值, 返回新length
arr.pop();//删除末尾的值,返回删除的值
arr.unshift();//前面添加 一个/多个值,返回新length
arr.shift();//删除第一个值,返回删除的值
arr.reverse();//数组逆序,不是排序
arr.sort((a,b)=>a-b);//升序,return 大于0的值,a b互换,小于0不换
arr.splice(startIndex,length,'替换或插入的值 ?可选');//起始下标,截取的长度,返回剪切的[数组]
不改变原数组
arr.concat('12',[2]);//拼接数字或字符,返回新数组
arr.slice(startIndex,endIndex);//截取开始下标,结束下标-1
arr.join("-");//返回以标识符连接字符串
arr.toString();//返回数组的字符串
arr.indexOf('2');//查找数值在数组的位置,有返回下标,没有返回-1
Array.isArray([]);//传入的参数是否是数组,是返回true
数组迭代
arr.every((items,i,arr)=>{return 条件});//条件每一项为true,全部符合条件才为true
arr.some((items,i,arr)=>{return 条件});//条件有一项为true,则为true
arr.filter((items,i,arr)=>{return 条件});//返回符合条件的值,组成数组返回,没有符合返回空[]
arr.forEach((items,i,arr)=>{});//遍历
arr.map((items,i,arr)=>{return val*2});//遍历每一项,组成新数组返回
归并 arr.reduce(function(prev,cur,index,array){
return prev + cur ;
})//15 prev是1 cur是2 相加后 prev是3(相加后的结果) cur是3 数组中的3
// reduceRight与reduce是一样的,从右边开始遍历
类数组
var obj = {
"0" : "12",
"1" : 21,
"2" : "122",
length : 1,
splice : Array.prototype.splice,
}
console.log(obj);
/*
条件:1、键为 0 1 2 3的数字
2、有length属性
3、绑定splice为Array原型上的方法
此时输出的obj为数组
*/
数组去重
var arr = [9,9,0,0,2,3,2,3,5];
var a = [];
arr.forEach(function(item,index,arr){
if(a.indexOf(item) == -1){
a.push(item);
}
});
冒泡排序
// 二重循环 外层循环控制比较次数 内层 两两相邻进行比较换位 谁大谁换到后一位
for(var i = 0; i < arr.length; i++){
for(var j = 0; j < arr.length - i; j++){//循环相邻两位比较 外层每走一次 内层的循环最大值 就减小i
// 内层循环进行相邻的两两比较
if(arr[j] > arr[j + 1]){//如果 前一项大于后一项 进行换位
// 引入第3个变量 才能进行两个变量的值的交互
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
选择排序
for(var i = 0; i < arr.length; i++){//外层循环 控制每次选择的下标
for(var j = i + 1; j < arr.length; j++){//内层循环 控制 i下标的后续下标
if(arr[i] > arr[j]){//比较 选择的下标值 和后续的下标的值 谁小 就将谁换到选择的下标上来 然后在用选择的下标上换来的值 和后续下标值进行比较
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
递归排序
function qSort(arr){
// 当 lArr或rArr中 只有一个数据项或没有数据项时 就返回该数组本身 边界条件
if(arr.length <= 1){
return arr;
}
// 获取中间下标值
var mIndex = Math.floor(arr.length / 2);
// 截取中间下标对应的值
var mVal = arr.splice(mIndex , 1)[0];
// 创建左右空数组
var lArr = [], rArr = [];//千万不能 var lArr = rArr = [];
// 遍历数组中剩余的数据项 当该数据项小于 mVal就放到lArr中 当大于mVal就放到rArr
for(var i = 0; i < arr.length; i++){
if(arr[i] < mVal){
lArr.push(arr[i]);
}else{
rArr.push(arr[i]);
}
}
// 合并返回新数组 切对lArr数组和rArr数组进行递归
return qSort(lArr).concat(mVal, qSort(rArr));
}
Math
// 最大最小值
console.log(Math.max(1,3,4,5,9)); //最大值
console.log(Math.min(1,3,4,5,9)); //最小值
console.log(Math.max.apply(Math,[2,3,6]));//最大值
console.log(Math.min.apply(Math,[2,3,6]));//最小值
// 舍入
console.log(Math.ceil(1.3));//向上舍入
console.log(Math.floor(1.9));//向下舍入
console.log(Math.round(1.49));// 1 四舍五入(只看小数点后一位数)
console.log(Math.floor(Math.random() * 10 + 1));
// 随机一个 [A - B] 之间的随机数
function selectFrom(A,B){
return Math.floor(Math.random() * (B - A + 1) + A)
}
selectFrom(2,9);//生成 2 -9 (包括2和9) 的随机数
// 其他方法
var num = -2.4;
Math.abs(num);//绝对值
Math.exp(num);//返回Math.E的num次幂
Math.log(num);//自然对数
Math.pow(num,p);// num 的 p次幂
Math.sqrt(num);//num的平方根
Math.PI();//表示数学中的π 代表的是180的弧度
1弧度 = Math.PI() / 180;
----下面的方法传入的值要是弧度,不能传数字----
Math.acos(x);//x的反余弦值
Math.asin(x);//x的反正弦值
Math.atan(x);//反正切值
Math.atan2(x,y)//y/x的反正切值
Math.cos(x)//x的余弦值
Math.sin(x)//x的正弦值
Math.tan(x)//x的正切值
-------------------------
Math.cbrt(1); // 1 计算一个数的立方根
Math.cbrt('1'); // 1 会对非数值进行转换
Math.imul(1, 2); // 2 大多数情况下,与 a * b 相同
Date
创建日期
new Date(); //英文 星期几 月 日 年 时:分:秒 地区
new Date(Date.parse("may 25 , 2004")) //以传入的时间为起始
new Date(Date.UTC(2005 , 4 , 5 , 17 , 5, 55)) //UTC时间
new Date("2005,4,5,5,17,5,55") //本地时间 年月日
var start = Date.now() //取得开始时间 , 调用函数
var stop = Date.now() //取得结束时间
var start1 = new Date(); //取得开始时间 , 调用函数
var stop1 = new Date();//取得结束时间
Date.parse("2020-1-3");//取得传入时间的时间戳
时间格式化
date.toDateString();// 显示星期几、月 日 年
date.toTimeString();// 显示 时 分 秒 地区
date.toLocaleDateString();//以特定地图显示 星期几、月 日 年
date.toLocaleTimeString(); //以特定地图显示 时 分 秒
date.toUTCString(); // 显示完整UTC时间
时间组件
date.getTime(毫秒); // 返回日期的毫秒数
date.setTime(); // 以毫秒设置日期,会改变整个日期
date.getFullYear(年); // 取得4位数的年份
date.setFullYear(); // 设置4位数的年份
date.getUTCFullYear();//返回UTC日期的4位数年份
date.setUTCFullYear();//设置UTC日期的4位数年份
date.getMonth(月);//取得月份 0表示1月
date.setMonth();//设置月份 传入月份必须大于0 超过11会增加年份
date.getDate(日);//取得日期天数 1- 31
date.setDate();//设置日期天数
date.getDay(星期);//取得星期几 0是星期天
date.getHours(时);//取得小时0 - 23
date.setHours();//设置小时超过23会增加天数
date.getMinutes(分);//取得分钟 0 - 59
date.setMinutes();//设置分钟数 超过59会加小时
date.getseconds(秒);//取得秒数 0-59
date.setSeconds();//设置秒数
date.getMilliseconds(毫秒);//取得毫秒
date.setUTCMilliseconds();//设置毫秒
date.getTimezoneOffset(UTC相差分钟);//返回本地时间与UTC时间相差的分钟数
function
函数分类
普通命名函数
通过名字调用执行
function fn(){}
事件处理函数
可以是匿名函数也可以是匿名函数,通过元素对象的事件触发来执行
btn.onclick = function(){}
构造函数
通过new运算符来执行
function Person(){}
new Person();
回调函数
在主函数中满足一定条件调用执行 匿名函数也可以是命名函数
表达式函数:将一个函数 赋值给一个变量 通过函数名的调用执行
var a = function(){}
匿名函数:闭包
;(function(name){
console.log(name);
return 'aaa';
})('mark');
callee 与 caller
function a(){
console.log(arguments.callee);// 当前函数
console.log(a.caller); // 真正调用此函数的函数
}
改变this指向
fn.call(obj,a,b,c...);//多个参数
fn.apply(obj,[a,b,c...]);//两个参数,第二个为数组
fn.bind(obj,a,b,c...);// 与call一样,返回的是函数本身
注意:第一个参数传null为不改变this指向
EegExp
修饰符
g:全局模式,表示查找字符串的全部内容,而不是找到第一个匹配的内容就结束。
i:不区分大小写,表示在查找匹配时忽略pattern 和字符串的大小写。
m:多行模式,表示查找到一行文本末尾时会继续查找。
y:粘附模式,表示只查找从lastIndex 开始及之后的字符串。
u:Unicode 模式,启用Unicode 匹配。
s:dotAll 模式,表示元字符,匹配任何字符(包括n 或r)。
实例属性
global:布尔值,表示是否设置了g 标记。
ignoreCase:布尔值,表示是否设置了i 标记。
unicode:布尔值,表示是否设置了u 标记。
sticky:布尔值,表示是否设置了y 标记。
lastIndex:整数,表示在源字符串中下一次搜索的开始位置,始终从0 开始。
multiline:布尔值,表示是否设置了m 标记。
dotAll:布尔值,表示是否设置了s 标记。
source:正则表达式的字面量字符串(不是传给构造函数的模式字符串),没有开头和结尾的
斜杠。
flags:正则表达式的标记字符串。始终以字面量而非传入构造函数的字符串模式形式返回(没
有前后斜杠)。
方法
test()
test:检测字符串是否匹配正则 如果匹配 返回true 不匹配返回false 表单验证的返回值
/is/.test('my name is joth') //true
/is/.test('you are a ediot') //false
RegExp.input // 查询的字符串
RegExp.leftContext // 返回表达式之前的字符串
RegExp.rightContext // 返回表达式之后的字符串
RegExp.lastMatch // 返回与表达式匹配的字符串
RegExp.lastParen // 返回(.)匹配的捕捉组
macth()
全局 返回所有匹配字符串组成的一个数组。
非全局 返回匹配到的第一个字符串数组,且会返回该字符串的下标及相关信息。
var str = 'my name is mark, my age is 18, my sex is male';
var reg = /is/;
str.match(reg);//["is", index: 8, input: "my name is mark, my age is 18, my sex is male", groups: undefined]
// 全局模式
var reg = /is/g;
console.log(str.match(reg));//["is", "is", "is"]
exec()
全局模式 有一个自己的lastIndex值 引导下次进行exec匹配的起始位置。
非全局模式下进行字符串的匹配 结果和macth一样
var str = 'my name is mark, my age is 18, my sex is male';
var reg = /is/;
// 非全局
reg.exec(str)//["is", index: 8, input: "my name is mark, my age is 18, my sex is male", groups: undefined]
// 全局
var reg = /is/g;
reg.lastIndex //0
reg.exec(str) //["is", index: 8, input: "my name is mark, my age is 18, my sex is male", groups: undefined]
reg.lastIndex //10
reg.exec(str) //["is", index: 24, input: "my name is mark, my age is 18, my sex is male", groups: undefined]
reg.lastIndex //26
reg.exec(str) //["is", index: 38, input: "my name is mark, my age is 18, my sex is male", groups: undefined]
reg.lastIndex //40
reg.exec(str) //null
reg.lastIndex //0
正则预查询
判断括号内表达式
返回 ---> 括号外表达式
正向肯定
(?=):
表达式1(?= 表达式2)
返回 --> 前面是表达式1
后面是表达式2
var path1 = 'path/hello.html';
var reg = /w+(?=.html)/; // 前面是数字字母_ 后面是.html
path1.match(reg); // hello
正向否定
(?!):
表达式1(?!表达式2)
返回 ---> 前面是表达式1
后面不是表达式2
var str = 'a,1,b,2,c,3,'
var reg = /,(?![a-z]|$)/g; // 前面是, 后面不是字母
console.log(str.replace(reg, '=')); // 'a=1,b=2,c=3,'
反向肯定
(?<=):
(?<=表达式2)表达式1
前面是表达式2
返回 ---> 后面是表达式1
var path1 = 'path/hello.html';
var reg = /(?<=path/)w+/; // 前面是path/ 后面是数字字母_
console.log(path1.match(reg)); // hello
反向否定
(?<!):
(?<!表达式2)表达式1
前面不是表达式2
返回 ----> 表达式1
var str = 'a,1,b,2,c,3,';
var reg1 = /(?<!d),/g; // 前面不是, 后面是,
str.replace(reg1, '=') // 'a=1,b=2,c=3,'
元字符
单个字符
. 匹配除换行外单个的任意字符
[范围] 匹配单个范围内的字符
[0-9] 匹配单个 数字
[^范围] 匹配单个范围内除括号内的字符
[^0-9] 匹配单个 非数字
[a-zA-Z0-9_] 匹配单个 数字、字母、下划线
w 匹配单个 数字、字母、下划线 等价于[a-zA-Z0-9_]
W 匹配单个 非数字、字母、下划线
d 匹配单个 数字 等价于[0-9]
D 匹配单个 非数字 等价于[^0-9]
重复字符 x 代表任意的单个字符
x? 匹配0个或1个x /goog?le/ 要么是google 要么是goole
x+ 匹配最少1个字符
x* 匹配任意个x字符
x{m,n} 匹配至少m个,最多n个(包括n
x{n} 必须匹配n个字符
(xyz)+ 小括号括起来的部分是当做单个字符处理
空白字符
s 匹配任意单个空白字符(空格 制表 回车
S 匹配任意单个非空白字符
b 单词边界
B 非单词边界
锚字符
^ 行首匹配/^google/
$ 行尾匹配/google$/
替代字符
| 或 /google|baidu|bing/
转义字符
.
*
// 验证字符串是否存中文
/^[u4e00-u9fa5]+$/
Error
EvalError:eval()的使用与定义不一致
RangeError:数值越界 一个数字超出它的边界时抛出。该错误在正常的代码执行中非常罕见
ReferenceError:非法或不能识别的引用 期望的对象不存在时抛出
SyntaxError:有语法错误时抛出
TypeError:变量不是期望的类型时抛出
URIError:UR处理函数使用不当 给encodeURI(), encodeURIComponent(), decodeURI()或者decodeURIComponent()等函数传递格式非法的URI字符串时抛出
Object
Object.create()
Object.create(prototype, [descriptors])
返回一个新对象
新对象的__proto__指向第一个参数。参数可以为null,即没有原型对象
要添加的属性以及配置
var newObj=Object.create(obj,{
sex:{// 键名
value:"男",//键值,默认undefined
writable:true,//是否可以被修改。默认false
configurable:true,//是否可以被删除。默认false
enumerable:true,//是否支持可枚举(for in访问)。默认值是false
}
});
Object.defineProperty()
Object.defineProperty(obj, [propName], descriptor)
直接操作参数1 obj地址
propName : 添加的键名[两个参数时 = 配置选项的value值]
descriptor : 配置选项
var obj = {sex1:''};
Object.defineProperties(obj,{
sex:{
// 也可以有Object.create()的配置
set(value){//赋值时调用
this.sex1=value;
},
get(){//获取值时调用
return this.sex1;
}
}
})
1、可以多次调用 Object.defineProperty()方法修改同一个属性,但把configurable
设置为false 之后就会报错。
2、当使用了getter或setter方法,不允许使用writable和value这两个属性。如果使用,会直接报错
Object.assign()
Object.assign(target, ...sources)
后面的sources源对象 拷贝到 target目标对象上
返回target对象
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returned = Object.assign(target, source);
console.log(target); // Object { a: 1, b: 4, c: 5 }
console.log(returned); // Object { a: 1, b: 4, c: 5 }
会调用源对象的[[Get]]
和目标对象的[[Set]]
Object.keys()
var user ={
name:"狂奔的蜗牛",
age:25
}
var keys = Object.keys(user)// ['name','age'] 返回键的数组,参数可以是原型对象
只遍历键
for (let key of Object.keys(obj)){
console.log(key);
}
Object.values()
var user ={
name:"狂奔的蜗牛",
age:25
}
var keys = Object.values(user) // ["狂奔的蜗牛", 25]
只遍历值
for(let item of Object.values(obj)){
console.log(item);
}
Object.entries()
遍历键和值
以二维数组的形式,将对象中的每个键名和键值,进行数组分解。
for(let [key,item] of Object.entries(obj)){
console.log(item,key);
}
Object.getOwnPropertyNames()
Object.getOwnPropertyNames(Person.prototype)
// ["constructor", "name", "job", "sayName"] 返回键的数组
包含constructor
不包含Symbol 属性
Object.getOwnPropertySymbols()
Object.getOwnPropertySymbols(obj)
参数:要返回 Symbol 属性的对象。
返回值:对象自身上找到的所有 Symbol 属性的数组。
var obj = {};
var a = Symbol("a");
var b = Symbol.for("b");
obj[a] = "localSymbol";
obj[b] = "globalSymbol";
var objectSymbols = Object.getOwnPropertySymbols(obj);
console.log(objectSymbols.length); // 2
console.log(objectSymbols) // [Symbol(a), Symbol(b)]
console.log(objectSymbols[0]) // Symbol(a)
Object.is()
Object.is(value1, value2);
比较两个值是否相等,与 == 和 === 不一样。返回 true/false
Object.is('foo', 'foo'); // true
Object.is(window, window); // true
Object.is([], []); // false
var foo = { a: 1 };
var bar = { a: 1 };
Object.is(foo, foo); // true
Object.is(foo, bar); // false
Object.is(null, null); // true
// 特例
Object.is(0, -0); // false
Object.is(0, +0); // true
Object.is(-0, -0); // true
Object.is(NaN, 0/0); // true
Object.getPrototypeOf()
Object.getPrototypeOf(object)
返回参数的原型对象,没有继承属性则返回 null
Object.getPrototypeOf( Object ); // ƒ () { [native code] }
Object.getPrototypeOf( Function ); // ƒ () { [native code] }
Object.getPrototypeOf( Object ) === Function.prototype; // true
var obj = new Object();
Object.prototype === Object.getPrototypeOf( obj ); // true
Object.prototype === Object.getPrototypeOf( {} ); // true
Object.freeze()
Object.freeze(obj); // 返回被冻结的对象; 返回传递的对象,不是创建一个被冻结的副本
//冻结一个对象,冻结后不能添加删除,包括配置,可枚举,可写性等;也包括原型上的属性
Object.seal()
Object.seal(obj); // 返回被封闭的对象的引用
// 阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。
// 不会影响从原型链上继承的属性。但 __proto__ 属性的值也会不能修改。
面向对象
创建对象
/*
new 做了什么
1、函数开始隐式创建了一个空对象 ----> new Object() = {}
2、将函数中的this指向空对象,在该对象上添加属性和方法 ----> this = {}
3、将该对象的__proto__指向函数的prototype
4、隐式的返回this
*/
字面量创建
var obj = {};
实例化创建
var obj = new Object();
工厂模式
function create(name){
var obj = {};
obj.name = name;
return name;
}
var obj = create('xiaoming');
构造函数创建
function Person(name){
this.name = name;
}
var person = new Person('小明');
原型创建
function Person(){}
Person.prototype.fn = function(){
console.log('共享');
}
var person = new Person();
混合创建
function Person(name){
this.name = name;
}
Person.prototype.eat = function(){
console.log('混合创建');
}
var person = new Person('xiaowan');
动态混合创建
function Person(name){
this.name = name;
if(typeof this.eat == 'function'){
Person.prototype.ear = function(){
console.log('混合创建');
}
}
}
var person = new Person('xiaoming');
原型继承
原型链继承
function Person(name){
this.name = name;
}
Person.prototype.fn = function(){
console.log('parent');
}
function Child(){}
Child.prototype = new Person('name');// new 之后 只是实例化的对象,下面有__proto__
Child.prototype.constructor = Child;// 手动修改回来
var child = new Child();
/* 在原型上继承,子类不能修改和传参进去 */
对象冒充继承(借用构造函数
function Parent(name){
this.name = name;
}
Parent.prototype.fn = function(){
console.log('parent');
}
function Child(name){
Parent.call(this,name);
}
var child = new Child('xiaohong');
组合继承
function Parent(name){
this.name = name;
}
Parent.prototype.eat = function(){
console.log('11');
}
function Child(name){
Person.call(this,name);
}
Child.prototype.eat = Parent.prototype;
Child.prototype.constructor = Child;
寄生式组合继承
function Parent(name){
this.name = name;
}
Parent.prototype.aa = function(){
console.log('aa');
}
function inherit(Child,Parent){
function Super(){};
Super.prototype = Parent.prototype;
Child.prototype = new Super();
Child.prototype.constructor = Child;
}
function Child(){}
inherit(Child,Parent);
var child = new Child();
for...in继承
// 遍历父原型对象
for(funName in Person.prototype){
// 子构造函数原型属性 = 父原型对象的属性
NewPerson.prototype[funName] = Person.prototype[funName];
}
Object.create()继承
create创建新对象
NewPerson.prototype = Object.create(Person.prototype)
方法
aa instanceof Fun aa 是由构造函数 Fun构造出来的吗 返回 Boolean
Object.getPrototypeOf(Person) // 返回Person 构造函数的原型
Object.getPrototypeOf(Person) == Person.prototype // true
检查来自实例还是原型
Person.hasOwnProperty("fun"); // 是来自实例 返回 true 不是返回 false
console.log('name' in a); // 实例 或 原型上有都返回 true
利用hasOwnProperty 与 in 判断到底来自实例还是原型
function hasO(object,name){
return object.hasOwnProperty(name) && (name in object);
判断是不是来自实例,如果不是,再in判断是不是原型
}
返回实例或原型
将实例保存为数组
function Person(){this.age = 'age';}
Person.prototype.name = "nn";
Person.prototype.sayName = function(){}
var p = new Person();
Object.keys(Person.prototype); //["name", "sayName"] 原型中的所有实例
Object.keys(p) // ["age"] 只返回p 的实例
Object.getOwnPropertyNames(Person.prototype) // ["constructor", "name", "job", "sayName"] 包含constructor
BOM
系统对话框
alert("hello");
confirm("确定?");// 返回 true false
prompt("输入文本","默认文本");// 返回输入的值 取消返回null
window.print();//打印对话框
window.find();//查找对话框
console.time()
console.time("test1")
var div = document.getElementById("div");
console.timeEnd("test1")
测试从上一个test1到这行代码运行所用的时间
open及close
open(url,'_blank',新窗口尺寸,是否替换当前历史记录 boolean)
close()关闭当前页面
location 对象
协议://主机名:端口号 /路径/ ?查询字符串 #锚点
https://127.0.0.1:5500/javascript.html/?a=ssa&bd=asd#aaa
location.hash // #aaa 哈希值
location.host //127.0.0.1:5500 域名+端口
location.hostname //127.0.0.1 域名
location.href //https:127.0.0.1:5500/?a=ssa&bd=asd#aaa url地址 toString()也能返回这个值
location.origin //https:127.0.0.1:5500 文件来源地址
location.pathname // /JavaScript.html 文件路径
location.port // 5500 端口
location.protocol // https: 协议
location.search // ?a=ssa&bd=asd 表单提交的数据
location.port = 8080; //可以用这样的方法修改上面的值,除了hash值外,页面都会以新的URL重新加载
location = 'http://www.163.com';
location.assign(url)//在当前窗口跳转到这个URL
location.replace("http://baidu.com");//在当前窗口替换成新的URL用户将不能回到前一个页面
location.reload();//重新加载 (可能从缓存中加载
location.reload(true);//重新加载 (从服务器重新加载
history 对象
history.go(-1);//后退一页
history.go(0);//刷新当前页面
history.go(2);//前进两页
history.go("wrox.com");//跳转到最近wrox.com的页面
history.back();//后退一页
history.forward();//前进一页
(history.length == 0) //这是用户打开宽口后的第一个页面
navigator 对象
navigator.appCodeName 浏览器代号
navigator.appName 浏览名称
navigator.appVersion 浏览器版本
navigator.cookieEnabled 是否启用cookie
navigator.language 系统语言:标准
navigator.systemLanguage 系统语言:ie
navigator.platform 操作系统
navigator.userAgent 用户代理
窗口位置
p.clientWidth; // 可视宽度 width + padding
p.clientTop; // 上边框宽度
p.clientLeft; // 左边框宽度
p.offsetParent; // 获取上一个带有定位的父元素
p.offsetWidth; // 占位宽度 width + padding + border
p.offsetLeft; // 距上一个具有定位元素边框的距离
document.documentElement.clientWidth || document.body.clientWidth; // 宽口宽度
document.documentElement.scrollTop/Left;// 已滚动出的距离
DOM
获取元素 ( 选择符
document.querySelector("css选择器");// 只选择符合的第一个,静态获取,后添加的元素不会加进来
document.querySelectorAll("css选择器");// 取得span伪数组集合
document.body.MatchesSelector("body.page");//这个方法能够判断能否 被以上两个方法选择返回
document.getElementsByTagName("标签名");//获取标签名 集合
document.getElementsByClassName("class名");//获取class 集合
document.getElementsByName("name属性值");//使用在表单元素
div.namedItem("aa");//div中name属性为aa 的集合
div["aa"];// div中 name属性为aa 的集合
div.tagName;// DIV 在HTML中始终以大写表示
document.title;// 取得文档标题
document.URL;// 取得地址栏显示的URL 不能修改
document.domain;//域p2p.wrox.com 修改成wrox.com可以成功 修改成其他跨域会出错
document.referrer;// 取得来源此页面的URL
// 特殊集合
document.anchors;// 所有带name特性的a标签
document.forms;// 所有form元素
document.images;// 所有img元素
document.links;// 所有带href特性的a元素
node节点
获取节点
父节点.childNodes 获取子节点(包含一切节点)
p.nodeType == 1//true 判断是否存在节点 是不是一个元素
1 元素节点 2 属性节点 3 文本节点
nodeName
#text 文本节点的名字
P 元素节点的元素名 大写
#comment 注释节点的名字
p.nodeValue //文本节点的内容
必须是文本节点,元素节点会返回null
父元素.children 获取子节点
IE9+ 正常
IE8-中 会获取 注释和元素节点
// 父节点
p.parentNode;//获取直系父元素
p.offsetParent;//获取上一个带有定位的父元素,position:stalic不算
/*
兼容方法
firstchild 都有值,firstElementChild IE会undefined
短路运算
firstElementChild || firstchild;
*/
// 子节点
p.firstChild;//标准浏览器获取第一个 文本或换行 节点,IE只获取第一个元素
p.firstElementChild;//标准浏览器只获取第一个元素,IE为 undefined
lastElementChild || lastChild; 最后一个子节点
// 兄弟节点
p.previousElementSibling || p.previousSibling;// 上一个兄弟节点
p.nextElementSibling || p.nextSibling;//下一个兄弟节点
操作节点
// 新建节点
var li = document.createElement("p"); // 新建li元素
var text = document.createTextNode("wenben"); // 新建文本
// 插入节点
父节点.appendChild(li);// 父节点的末尾插入
父节点.insertBefore(li,参照子节点);// 在参照子节点前插入
// 替换节点
//替换之前的文本依然还在 ,但它在文档中已经没了自己的位置
父节点.replaceChild(新节点,被替换的子节点);// 替换
// 删除节点
//移除的节点仍然为文档所有,只不过没有了自己的位置
父节点.removeChild(子节点);//删除子节点
节点.remove();//自己删除自己
// 克隆节点
节点.cloneNode(false);// 默认:只复制本身空标签
节点.cloneNode(true);// 本身与所有子节点都复制
attribute 属性
div.getAttribute("className");// 获取属性
div.setAttribute("class","ft");// 设置属性
div.removeAttribute("class");// 删除属性
div.attributes;//获取div所有的属性 返回集合
获取样式
// 兼容所有浏览器
function getStyle(node,cssStyle){
// IE获取 标准浏览器
return node.currentStyle ? node.currentStyle[cssStyle] : getComputedStyle(node)[cssStyle];
}
getComputedStyle(div)["width"];//标准浏览器
div.currentStyle["width"];//兼容IE浏览器
div.style只能获取到行间的css样式
div.style.cssText = "width: 200px;height: 30px;";// 设置css样式
div.style.getPropertyValue("width");// 200px 取得宽度值
div.style.removeProperty("width");// 删除width 属性
// 取得计算后的css样式
div.style.cssText = "width:200px";
div.style.getPropertyValue("width");//取得设置cssText的样式
表格操作
// 表头
oTab.tHead
// 表体 多个tbody
oTab.tBodies[0]
// 表尾
oTab.tFoot
// tr 一行
oTab.tBodies[0].rows[1]
// td 单元格
oTab.tBodies[0].rows[1].cells[1]
classList 属性
div.classList.remove("user");// 删除user 类
div.classList.add("current");// 添加current类
div.classList.toggle("user");// 切换user类
div.classList.contains("d");//判断是否有 d 类
btn.onfocus();// 获取焦点
btn.onblur(); // 取消焦点
// 兼容模式
document.compatMode;//标准模式下 CSS1Compat 混杂模式下 BackCompat
data- 属性
var name = div.dataset.name;// 123 取得自定义data属性的值
div.dataset.name = "222";// 设置data属性的值
事件
鼠标事件
click 单击
dblclick 双击
mouseover 移入(子节点会触发)
mouseout 移出(子节点会触发)
mousemove 移动(会不停的触发)
mouseenter 移入(子节点不会触发)IE8+
mouseleave 移出(子节点不会触发)IE8+
mousedown 按下(左右键)
mouseup 抬起(左右键)
contextmenu 右键单击(上下文环境菜单)
onmousewheel ----> chrome ie 滚轮滚动
e.wheelDalta 向下 -120 向上 120
DOMMouseScroll ----> firefox 只能事件绑定 滚轮滚动
e.detail 向下 3 向上 -3
键盘事件
keydown 键盘按下(按下不动会一直触发
keyup 键盘抬起
keypress 键盘按下(只支持字符键)
window事件
load 当页面加载完成以后会触发
unload 当页面解构的时候触发(刷新页面,关闭当前页面)IE浏览器兼容
scroll 页面滚动 不停的触发
resize 窗口大小发生变化 不停的触发
表单事件
input value值发生改变
blur 失去焦点
focus 获取焦点
select 输入框中文本被选中触发
change 当输入框被修改 且 失去焦点
// 必须添加到form表单元素上
submit 点击submit按钮才触发
reset 点击reset按钮才触发
event对象
早期火狐不兼容event 需要传参 ev
var ev = ev || event;
鼠标按下/单击 ----> mousedown 支持
e.button;// 0 左键 1 滚轮 2 右键
鼠标位置 ----> 鼠标事件支持
e.offsetX/Y 距离当前触发元素的left/top值
e.clientX/Y 可视区left/top值
e.pageX/Y 页面文档的top/left值
e.screenX/Y 屏幕左上角left/top值
热键 ---> keydown 支持 按下为true
e.shiftkey Boolean
e.altKey Boolean
e.ctrlKey Boolean
e.metakey windows ---> windows键
macos ---> command键
键盘按下 ---> keydown/keyup 支持
e.which/e.keycode ----> 返回按下的ascll码值,不区分大小写
enter ----> 13
shift ----> 16
ctrl ----> 17
alt ----> 18
a ----> 65
上下左右----> 37 38 39 40
键盘按下 ----> keypress 仅支持字符键(DOM3 被弃用)
e.which/e.charCode ---> 返回按下的ascll码值,区分大小写
滚动
e.wheelDelta ---> chrome IE 向下 -120 向上 120
e.datail ---> firefox 向下 3 向上 -3
兼容:
e.wheelDalta ? e.wheelDalta < 0 : e.datail > 0 ;
//chrome是否存在 ? chrome < 0 是否向下为true : firefox < 0 是否向下
阻止冒泡
e.cancalBubble = true; ----> IE8- chrome
e.stopPropagation() ----> firefox chrome
兼容:
e.stopPropagation ? e.stopPropagation() : e.cancalBubble = true;
阻止默认行为
普通函数 ----> return false
addEventListener ----> e.preventDefault() chrome
attachEvent ----> e.returnValue = false IE
e.preventDefault ? e.preventDefault() : e.returnValue = false;
事件委托
e.target ----> chrome
e.srcElement ----> IE8-
兼容:
e.target || e.srcElement
阻止IE选择事件
onmousedown ----> setCapture()设置捕获
onkeydown ----> releaseCapture()释放捕获
事件监听
绑定事件
addEventListener('click',fn,false) ----> chrome
事件(不带on),函数
默认 false 冒泡触发,true 捕捉阶段触发
attachEvent("onclick",fn) ----> IE
事件(带on),函数
解绑事件
removeEventListener(oEvent,fn); ----> chrome
detachEvent(oEvent,fn); ----> IE
区别:
事件 ----> chrome 不带on IE 带on
函数执行顺序 ----> chrome 顺序执行 IE 逆序执行
是否支持捕捉触发 ----> chrome 支持 IE 只支持冒泡
this 指向 ----> chrome 调用对象 IE window对象
兼容
el.addEventListener ? el.addEventListener(event,fn,false) : el.attachEvent('on' + event,fn);
el.removeEventListener ? el.removeEventListener(event,fn) : el.detachEvent('on' + event,fn);
UI事件
属性/方法 类型 说明
bubbles Boolean 事件是否冒泡
stopPropagation() Function 取消捕捉/冒泡,bubbles为true,可以使用 ----> Firefox chrome
cancelable Boolean 取消默认行为 ---> IE8 chrome
preventDefault() Function 取消默认行为。cancelable为true,可以使用 ----> Firefox chrome
currentTarget Element 全等 === this
defaultPrevented Boolean 是否调用 ---> preventDefalt()
detail integer 滚动滚轮相关信息 ----> Firefox
eventPhase integer 调用事件处理程序阶段:1表示捕捉阶段 2表示处于目标 3表示冒泡阶段
stopImmediatePropagation() Function 取消捕捉/冒泡,同时阻止任何事件处理程序被调用
target Element 当前触发的元素
trusted Boolean 为true表示事件是浏览器生成的,false表示js生成写的
type String 被触发事件的类型
view AbstractView 与事件关联的抽象视图。等同于发生事件的window对象
动画
拖拽效果
拖拽效果
鼠标按下 onmousedown 里边 鼠标移动onmousemove 鼠标释放onmouseup
var oDiv = document.getElementById('box');
var disX = disY = 0;
oDiv.onmousedown = function(ev){
var ev = ev || event;
disX = ev.offsetX;
disY = ev.offsetY;
document.onmousemove = function(ev){
var ev = ev || event;
var l = ev.clientX - disX;
var t = ev.clientY - disY;
// 边界限定
if(l <= 0){
l = 0;
}else if(l >= document.documentElement.clientWidth - oDiv.offsetWidth){
l = document.documentElement.clientWidth - oDiv.offsetWidth;
}
if(t <= 0){
t = 0;
}else if(t >= document.documentElement.clientHeight - oDiv.offsetHeight){
t = document.documentElement.clientHeight - oDiv.offsetHeight;
}
// 吸附效果
// if(l <= 100){
// l = 0;
// }else if(l >= document.documentElement.clientWidth - oDiv.offsetWidth - 100){
// l = document.documentElement.clientWidth - oDiv.offsetWidth;
// }
// if(t <= 0){
// t = 0;
// }else if(t >= document.documentElement.clientHeight - oDiv.offsetHeight){
// t = document.documentElement.clientHeight - oDiv.offsetHeight;
// }
oDiv.style.left = l + 'px';
oDiv.style.top = t + 'px';
}
document.onmouseup = function(){
this.onmousemove = null;
this.onmouseup = null;
}
}
碰撞检测
function konck(node1,node2){
var l1 = node1.offsetLeft;
var r1 = node1.offsetLeft + node1.offsetWidth;
var t1 = node1.offsetTop;
var b1 = node1.offsetTop + node1.offsetHeight;
var l2 = node2.offsetLeft;
var r2 = node2.offsetLeft + node2.offsetWidth;
var t2 = node2.offsetTop;
var b2 = node2.offsetTop + node2.offsetHeight;
if(l2 > r1 || r2 < l1 || t1 > b2 || t2 > b1){
return false;
}else{
return true;
}
}
链式运动
缓动运动框架
每次的步长 = (总路程 - 当前位置) / 运动系数(6-10)
function getStyle(el, attr){
return el.currentStyle ? el.currentStyle[attr] : getComputedStyle(el)[attr];
}
function bufferMove(el, obj, fn){//fn就是回调函数
clearInterval(el.timer);
el.timer = setInterval(function(){
var flag = true;//判断是否所有属性都到达目标值 如果有一个属性没有到目标值 就将flag设置为false 如果全部都到了目标值 那么flag就不会被改变为false 就是初始true
for(var attr in obj){
// 判断 attr是不是opacity 是 采用一种获取办法 不是 采用之前的获取方法
if(attr == 'opacity'){
var cur = Math.round(getStyle(el, attr) * 100);
}else{
var cur = parseInt(getStyle(el, attr));
}
var step = (obj[attr] - cur) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
// if(cur == obj[attr]){
// clearInterval(el.timer);
// }
if(cur != obj[attr]){//如果有一个当前值 不等于目标值 说明没有全部执行完成
flag = false;
}
// 赋值时也分两种情况 一种是透明度 另一种是带有单位px的
if(attr == 'opacity'){
el.style.opacity = (cur + step) / 100;
el.style.filter = 'alpha(opacity=' + (cur + step) + ')';
}else{
el.style[attr] = cur + step + 'px';
}
}
if(flag){//如果flag为假 说明没有全部属性达到目标值 那么不清除定时器 如果flag为true说明全部属性都达到了目标值 就清除定时器
clearInterval(el.timer);
// fn && fn();
// 回调函数的this指向window 当该运动框架适用于元素集合时 this执行导致报错
// if(fn) fn();
// 改 call就是修改函数的调用时的this指向
if(fn) fn.call(el);
}
},20)
}
ajax
readyState
open 之前是 0
send 发送请求之后是 1
send 方法完成,已经接受到所有的响应内容 2
正在解析下载到的数据 3
解析完成 4
State HTTP状态码
200——交易成功
400——错误请求,如语法错误
404——没有发现文件、查询或URl
1**:请求收到,继续处理
2**:操作成功收到,分析、接受
3**:完成此请求必须进一步处理
4**:请求包含一个错误语法或不能完成
5**:服务器执行一个完全有效请求失败
json对象
JSON.parse() // josn字符串 => 数据结构
JSON.stringify() // 数据结构 => 字符串
eval() ---> 将具有js格式的字符串 转换为js执行,可以转换除了json以外的任意js字符串
数组深拷贝
var obj={name:"rypy",age:20};
var obj1=JSON.parse(JSON.stringify(obj));
obj1.name="rypy1";
console.log(obj); // {name: "rypy", age: 20}
console.log(obj1); // {name: "rypy1", age: 20}
php
echo json_decode($arr);// josn字符串 => 数据结构
echo json_encode($arr);// 数据结构 => 字符串
封装
function ajax(setting){
var ajax = new XMLHttpRequest();
// 默认 set
if(!setting.method) setting.method = 'get';
// 组合data查询数据
if(setting.data){
setting.data = getSearch(setting.data);
}else{
setting.data = '';
}
if(setting.method.toLowerCase() == 'get'){
ajax.open('get',setting.url + '?' + setting.data,true);
ajax.send();
}else if(setting.method.toLowerCase() == 'post'){
ajax.open('post',setting.url,true);
ajax.setRequestHeader('Content-type','appliction/x-www-form-urlencoded');
ajax.send(setting.data);
}
ajax.onreadystatechange = function(){
if(ajax.readyState == 4){
if(ajax.status == 200){
setting.success(ajax.responseText);
}else{
console.log('Error:' + ajax.status);
}
}
}
}
// 拼接字符串
function getSearch(obj){
var str = '';
for(var key in obj){
str += key + '=' + obj[key] + '&';
}
return str.slice(0,str.length-1);
}
表单脚本
对象属性/方法
acceptCharset:服务器能够处理的字符集;等价于HTML中的accept-charset
action: 接受请求的URL;等价于HTML中的action特性
elements: 表单中所有控件(HTMLCollection)
enctype: 请求编码类型
length: 表单中控件的数量
method: 要发生的HTTP请求类型,通常是get、post
name: 表单名称
target: 用于发送请求和接收响应的窗口名称
reset(): 讲所有表单域重置为默认值
submit(): 提交表单
<form action="" novalidate></form>
novalidate = true;//禁用验证
获取元素
document.forms[0];//获取页面中的第一个表单
document.forms['username'];//获取页面中的name为username
form.pass; // 获取表单中name属性为pass
form.elements[0];//取得表单中第一个字段
form.elements.['textbox1'];//取得name为textbox1的字段
form.elements.length;//取得表单包含字段的数量
事件
事件也对应的有方法,form.submit()为提交
表单事件
input value值发生改变
IE: onpropertychange value值改变时
blur 失去焦点
focus 获取焦点
select 输入框中文本被选中触发
change 当输入框被修改 且 失去焦点
// 必须添加到form表单元素上
submit 点击submit按钮才触发
reset 点击reset按钮才触发
字段属性
共有字段属性
disabled: 布尔值,表示当前字段是否被禁用
form: 指向当前字段所在的表单;只读
name: 当前字段名称
readOnly: 布尔值,表示当前字段是否只读
tabIndex: 表示当前字段tab序号
type: 当前字段类型
value: 当前字段将被提交给服务器的值
选中文本
inp.select(); //选中文本框中的所有文字
function getSelectedText(text){
if(typeof text.selectionStart == 'number'){
// 选择文字的起始,结束下标
return text.value.substring(text.selectionStart,text.selectionEnd);
}else if(document.selecttion){//IE 取得IE中的选择文本代码 调用document.selecttion 不需要考虑text参数
return document.selecttion.createRang().text;
}
}
输入检测
// 检测浏览器是否支持pattern属性
var isPatternSupported = 'pattern' in document.createElement('input');
input.stepUp(); // 加1
input.stepUp(5); // 加5
input.stepDown(); // 减1
input.stepDown(5); // 减5
// 检测有效性
if(document.forms[0].checkValidity()){
// 整个表单有效,返回true。 也可以单独input调用这个方法
}
customError:如果设置了 setCustomValidity(),则为true,否则返回false
patternMismatch:如果值与指定的pattern属性不匹配,返回true
reangeOverflow:如果值比max值大,返回true
rangeUnderflow:如果值比min值小,返回true
stepMisMatch:如果min和max直接的步长值不合理,返回true
tooLong:值的长度超过了maxlenght属性指定的长度,返回true。火狐会自动约束字符数量,所以会永远返回true
typeMismatch:如果值不是'mail'或'url'要求的格式,返回true
valid:如果这里的属性都是false,返回true。checkValidity()也要求相同的值
valueMissing:如果标注为required的字段中没有值,返回true
选择框脚本
add(new option, relOption):向控件中插入行的<option>
multiple:布尔值,是否允许多选
options:控件中所有<option>元素的HTMLCollection
remove(index):移除给定位置的选项
selectedIndex:选中的索引,从0开始,没有则是-1
size:选择框可见的行数
每个<option>都有一个HTMLOptionElement对象
index:当前选项在option集合中的索引
label:当前选择的标签;等价于html中label的特性
selected:布尔值,表示当前选项是否被选中,设为true可以选中当前选项
text:选项的文本
value:选项的值
本地存储技术
localStorage(IE8以下不兼容
永久存储
最大存储5M 客户端的微型数据库
只能存储string
cookie
可以设置过期时间
最大存4KB
每一个域名下面最多可以存储50调数据
sessionStorage (结合后台使用、关闭窗口,存储的数据清空
localStorage 对象
// 设置键 值
localStorage.setItem("key","value");// 设置键,值(必须json字符串)
localStorage.key="value";
// 获取对应键值
变量=localStorage.getItem("key");
变量=localStorage.key;
// 删除键值
localStorage.removeItem(name); // 删除对应键
localstorage.clear(); // 清除所有
sessionStorage 对象
// 设置键 值
sessionStorage.setItem("key","value");
sessionStorage.key="value";
// 获取对应键值
变量=sessionStorage.getItem("key");
变量=sessionStorage.key;
// 删除键值
sessionStorage.removeItem(name); // 删除对应键
sessionStorage.clear()
cookie
格式: name=value;[expires=date];[path=path];[domain=somewhere.com];[secure],
键 = 值; 后续中括号的内容,都是可选项。
火狐支持缓存cookie,谷歌只支持服务器缓存cookie
[expires=date]
'expires=过期时间'
[path=path]
【注】我们设置的cookie的路径,和加载当前文件的路径,必须一致,如果不一致,cookie访问失败。
'username=xxx;path=' + '/code14/cookie'; //可以访问当前与html同一路径
'username=xxx;path=' + '/code14/cookie/111';//设置其他路径后 不能访问
如果不设置,默认是加载当前.html文件的路径
[domain=somewhere.com]
domain 限制访问域名
如果不去设置,默认是加载当前.html文件的服务器域名/ip
【注】如果加载当前文件域名和设置的域名不一致,设置cookie失败。不能设置
document.cookie = 'username=xxx;domain=' + 'localhostxxx'; 设置失败
secure
如果不设置,设置cookie,可以通过http/https协议加载文件设置
【注】设置字段后,只能https协议加载cookie.
document.cookie = 'username=xxx;secure'
//获取cookie
alert(document.cookie);
//设置cookie
document.cookie = 'username=xxx';
转码储存
encodeURIComponent() 将中文编译成对应的字符
decodeURIComponent() 将对应的字符编译成中文
document.cookie = 'username=' + encodeURIComponent("钢铁侠");
转码获取
decodeURIComponent(document.cookie)
删除cookie
document.cookie = "username=;expires=" + new Date(0);
setCookie
function setCookie(name,value,{expires,path,domain,secure}){
var str = encodeURIComponent(name) + "=" + encodeURIComponent(value);
if(expires){
str += ";expires=" + afterOfDate(expires);
}
if(path){
str += ";path=" + path;
}
if(domain){
str += ";domain=" + domain;
}
if(secure){
str += ";secure";
}
document.cookie = str;
}
// 获取n天后的时间
function afterOfDate(n){
var date = new Date();
var day = date.getDate();
date.setDate(n + day);
return date;
}
getCookie
// n121=sa; 名字=name; 名字2=2name
function getCookie(name){
var cookieStr = decodeURIComponent(document.cookie);
var strat = cookieStr.indexOf(" " + name + "=");
if(strat == "-1"){
return null;
}else{
var end = cookieStr.indexOf(";",strat);
if(end == "-1"){
end = cookieStr.length;
}
var str = cookieStr.substring(strat,end);
return str.split("=")[1];
}
}
alert(getCookie("名字2"))
removeCookie
function removeCookie(name){
document.cookie = encodeURIComponent(name) + "=;expires=" + new Date(0);
}
封装
/*
$cookie()
一个参数 获取
两个参数或以上 设置
两个参数,参数二 null 删除
*/
function $cookie(){
switch (arguments.length){
case 1 :
return getCookie(arguments[0]);
case 2 :
if(arguments[1] == null){
removeCookie(arguments[0]);
}else{
setCookie(arguments[0],arguments[1],{});
}
break;
default:
setCookie(arguments[0],arguments[1],arguments[3]);
break;
}
}
function setCookie(name,value,{expires,path,domain,secure}){
var cookieStr = encodeURIComponent(name) + "=" + encodeURIComponent(value);
if(expires){
cookieStr += ";expires=" + afterOfDate(expires);
}
if(path){
cookieStr += ";path=" + path;
}
if(domain){
cookieStr += ";domain=" + domain;
}
if(secure){
cookieStr += ";secure";
}
document.cookie = cookieStr;
}
// 获取n天后的时间
function afterOfDate(n){
var date = new Date();
var day = date.getDate();
date.setDate(n + day);
return date;
}
function getCookie(name){
var cookieStr = decodeURIComponent(document.cookie);
var start = cookieStr.indexOf(name + "=");
if(start == -1){
return null;
}else{
var end = cookieStr.indexOf(";",start);
if(end == -1){
end = cookieStr.length;
}
var str = cookieStr.substring(start,end);
var value = str.split("=")[1];
return value;
}
}
function removeCookie(name){
document.cookie = encodeURIComponent(name) + "=;expires=" + new Date(0);
}
媒体API
audio
标签相关属性
src 要播放的音频/视频的URL。
controls 显示音频/视频播放控件
loop 音频/视频结束后重新播放
muted 音频/视频静音
只读属性
duration 文件的播放时长,单位s,无法获取则NaN,当触发canplay事件后可以获取
paused 是否暂停,返回 true/false
ended 是否播放完毕 true/false
error 发现错误后返回错误代码
currentSrc 返回字符串形式正在播放或已加载文件,对应浏览器source元素中选择的文件
buffered 获取当前缓冲区大小,返回TimeRanges对象
可控制属性
src 指定音频文件位置
autoplay 是否自动播放
preload 是否预加载
loop 是否循环播放
controls 显示/隐藏用户控制界面
muted 设置是否静音
volume 当前音量值,0-1之间
currentTime 返回/设置当前播放的时间,单位s
方法
load() 加载视频、音频软件
play() 播放
pause() 暂停
canPlayType(obj) 测试播放后指定的Mime类型文件
事件
loadstart 客户端开始请求数据
progress 正在播放的时候不停触发,暂停不会触发,触发事件间隔较大
play play()和autoplay时触发,类似onplaying
pause pause()方法时触发
ended 结束播放时触发
timeupdate 播放时间发生改变时触发,暂停不触发,触发事件间隔较小
canplaythrough 歌曲载入完成
canplay 缓存至可播放状态,类似事件onloadedmetadata
onloadedmetadata 当元数据(如分辨率和时长)被加载时触发
video
标签属性
src 要播放的音频/视频的URL。
controls 显示音频/视频播放控件
loop 音频/视频结束后重新播放
muted 音频/视频静音
width 播放区宽度
height 播放区高度
poster 预览图片
属性
audioTracks 返回可用音频轨道的Audio TrackList对象
autoplay 设置/返回是否在加载完成后播放视频/音频
buffered 返回音频/视频已缓存部分的timeRanges对象
controller 返回音频/视频当前媒体控制器的MediaController对象
controls 设置/返回音频/视频是否显示控件
crossOrigin 设置/返回音频/视频的CORS设置
curretSrc 返回当前音频/视频的URL
currentTime 设置/返回音频/视频中当前播放位置(以秒
defaultMuted 设置/返回音频/视频默认是否静音
defaultPlaybackRate 设置/返回音频/视频的默认播放速度
duration 返回当前音频/视频的长度s
ended 返回音频/视频是否播放结束
error 返回音频/视频发生错误状态的MediaError对象
loop 设置/返回是否应在结束时重新播放
mediaGroup 设置/返回音频/视频所属的组合
muted 设置/返回是否静音
networkState 返回当前音频/视频网络状态
paused 设置/返回是否暂停
playbackRate 设置/返回音频/视频播放速度
palyed 返回音频/视频已播放部分TimeRanges对象
repload 设置/返回是否在页面加载后加载
readyState 返回音频/视频当前的就绪状态
seekable 返回音频/视频可寻址部分的TimeRanges对象
seeking 返回用户是否在音频/视频中进行查找
src 设置/返回当前来源
startDate 返回当前时间偏移的date对象
textTracks 返回可用文本轨道的TextTrackList对象
videoTracks 返回可用视频轨道的VideoTrackList对象
volume 设置/返回音量
方法
addTextTrack() 向音频/视频添加新的文本轨道
canPlayType() 检测浏览器是够能播放指定的音频/视频类型
load() 重新加载音频/视频
play() 开始播放音频/视频
pause() 暂停音频/视频
事件
abort 当音频/视频的加载已放弃时触发
canplay 当浏览器可以开始播放音频/视频时触发
canplaythrough 当浏览器在不因缓冲而停顿的视口下进行播放时触发
durationchange 音频/视频的时长发生改变时触发
emptied 目前播放列表为空时触发
ended 播放列表结束时触发
error 音频/视频加载期间发生错误时触发
loadeddata 当音频/视频已加载当前帧时触发
loadedmetadata 当浏览器已加载音频/视频的元数据时触发
loadstart 当浏览器开始查找音频/视频时触发
pause 音频/视频暂停时触发
play 音频/视频一开始或不在暂停时触发
playing 音频/视频因缓冲而暂停或停止后已就绪时触发
progress 当浏览器正在下载音频/视频时触发
ratechange 音频/视频的播放速度已更改时触发
seeked 用户开始移动/跳跃到音频/视频新的位置时触发
seeking 开始移动到/跳跃到音频/视频新的位置时触发
stalled 当浏览器尝试获取媒体数据,但数据不可用时触发
suspend 浏览器刻意不获取媒体数据时触发
timeupdate 当目前播放位置已更改时触发
volumechange 当音量已更改时触发
waiting 当视频由于需要缓冲下一帧而停止时触发
touch
事件
touchstart 手指按下
touchmove 手指移动
touchend 手指抬起
PC 端事件,比移动端事件略慢,大概慢 300ms
点透问题
在 300ms 之内,如果上层元素消失或隐藏,目标就会漂移到下层元素身上,就会触发点击行为。
解决办法:下层元素不要使用有点击特性的元素
事件对象
ev不需要兼容
ev主要使用的3个属性
touches: 所有在屏幕上的手指的一个列表
targetTouches: 当前在目标元素上的手指的列表
changedTouches: 当前在目标元素上发生变化(触发当前事件)的手指的列表 最常用
clientX: 事件触发到可视区左边的距离
clientY:事件触发到可视区上边的距离
identifier: 标识符 第几个手指 0-n
pageX: 事件触发到页面的左边的距离
pageY: 事件触发到页面的上边的距离
radiusX: x轴的旋转半径
radiusY: y轴的旋转半径
rotationAngle: 旋转角度 deg
screenX: 事件触发到屏幕的左边距离
screenY: 事件触发到屏幕的上边距离
rem.js
使用方法: 设计稿得到尺寸 除以100 就是你的rem值
;(function(){
var html = document.documentElement, // 储存html
// 横屏还是竖屏
resizeEvent = 'orientationchange' in window ? 'orientationchange' : 'resize',
dW = 750; // 设计稿宽
function remCalc(){
var clientW = html.clientWidth; // 视口宽
if(!clientW) return;
if(clientW > dW){
// 如果视口宽大于dW 设计稿宽 就等于100px字体
html.style.width = dW + 'px';
html.style.fontSize = '100px';
html.style.margin = '0 auto';
}else{
// 否则,当前视口/设计稿宽*100字体大小
html.style.fontSize = clientW / dW * 100 + 'px';
}
}
if(!html.addEventListener) return;// 是否支持addEventListener方法
// 绑定视口变化事件
window.addEventListener(resizeEvent,remCalc,false);
// DOMContentLoaded ---> 类似window.onload ,但是只需要加载完成页面文档后就可以调用
docment.addEventListener('DOMContentLoaded',remCalc,false);
})()
touch.js
事件
touch.on(元素,'事件(多个事件空格隔开,支持原生事件)','回调函数')
缩放类
pinch 缩放手势
pinchstart 缩放手势起点
pinchend 缩放手势终点
pinchin 收缩
pinchout 放大
旋转类
rotate 旋转
rotateleft 向左旋转
rotateright 向右旋转
滑动类
swipe 滑动
swipestart 滑动手势起点
swiping 滑动中
swipeend 滑动手势终点
swipeleft 向左滑动
swiperight 向右滑动
swipeup 向上滑动
swipedown 向下滑动
拖动类
drag 拖动
dragstart 拖动开始
dragend 拖动结束
长按
hold
单击/双击
Tap、doubletap
事件委托
touch.on(父元素,'事件(多个事件空格隔开,支持原生事件)','子元素css选择器','回调函数')
this指向当前触发的节点
事件对象
touch.on(div,'doubletap',function(e){
e.originEvent;// 返回触发某事件的原生对象
e.type; //事件的名称
e.rotation; //旋转角度(旋转事件下)
e.scale; //缩放比例(缩放事件、0.5 缩小一半 2 放大2倍)
e.direction; //操作方向属性、滑动的方向
e.fingersCount; //操作手势的数量
e.position; //相关位置信息,不同操作产生不同的位置信息
e.distance; //swipe类两点之间的位移
e.distanceX; //滑动x轴的距离,向左移动时为负数
e.distanceY; //滑动y轴的距离,向上移动时为负数
e.angle; //rotate事件触发是旋转的角度
e.duration; //touchstart与touchend值的时间戳
e.startRotate()//方法 旋转的方法
/* 不同的事件事件对象的信息不同,点击事件没有旋转角度等 */
})
ES6
let和const
1、遇到{}就形成作用域
2、同一作用域不能重复声明变量或函数 [如:let声明过不能用const和var声明相同名字]
3、没有变量提升
4、const 必须初始化赋值,不能被修改,而let声明的变量不用
5、const 定义的对象或者数组,其实是可变的。
1、可以修改添加属性
const car = {color:"white"};
car.color = "red";// 修改属性:
car.owner = "Johnson";// 添加属性
2、不能赋值
const car = {};
car = {}; // 错误
数组同理
6、全局作用域 var 属于window对象。let不属于window对象。
7、let 有暂时性死区、要先声明再使用。
解构
[模式] = [数组];
[模式] = {对象};
完全解构
不完全解构[,可以被忽略 为赋值成功为undefined ]
嵌套
默认值 , undefined 不会被赋值,null 可以被赋值
数组解构
let [, [x, y], m = 88,...z] = [2, [3, 4], undefined,1,2]; //m为88
1、, 会忽略
2、[]可以嵌套
3、undefined 不会赋值上去, m = 88 默认值; null 会被赋值
4、...z剩余运算符 收集对象/数组/值 或 展开数组/对象/值
let [x,...arr] = [1,2,3]; // arr = [2,3]
let {a,...obj} = {a : 'aa', b : "bb" , "c" : "cc"};//obj = {b : "bb" , "c" : "cc"}
字符串
let [a, b, c] = 'hel';
// 'h' 'e' 'l'
对象
// 剩余运算符
let {a, ...obj} = {a: 10, c: 30, d: 40};
// 10,{c: 30, d: 40}
// 解构默认值
let {a = 10, b = 5} = {a: 3};
// a = 3; b = 5;
运用
//交换值
var [x,y] = [10,20];
[x,y] = [y,x];
//函数可以返回多个值
var [x,y,z] = show();
function show(){
return ["结果1","结果2","结果3"]
}
// 设置默认值,可以改变传入参数的顺序
function showSelf({name,age = 18}){// 可以
console.log(`我叫${name}今年${age}`); // 我叫aa 今年18
}
showSelf({name: "aa"})
// 取出数组中的值
var arr = [10,20,30];
var {0:first,3:last} = arr; //first等于10 last是30
object
简写
对象简写
const age = 12;
const name = "Amy";
const person = {age, name}; //{age: 12, name: "Amy"}
//等同于 person = {age: age, name: name}
方法简写
const person = {
sayHi(){
console.log("Hi");
}
}
Generator 函数,要在前面加星号
const obj = {
* myGenerator() {
yield 'hello world';
}
};
属性名表达式[变量]
let a="aaa";
let obj={
[a]:"bbb"
}
const obj = {
["he"+"llo"](){
return "Hi";
}
}
obj.hello(); //"Hi"
合并对象
let age = {age: 15};
let name = {name: "Amy"};
let person = {...age, ...name}; //{age: 15, name: "Amy"}
注意,如果两个对象有同名的属性会被覆盖(数组也是同理)
Object.assign()
Object.assign(target, source_1, ···)
将后面所有可枚举的属性赋值到target对象中。重复的值会覆盖
let target = {a: 1};
let object2 = {b: 2};
let object3 = {c: 3};
Object.assign(target,object2,object3); // {a: 1, b: 2, c: 3}
// 第一个参数是目标对象,后面的参数是源对象
只有一个参数不是对象,也会转换为对象返回
Object.assign(3); // Number {3}
第一个参数时 null 或 undefined 会报错
Object.assign(null); // TypeError: Cannot ...
null 和 undefined 放第二个之后会跳过
Object.assign(1,undefined); // Number {1}
//注意: assign 的属性拷贝是浅拷贝
let sourceObj = { a: { b: 1}};
let targetObj = {c: 3};
Object.assign(targetObj, sourceObj);
targetObj.a.b = 2; // 原始值修改
sourceObj.a.b; // 2 已经拷贝的值也会跟着变
同名属性会被替换
targetObj = { a: { b: 1, c:2}};
sourceObj = { a: { b: "hh"}};
Object.assign(targetObj, sourceObj);// {a: {b: "hh"}}
数组的处理
Object.assign([2,3], [5]); // [5,3] 下标0被覆盖
Symbol
声明
1、原始数据类型,不能使用new
2、括号内是备注的意思,独一无二的值,两个Symbol不相等
3、typeof检测为Symbol
4、作为对象的键名独一无二、使用[]设置/获取,不能用.运算符获取设置
5、作为对象属性名是,是共有属性,不是私有属性,可以在类的外部访问
6、不能被枚举 for in/for of 、Object.keys() Object.getOwnPropertyNames() 返回
7、可以被 Object.getOwnPropertySymbols() 和 Reflect.ownKeys() 取到
let sy = Symbol('name');//不能用 new 命令,参数是备注
Symbol("KK") == Symbol("KK") // false
typeof Symbol("KK"); // 'symbol'
作为属性名
var obj = {};
// 设置symbol属性
obj[sy] = 'kk';
// 获取
obj.sy // undefined 不能使用.运算符获取
obj[sy] // kk
Symbol.for()
var sy = Symbol('a');
console.log(Symbol.for('a'));; // Symbol(a)
1、全局搜索是否存在该名称
2、有 返回本身,没有 新建一个返回
3、使两个Symbol类型的变量相等,生成同一个Hash值
Symbol("Yellow") === Symbol.for("Yellow"); // false
Symbol.for("Yellow") === Symbol.for("Yellow"); // true
Symbol.keyFor(sym)
1、查找键值的某个 Symbol
2、找到返回该symbol的key值,字符串类型。否则undefined
// 创建一个全局 Symbol
var globalSym = Symbol.for("foo");
Symbol.keyFor(globalSym); // "foo"
var localSym = Symbol();
Symbol.keyFor(localSym); // undefined,
// 以下Symbol不是保存在全局Symbol注册表中
Symbol.keyFor(Symbol.iterator) // undefined
Map与Set
Map对象
方法
set()、get()、delete()、has()、clear()、size
set,get键值对
var myMap = new Map();
key是字符串
myMap.set('键', "和键关联的值"); // 设置 键值对
myMap.get('键'); // "和键关联的值" 获取值
key是对象
var myMap = new Map();
var keyObj = {}
myMap.set(keyObj, "和键 keyObj 关联的值");
myMap.get(keyObj); // "和键 keyObj 关联的值"
myMap.get({}); // undefined, 因为 keyObj !== {}
key是函数时也与key是对象同理
key 是 NaN ,NaN 作为 Map 的键没有区别。
var myMap = new Map();
myMap.set(NaN, "not a number");
myMap.get(NaN); // "not a number"
myMap.get(Number("无法转换")); // "not a number"
Map 的迭代 遍历
var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
for...of
for (var [key, value] of myMap) {
console.log(key + " = " + value);
}
/* 打印两次
"0 = zero"
"1 = one"
*/
myMap.entries() // MapIterator {0 => "zero", 1 => "one"}
for (var [key, value] of myMap.entries()) {
console.log(key + " = " + value);
}
// entries() 方法返回 Iterator 对象,它按set插入键值对顺序包含 Map 对象中每个元素的 [key, value] 数组。
myMap.keys(); // MapIterator {0, 1} 返回键
for (var key of myMap.keys()) {
console.log(key); // 打印 0 和 1
}
// keys()返回 Iterator 对象,按插入顺序包含 Map 对象每个元素的键
myMap.values(); // MapIterator {"zero", "one"}
for (var value of myMap.values()) {
console.log(value); // 一个是 "zero" 另一个是 "one"
}
/* values() 返回 Iterator 对象,按插入顺序包含 Map 对象每个元素的值。 */
forEach
myMap.forEach(function(value, key) {
console.log(key + " = " + value);
// 一个是 "0 = zero" 另一个是 "1 = one"
}, myMap)
对象操作
转换
var kvArray = [["key1", "value1"], ["key2", "value2"]];
// 可以将 二维 键值对数组转换 Map 对象
var myMap = new Map(kvArray); //{"key1" => "value1", "key2" => "value2"}
// Array.from 函数将 Map 对象转回去
var outArray = Array.from(myMap); //[["key1", "value1"], ["key2", "value2"]]
克隆
var myMap1 = new Map([["key1", "value1"], ["key2", "value2"]]);
var myMap2 = new Map(myMap1);
/* {"key1" => "value1", "key2" => "value2"} */
console.log(myMap1 === myMap2); // false 新地址
合并
var first = new Map([[1, 'one'], [2, 'two'], [3, 'three'],]);
var second = new Map([[1, 'uno'], [2, 'dos']]);
// 合并两个 Map 对象时,有重复的键值,则后面的会覆盖前面的,对应值即 uno,dos, three
var merged = new Map([...first, ...second]); // 解构传参
console.log(merged); //{1 => "uno", 2 => "dos", 3 => "three"}
Set对象
原型方法
add()、delete()、has()、clear()、 size
Set 对象允许存储任何类型的唯一值,原始值或引用值都可。
特殊值
+0 与 -0 在存储判断唯一性的时候是恒等的,所以不重复;
undefined 与 undefined 是恒等的,所以不重复;
NaN 与 NaN 是不恒等的,但是在 Set 中只能存一个,不重复。
创建
let mySet = new Set();
mySet.add(5); // Set(1) {5}
mySet.add(5); // Set(1) {5} 值的唯一性
mySet.add({a: 1, b: 2});
mySet.add({a: 1, b: 2});
// Set(5) {1, {…}, {…}}
// 对象之间引用不同不恒等,即使值相同,Set 也能存储
转换
// Array 转 Set
var mySet = new Set(["value1", "value2", "value3"]);// {"value1", "value2", "value3"}
// 用...操作符,将 Set 转 Array
var myArray = [...mySet];// ["value1", "value2", "value3"]
// String
// String 转 Set
var mySet = new Set('hello'); // Set(4) {"h", "e", "l", "o"}
// 注:Set 中 toString 方法是不能将 Set 转换成 String
数组去重
var mySet = new Set([1, 2, 3, 4, 4]);
[...mySet]; // [1, 2, 3, 4]
并集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var union = new Set([...a, ...b]); // {1, 2, 3, 4}
/* 解构传入,唯一值,相当于去重 */
交集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
Set.has(x) 是 set 中的一个方法。
判断当前set对象 中是否含有x,返回true/false。var intersect = new Set([...a].filter(x => b.has(x))); // {2, 3}
[...a]解构成数组.filter过滤
传入x,返回set对象 b中是否存在x
存在返回true,不存在返回false被过滤掉
差集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var difference = new Set([...a].filter(x => !b.has(x))); // {1}
// 与交集同理
Proxy
let proxy = new Proxy(target, handler)
target 即目标对象,handler 是一个对象,代理 target 的指定行为
let target = {
name: 'Tom',
age: 24
}
let handler = {
get: function(target, key) { // 获取target的值会触发次函数
console.log('getting '+key);
return target[key]; // 不是target.key
},
set: function(target, key, value) {// 设置target的值会触发次函数
console.log('setting '+key);
target[key] = value;
}
}
字符串
识别查找
// 传入正则会抛出错误
includes() // 返回布尔值,判断是否找到参数字符串。
startsWith() // 返回布尔值,判断参数字符串是否在原字符串的头部。
endsWith() // 返回布尔值,判断参数字符串是否在原字符串的尾部。
let string = "apple,banana,orange";
string.includes("banana"); // true
string.startsWith("apple"); // true
string.endsWith("apple"); // false
string.startsWith("banana",6) // true
repeat()
repeat():返回新字符串,将字符串重复指定次数返回。
"Hello,".repeat(2); // "Hello,Hello,"
"Hello,".repeat(3.2); // "Hello,Hello,Hello," 向下取整
0 至 -1 之间的小数,取整得到 -0 ,等同于 repeat 零次
NaN,等同于 repeat 零次
负数或者 Infinity ,会报错:
"Hello,".repeat(-0.5); // ""
"Hello,".repeat(NaN); // ""
传入字符串会隐式转换数字
"Hello,".repeat("hh"); // ""
"Hello,".repeat("2"); // "Hello,Hello,"
字符串补全
padStart:返回新的字符串,从头部(左侧)补全。
padEnd:返回新的字符串,从尾部(右侧)补全。
"123".padStart(10,"0"); // "0000000123" 常用于补全位数
"h".padStart(5,"o"); // "ooooh"
"h".padEnd(5,"o"); // "hoooo"
"h".padStart(5); // " h" 没有第二个参数默认空格
"hello".padStart(5,"A"); // "hello" 小于或等于返回原字符
"hello".padEnd(10,",world!"); // "hello,worl" 截去超出位数
数组
Array.of()
将参数中所有值作为元素形成数组。
Array.of(1, '2', true); // [1, '2', true]
没有参数返回空数组
Array.from()
将类数组对象或可迭代对象转化为数组。
Array.from([1, 2]); // [1, 2]
Array.from([1, , 3]); // [1, undefined, 3]
转换类数组
let arr = Array.from({
0: '1',
1: '2',
2: 3,
length: 3 // 必须有length属性,没有则返回空数组
});// ['1', '2', 3]
// 属性名无法转换为数值,返回长度为 length 元素值为 undefined 的数组
let array1 = Array.from({
a: 1, // 下标 a,b 不能转换为 0 1
b: 2,
length: 2
});// [undefined, undefined]
转换 map
let map = new Map();
map.set('key0', 'value0');
map.set('key1', 'value1');
Array.from(map); // [['key0', 'value0'],['key1','value1']]
转换set
let set = new Set([1, 2, 3]);
Array.from(set); // [1, 2, 3]
转换字符串
Array.from('abc'); // ["a", "b", "c"]
方法
find()查找
则返回符合条件的第一个元素。
let arr = Array.of(1, 2, 3, 4);
arr.find(item => item > 2); // 3
findIndex()查找索引
则返回符合条件的第一个元素的索引。
let arr = Array.of(1, 2, 1, 3);
// 参数1:回调函数
// 参数2(可选):指定回调函数中的 this 值
arr.findIndex(item => item = 1); // 0
fill()填充
let arr = Array.of(1, 2, 3, 4);
// 参数1:用来填充的值
// 参数2:被填充的起始索引
// 参数3(可选):被填充的结束索引,默认为数组末尾
console.log(arr.fill('填充',1,2)); // [1, '填充', 3, 4]
copyWithin()覆盖
var arr = ["a","b","c","d","e","f","g"]
arr.copyWithin(2,4,6)//["a", "b", "e", "f", "g", "f", "g"]
// 1、开始覆盖的位置索引
2、复制起始位置
3、(可选)复制结束位置,默认为结尾
entries()遍历
// 遍历键值对。
for(let [key, value] of ['a', 'b'].entries()){
console.log(key, value);
}
// 0 "a"
// 1 "b"
不使用 for... of 循环
let entries = ['a', 'b'].entries();
console.log(entries.next().value); // [0, "a"]
console.log(entries.next().value); // [1, "b"]
keys()遍历键名
for(let key of ['a', 'b'].keys()){
console.log(key);
}
// 0
// 1
values()遍历键值
for(let value of ['a', 'b'].values()){
console.log(value);
}
// "a"
// "b"
includes()查找
数组是否包含指定值
注意:Set 的 has 方法用于查找值;Map 的 has 方法用于查找键名。
// 参数1:包含的指定值
[1, 2, 3].includes(1); // true
// 参数2:可选,搜索的起始索引,默认为0
[1, 2, 3].includes(1, 2); // false
flat()嵌套数组转一维数
console.log([1 ,[2, 3]].flat()); // [1, 2, 3]
// 指定转换的嵌套层数
console.log([1, [2, [3, [4, 5]]]].flat(2)); // [1, 2, 3, [4, 5]]
// 不管嵌套多少层
console.log([1, [2, [3, [4, 5]]]].flat(Infinity)); // [1, 2, 3, 4, 5]
// 自动跳过空位
console.log([1, [2, , 3]].flat());// [1, 2, 3]
flatMap()
先遍历元素,再对数组执行 flat() 方法。
// 参数1:遍历函数,遍历函数可接受3个参数:当前元素、当前元素索引、原数组
// 参数2:指定遍历函数中 this 的指向
console.log([1, 2, 3].flatMap(n => [n * 2])); // [2, 4, 6]
函数
传参
// 默认参数
// 使用默认参数时,不能有同名形参
function fn(name,age=17){
console.log(name+","+age);
}
function f(...values){ // [1, 2]
console.log(values.length); //2
}
f(1,2); //2
箭头函数
与一般函数区别
1、先声明后使用
2、不能使用arguments,使用...rest剩余运算符解决
3、不能new当做构造函数
简写
1、只有一个形参时可以省略圆括号
2、只有一条语句,且把这条语句当做返回值时可以省略大括号
this指向
1、this指向上一层函数的this
2、箭头函数的当前调用者不能使用call,apply、bind改变this指向
不适用场景
1、对象中的方法不适用箭头函数
2、DOM绑定事件不适用箭头函数
Iterator 迭代器
核心概念:
1、迭代器是一个统一的接口,作用是使各种数据结构可被便捷的访问
2、是 Symbol.iterator 下的方法实现。提供这种接口的有 Array、String、arguments、Map、Set、Dom元素(正在进行中)。可以被for。。。of遍历
3、Array下有Symbol属性,所以arr[Symbol.iterator]()调用,返回Iterator对象,
4、iterator对象下next方法单次调用方法{value:'本次遍历的值',done:是否遍历结束,返回true/false}
const items = ["zero", "one", "two"];
const it = items[Symbol.iterator]();
it.next(); // {value: "zero", done: false}
it.next(); // {value: "one", done: false}
it.next(); // {value: "two", done: false}
it.next(); // {value: undefined, done: true}
// 正常运行
for (let item of Array.from({...})) {
console.log(item);
}
部署一个Iterator接口
obj[Symbol.iterator] = function(){
}
Promise
Promise 状态
pending(进行中) ----> fulfilled/resolved(成功)
pending(进行中) ----> rejected(失败)
只要处于fulfilled/resolved[成功]和rejected[失败],状态就不会再变。
1、创建Promise参数内的函数会立即执行,并返回Promise对象
2、两个参数代表状态,resolve成功调用,reject失败调用
const p1 = new Promise((resolve,reject) =>{
if(1){
resolve('成功');
}else{
reject('失败');
}
} );
3、返回Pormise对象调用then方法,第一个参数对象resolve成功后的回调,第二个参数对应reject失败时回调。then方法也会返回Promise对象
p1.then(value => {console.log(value)},err => {console.log(err)});
4、then方法执行成功的回调时,如果发生错误,不会被第二个参数对应reject失败时回调捕捉到。
5、then方法执行成功的回调发生错误是,链式调用catch方法可以捕捉前面then方法发生的错误
p1.then(val => {代码块有发生错误}).catch(e => {console.log(e);})
Promise.all()与Promise.race()
Promise.all([Promise对象,Promise对象...])批量执行
1、传入数组中包含多个Promise实例,也可以是别的值,all包装成一个新的Promise
2、全部都成功后,返回每个Promise成功的值 ["resolve成功值1", "resolve成功值1"]
3、任何一个失败,返回第一个失败的Promise结果
Promise.race([Promise对象,Promise对象...])
1、不管成功还是失败、哪个结果获得的快,就返回那个结果。
Generator 函数
// 执行机制
1、function后加*,函数执行后返回Iterator对象
2、返回的对象调用next方法开始执行,遇到yield关键字会停止。
3、再次调用next方法会从上一次的结束的地方继续执行,直到yield
4、yield后面的值会在next执行停止时返回
5、next传的参数会在函数内传给yield
function* fnc(){
console.log("开始");
let a = yield '返回给next'; // next没有传参 a默认undefined
console.log(a,"结束");//next传入 '结束'
return '2';
}
let f = fnc();
f.next('next传入');//{value: "返回给next", done: false}
f.next();//{value: undefined, done: true}
async 函数
1、async函数返回Promise对象,用同步流程来表达异步操作
2、虽然返回的是Promise对象,但不能在async函数中调用 resolve,reject函数
3、async可以单独使用,await只能在async函数中使用
4、调用async函数会立即执行,遇到await关键字会暂停执行,await后的指向完成后,async函数接着执行。
5、如果await后的异步需要时间,await下一行会接着执行,导致await的结果比下一行代码后得到
6、解决异步需要时间的问题,await等待的是Promise的结果。所以await后面配合Promise执行异步函数,但await不能处理Promise失败后的结果
7、解决失败结果方法一:await prm().catch(e => {}); 阅读不方便
8、解决方法二 : 在 prm()结果中不管成功还是失败,都调用resolve方法,成功传[null,数据],失败传[err];await执行后[e,d]=await prm();结构判断e是否出错
async function fn(){
let d = await 异步函数;
}
async function fn(){
await ti();// 里面异步函数2秒后执行
console.log('这里会比上面await先输出');
}
async function fn(){
var [e,d] = await prm();
console.log(d,'promise执行完后才执行这行代码');
}
function prm(){
return new Promise(resolve => {
if('成功'){
resolve([null,d]);
}else{
resolve('失败了')
}
})
}
class类
1、constructor内外都可以定义属性,前面加static为静态属性
2、类里面 方法名(){}为成员方法,加static为静态方法 constructor内 this.方法为实例方法
3、继承父类方法使用extends,子类没有constructor会默认调用父类的constructor
4、子类constructor内使用this之前必须调用 super()方法把父类的this继承下来
5、成员属性、方法、静态属性、方法也会继承下来。子类使用父类方法可以 super.方法名,也可以 this.方法
6、子类用 super.父类属性,undefined,可以使用this来获取
7、静态方法不能访问成员属性,成员方法不能访问静态属性
class Person {
name;//成员属性
static age;//静态属性
constructor(name,age){
this.name = name;
this.age = age;
}
fn(){
// 成员方法(原型上)
}
static fn1(){
// 静态方法
}
}
class Son extends Person{
constructor(name,age,sex){
super(name,age);//this之前调用super
super.fn();//调用父类方法
this.sex = sex;
}
fn(){
// 重写父类方法
}
static ff(){
super.fn1();//调用父类静态方法
}
}
不可继承常规对象。
var Father = {
// ...
}
class Child extends Father {
// ...
}
// Uncaught TypeError: Class extends value #<Object> is not a constructor or null
// 解决方案
Object.setPrototypeOf(Child.prototype, Father);
es6模块化
1、es6模块语法无法在浏览器,vscode直接运行。
2、需要安装npm包:babel 将es6语法转换成es5 。browserify后台代码编译成前端【04-Node.js.docx】
单个暴露:
export let/var 属性名=属性值
export function 方法名(){ }
批量暴露:
let/var 属性名=值
function 方法名(){}
export {属性名,属性名 as 别名,方法名}
暴露所有
export default{}
使用模块:
导入单个 对应export
import {属性名,方法名,属性名 as 别名} from '模块文件名'
引入所有 对应export default
import 名字 from 路径