面向对象---封装、继承和多态
1、封装(创建)--三种方式
直接量方式 --适用于创建的对象较少时使用
语法: let obj={
"属性名1":属性值,
"属性名2":属性值,
....
"方法名1":function(){
操作;
}
"方法名2":function(){
操作;
}
...
}
预定义构造函数方式 --不推荐使用
语法:let obj=new Object()
添加属性和方法:
obj.属性名=属性值
obj.方法名=function(){
操作
}
特点:创建的是一个空对象,需要自己往里面添加属性和方法
自定义构造函数方式--需要创建多个同类对象(属性名相同,属性值不同)
使用步骤:创建 function 名(形参a,形参b,形参c){
this.形参a=形参a;
this.形参b=形参b;
this.形参c=形参c;
}
调用:let obj=new 名(实参a,实参b,实参c)
访问对象的属性和方法
访问属性: obj.属性名 或者 obj["属性名"]
访问方法: obj.方法名 或者 obj["方法名"]
访问所有属性和方法: 使用for in循环访问
在对象里面使用自己的属性时: this.属性名
问题:当多个对象有相同的方法时,每写一次方法就会占用内存,这就会降低网页的性能
解决:利用对象的继承这一特点
2、继承: 父对象的成员(属性和方法),子对象可以直接使
每个对象都有原型,我们只要为原型设置方法,子对象就可以使用其方法
找父对象的方法:
方法一:对象名.proto
前提:必须有一个对象
方法二:构造函数名.prototype
目前学习的构造函数名:Array、String、Date、RegExp、Number、String、Boolean
为原型添加方法:
语法:构造函数名.prototype.方法名=function(){
操作;
}
继承中的笔试与面试题:
1、判断对象中的属性自有还是共有
公式:
if(obj.hasOwnProperty("属性名")){
属性名是自有属性
}
else{
if("属性名" in obj){
属性名是共有属性
}
else{
没有这个属性或方法
}
}
2、为原型或者浏览器添加它没有的方法
例:为老IE添加数组的indexof方法
步骤:1.判断是否是老IE
2.为其添加方法(直到方法的执行原理)
语法:
if(Array.prototype.indexOf===undefined){
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;
}
}
3、修改和删除自有或共有属性
修改和删除自有属性和方法:
修改:
obj.属性名=属性值
obj.方法名=function(){
新操作;
}
删除:
delete obj.属性名=属性值
delete obj.方法名
修改和删除共有属性和方法:
修改:
原型.属性名
原型.方法名=function(){
新操作;
}
删除:
delete 原型.属性名
delete 原型.方法名
4、判断引用数据类型
例:x是否是数组
方法一;语法:Array/Object/Date/RegExp.prototype.isPrototypeOf(type) 返回值为布尔值
方法二:语法:引用数据名 instanceof Array/Object/Date/RegExp 返回值为布尔值
方法三:语法:ES5 新增数组的判断 Array.isArray(引用数据名) 只能判断是否是数组 返回值为布尔值
方法四:固定语法:Object.prototype.toString.call/apply(x) 返回值为 [object 构造函数名]
5、实现自定义继承--设置对象的父对象
两个对象之间设置继承
语法:子对象.proto=父对象
多个对象之间设置继承
语法:构造函数名.prototype=父对象
注意:一定要先设置父对象,然后在去创建对象
6、两链一包:
原型链:每个对象都有一个属性.proto,可以一层一层的找到每个人父亲,形成了一条链式结构
作用域链:以函数的EC的scope chain属性为起点,经过AO逐级引用,形成的一条链式结构
闭包:想得到一个可以反复使用的局部变量的一种特殊的函数创建方式
3、多态:每一个原型都有它自己独有的方法,与其父对象的方法名相同但是操作不同
4、ES6 class关键字--简化面向对象
语法:
class 类名 extends 老类名{
constructor(name,speed,rl){
super(name,speed);
this.rl=rl;
}
方法名(){
操作
}
}
注意:创建方法时,不用写function,直接写方法名(){操作}
函数的闭包
函数的执行原理:
步骤:
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自动释放,局部变量也就释放;只会保存全局EC
闭包:想得到一个可以反复使用的局部变量的一种特殊的函数创建方式
使用:
1、两个函数进行嵌套
2、外层函数创建出受保护的变量
3、外层函数return出内层函数 (内层函数需要接住)
4、内层函数在操作受保护的变量
简单闭包:
function out(){
let s=0;
return function(){
操作s;
}
}
let inner=out()
闭包的优缺点:
优点:防抖节流;变量不会改变
缺点;每调用一次就会创建一个副本保存变量的值,会占用大量的内存空间,降低网页的性能
使用场景:四个事件
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(()=>{
操作;
},间隔毫秒数)
}
}
let inner=fdjl()
正则表达式--定义字符串中字符出现规则的表达式
使用场景:切割、替换和验证(用的最多)
语法:/正则表达式/后缀
后缀有;g(找全部) i(不区分大小写)
1、最简单的正则表达式就式关键字符本身
例:/hello/gi --就可以找到全部的hello
2、备选字符集:/[备选字符集]/
备选字符集中可以放入你想要的字符
注意:一个中括号,只管一位。如果备选字符集的ASCII码是连续的可以简化为 开始字符-结束字符
常用的字符集:
一位数字:[0-9]
一位字母:[A-Za-z]
一位数字、字母、下划线:[0-9A-Za-z_]
一位汉字:[\u4e00-\u9fa5]
一位数字、字母、汉字、下划线:[0-9A-Za-z\u4e00-\u9fa5_]
3、预定义字符集
一位数字:\d
一位数字、字母、下划线:\w
一位空白字符:\s 什么叫空白字符:空格、制表符、换行
4、量词--规定了一个字符集出现的次数
有明确数量:
字符集{n,m}:前边相邻的字符集,至少n个,最多m个
字符集{n,}:前边相邻的字符集,至少n个
字符集{n}:前边相邻的字符集,必须n个
无明确数量:
字符集?:前边相邻的字符集,可有可无,最多1个
字符集*:前边相邻的字符集,可有可无,
字符集+:前边相邻的字符集,至少一个,
5、指定匹配位置
开头:^
结尾:$
特殊:两者同时使用,前加^后加$,表示从头到尾要求完全匹配 - 用于做验证
6、选择和分组--两则一般同时使用
选择:在多个规则中选一个
规则1|规则2
分组:将多个字符集临时组成一组子规则
(规则1|规则2)
7、密码强度:用于判断字符串的复杂程度的
预判公式:(?!字符集+$)
常用密码规则:
(?![0-9]+$) -> 不能全由数字组成
(?![a-z]+$) ->不能全由小写字母组成
(?![0-9a-z]+$) ->不能由数字和小写的组成,必须有其它字符
字符串中支持正则的API
1、切割
语法:let arr=str.split("固定切割符"/RegExp)
2、替换
基础替换法:
语法:str=str.replace(RegExp,"新内容");
缺点:只能替换成固定的内容
高级替换法:
语法:str=str.replace(RegExp,function(a,b,c){
return 判断a关键字的长度,从而返回不同的替换内容
})
3、格式化
例:手机号的格式化
关键:把你所需要显示的内容用组合括起来,这样就可以得到自己所需要的内容
function format1() {
let iphone = "13857642391";
let reg = /^(\d{3})\d{4}(\d{4})$/
iphone = iphone.replace(reg, function (a, b, c, d, e) {
return ${b}****${c}
})
console.log(iphone)
}
format1()
正则对象
创建:
直接量:let reg=/正则表达式/后缀
构造函数:let reg=new RegExp("正则表达式","后缀")
正则的API
reg.test(user) --放回是一个bool值
this的指向:
1、单个元素绑定事件this->这个元素
2、多个元素绑定事件this->当前元素
3、定时器中的this->window
4、箭头函数中的this->外部对象
5、函数中的this->谁在调用此方法,this就是谁
6、构造函数之中this->当前正在创建的对象
ES5 强制改变this的指向
call/apply: 临时替换this的指向 (他们会立即执行函数,不会要调用)
语法:
1、函数名.call(借用的对象,实参,...) - 单独传入每个实参
2、函数名.apply(借用的对象,arr) - 只能传入一个事件要求必须是一个数组
bind: 永久的替换了this的指向 (需要自己调用)
语法:let 新函数名=函数名.bind(永久对象,永久实参,...) //它相当于创建了一个与原函数功能一模一样的函数,并且更改了this的指向和可以设置永久的参数
借用别人的方法的三个固定套路
1、Math.max/min.apply(Math,arr) ===> Math.max/min(...arr)
2、Object.prototype.toString.call/apply(arr)=="[object
Array]"//toString不需要传入实参
3、类数组转为普通数组:
1、老方式:接住=Array.prototype.slice.call/apply(类数组对象);
2、新方法:接住=Array.from(类数组对象)
ES6 版本
1、创建变量与常量 :let const
2、箭头函数:专门简化一切的匿名回调函数
公式:function去掉,()和{}之间添加=>,如果形参只有一个,那么()省略,如果函数体只有一句话,那么{}省略,如果函数体只有一句话并且是return,那么{}和return都省略
3、模版字符串
语法:我的名字叫${变量名/对象名}
4、 结构赋值--使用与数组和对象
释义:解析结构再进行赋值 - 赋值的新方式
执行原理:如果赋值符号,左右两边的结构一样,就会悄悄得解开/脱掉结构再一一进行赋值
语法:
类数组:let [a,b,c]=[1,2,3]
注意:变量名和值要一一对应
类对象:let {a,b=默认值,c}={c:3,a:1,b:2}
注意:变量名和值要一一对应,但顺序可以不同
5、新的循环 for of
语法:for(let val of 数组名){
操作;
}
缺点:只能遍历索引数组,不能遍历hash数组;没有提供过下标,意味着不能修改原数组
6、Set 和Map 两种新的数据类型
Set:类似于数组的一种数据格式 - 【去重数组,然后再转回数组】
语法:[...new Set(arr)]
...扩展运算符,可以脱掉数组/对象的外套
Map:类似于对象的一种数据格式
let m=new Map();
添加:m.set("键","值");
获取:m.get("键");
删除:m.delete("键");
清空:m.clear();
遍历:m.forEach(callback);
取消绑定事件:
1、如果你使用elem.on事件名=()=>{},那么写成:elem.on事件名=null; 可以取消事件绑定了
2、如果你使用elem.addEventListener("事件名",callback); 那么写成
elem.removeEventListener("事件名",callback); - 事件名和回调函数,【必须和添加时是一模一样的】
注意:(只输出一次就取消绑定);要把回调函数进行封装,这样才能保证它们的地址值是一样的
封装一个运动函数来设置css样式;
语法:
function animate(elem,obj){
for(var i in obj){
elem.style[i]=obj[i]
}
}
插件文件的使用--百度
例1:动画文件的使用步骤:
1、打开百度:搜索animate.css得到网址 animate.style/
2、下载文件
3、引入此文件
4、挑选你喜欢的动画,把class放到你需要的元素上
5、并且要设置上animation-duration: 1s;执行时长
6、还需要根据不同的动画,设置不同的初始效果,才会好看
例2:地图插件的使用步骤:
1、打开百度:搜索:百度/高德地图开放平台,进入
2、注册/登录百度账号
3、拉到最下面 - 注册成为开发者,跳转到控制台
4、创建应用 - 应用名称你随便,应用类型浏览器端,白名单写一个*,实名认证一下
5、恭喜你得到了密钥 - 成功了一大半了
6、鼠标放到导航条上开放文档 -> javascript API -> 示例DEMO -> 挑选你喜欢的地图,复制到你的项目之中
7、修改JS代码、在线查询经纬度
8、注意:再百度地图某次升级过后,出现了GL地图和普通版地图,两者不可以混搭使用,只要是GL都可以混搭使用