第一天:
1、事件取消: 1、elem.on事件名=null; 2、elem.removeEventListener("事件名",当初添加时的回调函数);
2、this的指向: 单个元素绑定事件:this->这个元素 可用target代替 多个元素绑定事件:this->当前元素 可用target代替 定时器中的this->window 箭头函数中的this->外部对象 函数中出现了this->正在调用此函数的对象
3、其实不是自己的方法,也可以用,强制改变this的指向 call/apply:临时替换了函数中的this 语法:函数.call(借用的人,实参,...); 函数.apply(借用的人,arr); 借用相当于就是立刻调用
bind:永久替换了函数中的this
语法:var 新函数=函数.bind(指定的人,永久实参);
完成了3件事:
1、创建了一个和原函数完全相同的新函数
2、this被永久指定为了指定的人,其他人都借不走
3、甚至可以永久固定一些实参
买,是不会立刻执行的,需要自己调用
3个固定套路:
1、数组也可以获取最大值和最小值:Math.max/min.apply(Math,arr); ===> Math.max/min(...arr);
2、判断x是不是数组:Object.prototype.toString.call/apply(x)=="[object Array]"
3、类数组转为普通数组:普通数组=Array.prototype.slice.call/apply(类数组对象) ===> 普通数组=Array.from(类数组对象);
4、let、const、箭头函数
5、解构赋值: 1、类似数组的解构赋值 var [c,b,a]=[1,2,3] - return可以返回多个数据
2、类似对象的解构赋值
var {c,b=默认值,a}={a:1,b:2,c:3} - 衍生了传递实参的顺序其实无所谓了
6、模板字符串:
我的名字叫${name};
7、for(var v of arr){ v-值 } 缺陷: 1、没提供过下标,无法修改原数组 2、无法遍历hash数组,也无法遍历对象
8、Set和Map [...new Set(arr)] - 使用Set数组去重,在从Set转回Array
第二天:
1、正则表达式:规定了字符串的字符出现的规则 真实开发中:优先面向百度开发,学习正则的目的(1、看得懂可以改 2、笔试和面试) 何时使用:切割、替换(加g)、验证(前加^后加$) 如何使用: 1、最简单的正则就是原文本身:/原文/后缀 g:找全部 i:忽略大小写
2、备选字符集:[0-9]
3、预定义字符集:简化备选字符集
一位数字:\d
一位数字字母下划线:\w
一位空白字符:\s
4、量词:
有明确数量
{n,m} - 前边相邻的字符集,至少n个,最多m个
{n,} - 前边相邻的字符集,至少n个,多了不限
{n} - 前边相邻的字符集,必须n个
无明确数量
?:可有可无,最多一个
*:可有可无,多了不限
+:至少一个,多了不限
5、选择和分组:
(规则1|规则2)
6、指定匹配的位置
开头:^
结尾:$
特殊:两者同时使用,前加^后加$,代表要求用户输入的从头到尾完全匹配 - 只要是做验证就必加
7、预判:实现密码强度
/^(?![0-9A-Za-z]+$)[0-9A-Za-z\u4e00-\u9fa5]{4}$/
2、字符串支持正则的API: 1、切割:var arr=str.split(RegExp);
2、替换:
基础替换法:
str=str.replace(RegExp,"固定新内容")
高级替换法:
str=str.replace(RegExp,a=>{
return 通过判断a关键字的长度的不同,返回不同的内容;
})
格式化:
str=str.replace(RegExp,(a,...)=>{
如果正则里有分组,我们就会得到更多的形参,有几个分组,就会多出几个形参!
始终:
第2个形参保存的是第1个分组匹配到的内容
...
})
3、正则对象: 创建: 直接量:var reg=/正则表达式/后缀 构造函数:var reg=new RegExp("正则表达式","后缀");
API:
验证:var bool=reg.test(user); - 这个bool仅仅就是给出一个正确或错误的提示
4、新学的事件: 1、每个input都有一个onfocus获取焦点事件 - 提示用户 2、每个input都有一个onblur失去焦点事件 - 验证用户 3、form有一个onsubmit提交事件 - 阻止提交return false;
4、oninput - 只要内容发生了变化都会触发
第三天:
1、面向对象:三大特点:封装、继承、多态 1、封装:其实就是创建 1、直接量: var obj={ "属性名":属性值, ... "方法名":function(){}, ... }
2、预定义构造函数
var obj=new Object();//空对象
obj.属性名=属性值;
obj.方法名=function(){};
3、自定义构造函数 - 批量创建对象,创建了一个类
1、创建自定义构造函数
function h52302(name,age,hobby){
this.name=name;
this.age=age;
this.hobby=hobby;
}
2、调用自定义构造函数,创建对象
var obj=new h52302(实参,...);
4、使用:
访问:obj.属性名/方法名();
访问到不存在的:返回undefined
遍历:for in
如果对象的函数,想要使用对象自己的属性,要写为this.属性名;
this的指向:
1、单个元素绑定事件this->这个元素
2、多个元素绑定事件this->当前元素
3、定时器中this->window
4、箭头函数中this->外部对象
5、函数中的this->正在调用此函数的对象
6、构造函数中的this->正在创建的对象
2、继承:原型对象(父对象)的东西,子对象可以直接使用
作用:代码重用
如何:
1、找到原型对象(父对象):
对象名.__proto__;
构造函数名.prototype;
2、原型链:每个对象都有一个属性.__proto__,可以一层一层的找到每个人父亲,形成了一条链式结构
作用:找属性和方法的,哪怕自己没有会悄悄的向上查找,如果最顶层也没有才会报错
最顶层是Object的原型,甚至上面放着我们眼熟的API - toString,怪不得人人都可以使用
3、找到原型对象可以设置共有属性和共有方法
原型对象.属性名=属性值;
原型对象.方法名=function(){};
第四天:
面向对象: 1、*****继承具有很多很多的面试和笔试题: 1、判断是自有还是共有: 1、判断自有:obj.hasOwnProperty("属性名"); 结果结果为true,说明是自由属性,如果结果为false,有两种可能,有可能是共有,也有可能是没有
2、判断共有:
if(obj.hasOwnProperty("属性名")==false&&"属性名" in obj){//in关键字,会自动查找整条原型链上的属性,找到了结果为true,找不到结果为false
共有
}else{
没有
}
完整公式:
if(obj.hasOwnProperty("属性名")){
自有
}else{
if("属性名" in obj){
共有
}else{
没有
}
}
2、修改和删除:自有和共有
自有:
修改:obj.属性名=新属性值;
删除:delete obj.属性名;
共有:
修改:原型.属性名=新属性值;//千万不要觉得,自己能拿到,就能直接修改,这样很危险,并没有修改原型东西,而是再本地添加了一个同名属性
删除:delete 原型.属性名;//千万不要觉得,自己能拿到,就能直接删除,操作会无效
3、*如何为老IE的数组添加indexOf方法 - 这道题不是固定的,可能问如何为一类人创建某个方法
if(Array.prototype.indexOf===undefined){//老IE
Array.prototype.indexOf=function(key,starti){
starti===undefined&&(starti=0);
for(var i=starti;i<this.length;i++){
if(this[i]==key){
return i;
}
}
return -1;
}
}
var arr1=[1,2,3,4,5];
var arr2=[2,4,6,8,10];
console.log(arr1.indexOf(2));
console.log(arr2.indexOf(2));
更多案例见04和05.html
4、*如何判断x是不是一个数组:4种方式:千万别用typeof,只能检查原始类型, 不能检查引用类型,如果检查引用类型的得到的结果都是一个object
1、判断x是不是继承自Array.prototype
Array.prototype.isPrototypeOf(x);
结果为true,说明是数组,结果为false,说明不是数组
2、判断x是不是由Array这个构造函数创建
x instanceof Array;
结果为true,说明是数组,结果为false,说明不是数组
3、Array.isArray(x) - ES5新增的方法,只有数组可以这么使用
结果为true,说明是数组,结果为false,说明不是数组
4、*输出【对象的字符串】形式
在Object的原型上保存着最原始的toString()方法
原始的toString输出的形式:[object 构造函数名]
***多态:子对象觉得父对象的成员不好用,就在本地定义了一个同名函数,覆盖了父对象的成员,不严格定义:同一个函数,不同的人使用,表现出来得效果不一样,由多种形态
固定套路:
Object.prototype.toString.call/apply(x) === "[object Array]";
5、实现自定义继承:
1、两个对象之间设置继承:
子对象.__proto__=父对象
2、多个对象之间设置继承:
构造函数名.prototype=父对象;
时机:应该在开始创建对象之前就设置好继承关系
2、ES6 - class关键字:简化面向对象(封装、继承、多态) class 类名 extends 老类名{ constructor(name,speed,rl){//放在constructor里面得都是自有属性 super(name,speed);//帮你调用你继承的老类得constructor函数 this.rl=rl; }//放在constructor外面得都是共有方法 //还会继承到老类所有的API,也可以在此处添加属于自己的新的API }
var obj=new 类名(实参,...)
3、*****Function - 闭包: 作用域:2种 1、全局:随处可用,可以反复使用,缺点:容易被污染
2、函数:只能在函数调用时内部可用,不会被污染,缺点:一次性的,使用完就会释放的。
***函数的执行原理:
1、程序加载时:
创建执行环境栈(ECS):保存函数调用顺序的数组
首先压入全局执行环境(全局EC)
全局EC引用着全局对象window
window种保存着我们的全局变量
2、定义函数时
创建函数对象:封装代码段
在函数对象中有一个scope(作用域)属性:记录着函数来自的作用域是哪里
全局函数的scope都是window
3、调用前
在执行环境栈(ECS)压入新的EC(函数的EC)
创建出活动对象(AO):保存着本次函数调用时用到的局部变量
在函数的EC中有一个scope chain(作用域链)属性引用着AO
AO还有parent属性是函数的scope引用着的对象
4、调用时:
正是因为有了前面三步,才会带来变量的使用规则:优先使用局部的,局部没有找全局,全局没有就报错
5、调用完:
函数的EC会出栈,没人引用着AO,AO自动释放,局部变量也就释放了
*****闭包:希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一个函数,只是写法比较特殊
何时使用:希望保护一个可以【反复使用的局部变量】- 私有化变量
如何使用:
1、两个函数进行嵌套
2、外层函数创建出受保护的变量
3、外层函数return出内层函数
4、内层函数在操作受保护的变量
强调:
1、判断是不是闭包:有没有两个函数嵌套,返回内层函数,内层函数再操作受保护的变量
2、外层函数调用了几次,就创建了几个闭包,受保护的变量就有了几个副本
3、同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量
缺点:受保护的变量,永远都不会被释放,使用过多,会导致内存泄漏 - 闪退,不可多用!
问题:应该在哪里去使用呢?
1、四个事件需要防抖节流 - 共同:触发的飞快,但是我们不需要飞快的修改DOM树!
1、elem.onmousemove
2、input.oninput
3、window.onresize
4、window.onscroll
防抖节流公式:
function fdjl(){
var timer=null;
return function(){//停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开
if(timer){clearTimeout(timer);timer=null;}
timer=setTimeout(()=>{
操作;
},间隔毫秒数)
}
}
var inner=fdjl()
总结:
两链一包:
1、作用域链:以函数的EC的scope chain属性为起点,经过AO逐级引用,形成的一条链式结构
作用:查找变量,来带了变量的使用规则:优先使用局部的,局部没有找全局,全局没有就报错
2、原型链:每个对象都有一个属性.__proto__,可以一层一层的找到每个人父亲,形成了一条链式结构
作用:找共有属性和共有方法的,哪怕自己没有会悄悄的向上查找,如果最顶层也没有才会报错
最顶层是Object的原型,甚至上面放着我们眼熟的API - toString,怪不得人人都可以使用
3、闭包:希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一个函数,只是写法比较特殊
作用:专门用于防抖节流