前端知识点总结——JS高级(持续更新中)
1.字符串
什么是: 连续存储多个字符的字符数组
相同: 1. 下标 2. .length 3. 遍历
4. 选取: slice(starti[, endi])
不同: 类型不同 API不通用
API: 所有字符串API都无权修改原字符串,总是返回新字符串
- 大小写转换:
统一转大写: str=str.toUpperCase()
统一转小写: str=str.toLowerCase()
何时: 不区分大小写时,都需要先转为一致的大小写,再比较。
说明: 验证码本不该客户端做,应该由服务器端完成
2.获取指定位置的字符:
str.charAt(i) => str[i]
获取指定位置字符的unicode号
str.charCodeAt(i)
将unicode号转为汉字: String.fromCharCode(unicode)
3.获取子字符串:
str.slice(starti,endi+1)
强调: 如果一个API,两个参数都是下标,则后一个参数+1(含头不含尾)
str.substring(starti,endi+1) 用法和slice完全一样
强调: 不支持负数参数
str.subStr(starti,n) 从starti开始,取n个
强调: 第二个参数不是下标,所以,不用考虑含头不含尾
4.查找: 4种:
- 查找一个固定的关键词出现的位置:
var i=str.indexOf(“关键词”[,fromi])
在str中,fromi位置后,找下一个”关键词”出现的位置
如果找到,返回关键词第一个字的下标位置
如果没找到,返回-1
说明: fromi可省略,默认从0开始var i=str.lastIndexOf(“关键词”);
在str中,查找”关键词”最后出现的位置问题: 只能查找一个固定的关键词
卧我草/操/艹/槽
微 信 w x wei xin
解决: 用正则查找: 判断是否包含关键词:
var i=str.search(/正则/)
返回值: 如果找到,返回关键词的位置如果没找到,返回-1
问题: 默认,所有正则都区分大小写
解决: 在第二个/后加i ignore 忽略
问题: 只能获得位置,无法获得本次找到的敏感词的内容获得关键词的内容:
var arr=str.match(/正则/i);
2种情况:- 不加g的情况: 只能返回第一个找到的关键词内容和位置: [ 0: “关键词内容”, index: 位置 ]
- 加g: 返回所有找到的敏感词的内容,保存在数组中。g: global
强调: 如果找不到,返回null
警告: 凡是一个函数可能返回null!都要先判断不是null,才能用!
问题: 只能获得关键词内容,无法获得位置
- 即找每个关键词内容,又找每个关键词位置:
reg.exec()
5.替换:
什么是: 将找到的关键词替换为指定的内容
如何: 2种:
- 简单替换: 将所有敏感词无差别的替换为统一的新值
str=str.replace(/正则/,”替换值”) 高级替换: 根据每个敏感词的不同,分别替换不同的值
str=str.replace(/正则/,function(kw){//kw: 会自动获得本次找到的一个关键词 return 根据kw的不同,动态生成不同的替换值
})
衍生: 删除关键词:
str=str.replace(/正则/,””)
6.正则表达式: Regular Expression
什么是: 描述一个字符串中字符出现规律的规则的表达式
何时: 2种:
- 查找关键词:
- 验证:
如何: 正则表达式语法:
- 最简单的正则其实是关键词原文:
7.字符集:
什么是: 规定一位字符,备选字符列表的集合
何时: 只要一位字符,有多种备选字时
如何: [备选字符列表]
强调: 一个[]只能匹配一位字符
简写: 如果备选字符列表中部分字符连续
可简写为: [x-x] 用-省略中间字符
比如: [0-9] 一位数字
[a-z] 一位小写字符
[A-Z] 一位大写字母
[A-Za-z] 一位字符
[0-9A-Za-z] 一位字母或数字
[\u4e00-\u9fa5] 一位汉字
反选: 1 除了4和7都行
8.预定义字符集: 4种:
d 一位数字 [0-9]
w 一位数字,字母或下划线 [0-9A-Za-z_]
强调: 只有100%匹配时,才使用w,如果不允许有_,则使用自定义字符集
s 一位空字符,比如: 空格,Tab,…
. 通配符
问题: 字符集只能规定字符的内容,无法灵活规定字符的个数
9.量词:
什么是: 专门规定一个字符集出现次数的规则
何时: 只要规定字符集出现的次数,都用量词
如何: 字符集量词
强调: 量词默认只修饰相邻的前一个字符集
包括: 2大类:
1. 有明确数量边界:
{6,8} 最少6次,最多8次
{6,} 最少6次,多了不限
{6} 必须6次,不能多也不能少
2. 没有明确数量边界:
? 可有可无,最多1次
* 可有可无,多了不限
+ 至少1次,多了不限
10.选择和分组:
- 选择: 或
规则1|规则2
何时: 只要在两个规则中任选其一匹配 分组: (规则1规则2…)
何时: 如果希望一个量词同时修饰多个规则时,都要先将多个规则分为一组,再用量词修饰分组。比如: 车牌号: [\u4e00-\u9fa5][A-Z]•[0-9A-Z]{5} 比如: 手机号规则: \+86或0086 可有可无,最多1次 空字符 可有可无,多了不限 1 在3,4,5,7,8中选一个
9位数字
(+86|0086)?s*1[34578]d{9}比如: 身份证号:
15位数字 2位数字 一位数字或X
可有可无,最多一次 \d{15}(\d{2}[0-9X])? 比如: 电子邮件: 鄙视
/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/
比如: url:
(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]
11.匹配特殊位置: 3个:
- 字符串开头: ^
字符串结尾: $
比如: 开头的空字符: ^s+结尾的空字符: \s+$ 开头或结尾的空字符: ^\s+|\s+$
3.单词边界: b 包括开头,结尾,空字符,标点符号
比如: 单词首字母: \b[a-z] 匹配单词: \bxxx\b
12.String:
替换: 2种: 如果关键词是固定的:
str=str.replace(“关键词”,”替换值”);
如果关键词变化
str=str.replace(/正则/ig,”替换值”);
切割: 2种: 如果分隔符是固定的:
var substrs=str.split(“分隔符”)
如果分隔符不是固定的
var substrs=str.split(/正则/i)
固定套路: 将字符串打散为字符数组
var chars=str.split("")
13.RegExp:
什么是: 保存一条正则表达式,并提供用正则表达式执行验证和查找的API
何时: 只要用正则查找关键词或验证字符串格式时
如何:
创建: 2种:
- 直接量: var reg=/正则/ig
何时: 只要正则表达式的规则是固定不变的。
问题: 正则表达式时固定不变的,不支持动态生成 - new: var reg=new RegExp(“正则”,”ig”);
何时: 只要需要动态生成正则表达式
API: 2个:
- 验证: var bool=reg.test(str)
问题: 默认,只要找到匹配的内容,就返回true,不要求完整匹配!
解决: 今后,凡是验证必须前加^,后加$ - 查找: 即找每个关键词位置,又获得每个关键词内容
var arr=reg.exec(str)
在str中查找下一个关键词的位置和内容
返回值: arr:[ 0: 内容, index: 位置 ]
如果找不到,返回null
如果找所有: 只要用while反复调用reg.exec即可,exec可自动跳到下一个查找位置
14.Math
什么是: 保存数学计算的常量和API的对象
何时: 进行算术计算
如何:
创建: 不用创建,所有API都用Math直接调用
API:
- 取整:
上取整: Math.ceil(num)
下取整:
Math.floor(num)
parseInt(str) 去掉字符串结尾非数字字符(单位)
四舍五入取整:
Math.round(num)
优: 返回数字类型,可直接计算
缺: 不能随意指定小数位数
n.toFixed(d)
优: 可随意指定小数位数
缺: 返回字符串类型,不能直接做加法
自定义round
- 乘方和开平方:
Math.pow(底数,幂)
Math.sqrt(num) - 最大值和最小值
Math.max(值1, 值2,…)
Math.min(值1, 值2,…)
问题: 不支持数组
解决: Math.max(…arr) - 随机数:
Math.random() 0~1 随机小数
公式: 在min到max之间取一个随机整数
parseInt(Math.random()*(max-min+1)+min)
简写: 在0~max之间取一个随机整数
parseInt(Math.random()*(max+1)) 三角函数:
已知角度,求边长,用三角函数: sin cos tan
已知边长,求角度,用反三角函数: asin acos atan
仅以atan:
var 弧度=Math.atan(对边长/邻边长)360角度=2π弧度
问题: atan无法区分角度的象限
解决: Math.atan2(对边长, 邻边长);
15.Date:
什么是: 保存一个时间,提供操作时间的API
何时: 只要在程序中存储时间或操作时间,都用date
如何:
创建: 4种:
- 创建日期对象,并自动获得客户端当前系统时间
var now=new Date(); - 创建日期对象,保存自定义时间
var now=new Date(“yyyy/MM/dd hh:mm:ss”); - 用毫秒数创建日期对象:
var date=new Date(ms) - 复制一个日期对象:
问题: 日期的计算都是直接修改原日期对象
解决: 如果希望同时保留计算前后的开始和结束时间,都要先复制开始时间,再用副本计算结束时间
var date2=new Date(date1)
本质: 起始日期对象内部保存的是一个巨大的毫秒数:
1970年1月1日至今的毫秒数
文字存储日期的问题:
1. 有时区问题:
2. 不便于计算:
毫秒数存储日期:
1. 不受时区的干扰:
2. 便于计算:
总结: 将来在网络中传输或在数据库中存储时间,都用毫秒数
16.API:
- 8个单位:
FullYear Month Date Day
Hours Minutes Seconds Milliseconds - 每个单位上都有一对儿get/set方法:
getXXX() 负责获得单位的值
setXXX() 负责修改单位的值
特例: Day 不能修改,没有setDay() - 取值范围:
Month: 0~11 计算机中的月份总是比现实中小1
Date: 1~31
Day: 0~6
Hours: 0~23
Minutes/Seconds: 0~59
日期计算:
- 两日期相减: 得到的是毫秒差
何时: 计算时间段或计算倒计时 对任意单位做加减: 3步:
- 获得单位的当前值
- 做加减
- 将计算后的结果set回去
setXXX()可自动调整时间进制
可简化为: date.setXXX(date.getXXX()+n)
问题: setXXX()直接修改原日期
解决: 如果同时保存计算前后的开始和结束时间,应该先复制副本,再用副本计算。
17.Date:
日期格式化:
date.toString() 默认当地时间的完整版格式
date.toLocaleString() 转为当地时间的简化版格式
date.toLocaleDateString() 仅保留日期部分
date.toLocaleTimeString() 仅保留时间部分
18.Error:
什么是错误: 程序执行过程中,遇到的无法继续执行的异常情况
程序出错,都会强行中断退出。
什么是错误处理: 即使程序出错!也保证不会中断退出
何时: 如果希望程序,即使出错,也不会强行中断退出
如何:
try{
可能出错的正常代码
}catch(err){
//err: 错误对象, 自动保存了错误的信息
只有出错才执行的错误处理代码:
提示错误信息, 记录日志, 释放资源
}
问题: 效率略低
解决: 多数try catch,都能用if…else代替
主动抛出错误:
throw new Error(“错误信息”)
鄙视: js中共有几种错误类型: 6种:
SyntaxError 语法错误
ReferenceError 引用错误
TypeError 类型错误
RangeError 范围错误 参数超范围
EvalError URIError
19.Function:
什么是函数: 保存一段代码段的对象,再起一个名字。
为什么: 代码重用
何时: 只要一段代码可能被重复使用时!
如何:
创建: 3种:
声明: function 函数名(参数列表){
函数体; return 返回值; }
参数: 调用函数时,接收传入函数的数据的变量
何时: 如果函数自身必须某些数据才能正常执行时,就必须定义参数,从外部接收必须的数据
返回值: 函数的执行结果
何时: 如果调用者需要获得函数的执行结果时
调用: var 返回值=函数名(参数值列表);
问题: 声明提前: 在程序开始执行前,先将var声明的变量和function声明的函数,提前到当前作用域的顶部集中创建。赋值留在原地。
解决:直接量: var 函数名=function (参数列表){
特点: 不会被声明提前
揭示: 函数名其实只是一个变量函数其实是一个保存代码段的对象 函数名通过对象地址引用函数对象
- new :
var 函数名=
new Function(“参数1″,”参数2″,…,”函数体”)
20.重载overload:
什么是: 多个相同函数名,不同参数列表的函数,在调用时,可根据传入的参数不同,自动执行不同的操作。
为什么: 为了减少API的数量,减轻调用者的负担
何时: 只要一项任务,可能根据传入参数的不同,执行不同的流程时。
如何: js语法默认不支持重载!
因为: js中不允许多个同名函数,同时存在。最后一个函数会覆盖之前的。
变通实现: arguments
什么是: 每个函数中,自动包含的,接收所有传入函数的参数值的类数组对象
类数组对象: 长得像数组的对象
vs 数组: 相同: 1. 下标, 2. .length, 3. 遍历
不同: 类型不同, API不通用
21.匿名函数:
什么是: 定义函数时,不指定函数名
为什么: 节约内存 或 划分临时作用域
何时:
- 只要一个函数,希望调用后,立刻自动释放!
- 划分临时作用域:
如何:
- 回调: 定义函数后,自己不调用,而是传递给另一个函数去调用
- 自调: 定义函数后,立刻调用自己。
何时: 今后所有js代码必须都放在匿名函数自调中,避免全局污染。
22.垃圾回收:
什么是垃圾: 一个不再被任何变量使用的对象
什么是垃圾回收: js引擎会自动回收不再被使用的对象的空间。
为什么: 内存空间都是有限的!
垃圾回收器: 专门负责回收垃圾对象的小程序——js引擎自带
如何:
- 程序执行时,垃圾回收器伴随主程序执行而执行。
- 每创建一个对象,垃圾回收器就会记录对象被几个变量引用着.
- 如果发现一个对象不再被任何变量应用,则自动回收该对象的存储空间。
好的习惯: 只要一个对象不再使用,就要赋值为null
23.作用域和作用域链
作用域(scope): 一个变量的可用范围
为什么: 避免内部的变量影响外部
本质: 是一个存储变量的对象
包括: 2种:
- 全局作用域: window
保存全局变量: 随处可用,可反复使用 - 函数作用域: ?
保存局部变量: 仅在函数内可用,且不可重用!
24.函数生命周期:
程序开始执行前
在内存中创建执行环境栈(数组): 用于保存正在调用的函数任务。
在执行环境站中添加第一条记录: 调用浏览器主程序
创建全局作用域对象window: 2个作用:1. 保存浏览器自己需要的数据和对象 2. 作为程序的全局作用域对象,保存全局变量
- 定义函数时:
在window中定义函数名变量
创建函数对象保存函数定义
函数名变量引用函数对象
函数对象的scope属性,又指回了函数创建时的作用域 - 调用函数时
在执行环境栈中添加了本次函数调用的记录
创建本次函数调用的函数作用域对象AO
在AO中添加函数的局部变量
设置AO的parent指向函数的scope
执行环境栈中的函数调用记录,引用AO
变量的使用顺序: 先用局部,再用全局 - 函数调用后
本次函数调用的记录从执行环境栈中出栈
导致AO被释放, 导致所有局部变量都释放
25.作用域链:
什么是: 由多级作用域对象,逐级引用形成的链式结构
2个作用:
- 保存所有变量
- 控制着变量的使用顺序!
26.闭包closure:
什么是: 即重用一个变量,又保护变量不被污染的一种机制
为什么: 全局变量和局部变量都具有不可兼得的优缺点:
全局变量: 优: 可重用, 缺: 易被污染
局部变量: 优: 仅函数内可用,不会被污染
缺: 不可重用!
何时: 只要一个变量,可能被重用,又不想被篡改
如何: 3步:
- 用外层函数包裹要保护的变量和内层函数
- 外层函数将内层函数返回到外部
- 调用外层函数,获得内层函数的对象,保存在外部的变量中——形成了闭包
闭包形成的原因: 外层函数调用后,外层函数的函数作用域对象无法释放
主动使用闭包: 为一个函数绑定一个专属的变量
鄙视: 画简图
- 找受保护的变量,并确定其最终值
找内层函数对象
外层函数向外返回内层函数对象: 3种:- return function(){}
- 全局变量=function(){}
- return arr/obj{function(){…}}
27.OOP
什么是对象: 内存中存储多个数据的独立存储空间都称为一个对象。
什么是面向对象: 程序中都是用对象结构来描述现实中一个具体事物。
为什么: 为了便于大量数据的维护和查找
何时: 几乎所有js程序,都使用面向对象的方式开发
如何: 三大特点: 封装,继承,多态
封装: 用对象来集中描述现实中一个具体事物的属性和功能
为什么: 便于维护和查找
何时: 今后只要使用面向对象的方式开发,都要先封装对象,再按需使用对象的属性和功能。
如何: 3种:
用{}:
var obj={
属性名:值,... : ... ,
//方法名:function(){…},
方法名 (){…},
}
其中: 事物的属性值会成为对象的属性对象的属性本质是保存在对象中的一个变量 事物的功能会成为对象的方法! 方法的本质是保存在对象中的一个函数
如何访问对象的成员:
访问对象的属性: 对象.属性名
调用对象的方法: 对象.方法名()
问题: 对象自己的方法中要使用对象自己的属性
错误: 直接用属性名,报错: 找不到变量为什么: 默认,不加.就使用的变量,只能在作用域链中查找,无法自动进入对象中
解决一: 对象名.属性名
问题: 对象名仅是一个普通的变量名,可能发生变化。
正确解决: this.属性名
this: 自动指正在调用当前方法的.前的对象为什么: 不受对象名变量的影响 何时: 只要对象自己的方法向访问对象自己的属性时,都必须加this.
js中对象的本质,其实就是一个关联数组
- 用new:
var obj=new Object(); //创建空对象 等效于{}
obj.属性名=值;
obj.方法名=function(){
… this.属性名 …
}
和关联数组一样,js中的对象也可随时添加新属性和方法。
问题: 反复创建多个相同结构的对象时,重复代码太多,导致不便于维护
解决:
用构造函数:
构造函数: 描述一类对象统一结构的函数
为什么: 为了重用结构代码!
何时: 只要反复创建相同结构的多个对象时,都用构造函数
如何: 2步:定义构造函数
function 类型名(属性参数列表){
this.属性名=属性参数;
this. … = 属性参数;
this.方法名=function(){this.xxx
}
}调用构造函数创建新对象
var obj=new 类型名(属性值列表)
new: 1. 创建新的空对象2. 设置新对象继承构造函数的原型对象 3. 用新对象调用构造函数 将构造函数中的this都指向新对象 4. 返回新对象的地址
问题: 构造函数只能重用代码,无法节约内存!
解决: 继承:
28.继承:
什么是: 父对象的成员,子对象无需创建,就可直接使用
为什么: 代码重用,节约内存
何时: 只要多个子对象,拥有相同的成员时,都应只在父对象中定义一份,所有子对象共用即可!
如何: js中继承都是通过原型对象实现的
什么是原型对象: 集中存储同一类型的所有子对象,共用成员的父对象
何时: 只要继承,必然原型对象
如何:
创建: 不用创建,买一赠一
每创建一个构造函数,都附赠一个原型对象
继承: 在创建子对象时,new的第2步自动设置子对象继承构造函数的原型对象
访问成员: 优先访问自有成员
自己没有,就去父对象(原型对象)中查找
将成员添加到原型对象中:
构造函数.prototype.成员=值
自有属性和共有属性:
自有属性: 保存在当前对象本地,仅归当前对象独有的属性
共有属性: 保存在父对象中,所有子对象共有的属性
读取属性值: 子对象.属性
修改属性值: 自有属性,必须通过子对象自己修改
共有属性,只能用原型对象修改!
内置对象的原型对象:
鄙视: 内置对象: 11个:
String Number Boolean ——包装类型对象
Array Date RegExp Math
Error
Function Object
Global (在浏览器中,被window代替)
鄙视: 包装类型的理解
什么是: 保存一个原始类型的值,并提供操作原始类型值的API
为什么: 原始类型的值本身不具有任何功能
何时: 只要试图对原始类型的值调用API时,都会自动使用包装类型对象来帮助原始类型的值执行操作。
如何:
1. 内存中已经预置了三大包装类型的对象:
String Number Boolean
2. 在试图对原始类型的值调用API时,自动检测原始类型的值的类型名
var n=345.678;
typeof n => number
3. 根据类型名实例化对应的包装类型对象,调用其API
new Number(n).toFixed(2) => 345.68
4. 执行后,包装类型对象自动释放
new Number释放!
29.OOP
面向对象三大特点: 封装,继承,多态
继承:
原型对象:
内置类型的原型对象:
一种类型: 包含两部分:
1. 构造函数: 创建该类型的子对象
2. 原型对象: 保存所有子对象的共有成员
解决浏览器兼容性问题: 旧浏览器无法使用新API
1. 判断当前浏览器对应类型的原型对象中是否包含该API
2. 如果不包含,则自定义该API,添加到对应类型的原型对象中
30.原型链:
什么是: 由多级父对象,逐级继承形成的链式结构
保存着: 所有对象的属性
控制着: 对象属性的使用顺序:
先自有,再共有
鄙视: 如何判断一个对象是数组类型? 有几种方法
错误: typeof : 只能区分原始类型,函数,无法进一步区分引用类型对象的具体类型名
正确: 4种:
- 判断原型对象:
obj.__proto__==Array.prototype
Array.prototype.isPrototypeOf(obj) - 判断构造函数:
obj.constructor==Array
obj instanceof Array
问题: 不严格, 不但检查直接父对象,且检查整个原型链
- 判断对象内部的class属性
class属性: 对象内部的专门记录对象创建时的类型名的属性
问题1: class属性是内部属性,无法用.直接访问
解决: 唯一的办法: Object.prototype.toString()
问题2: 每种类型的原型对象都重写了各自不同的toString()方法,子对象无法调用到Object.prototype.toString()
解决: fun.call(obj) 让obj强行调用任何一个fun
Object.prototype.toString.call(obj)
在执行的一瞬间: obj.toString()
结果:"[object Class]"
鄙视: 何时将方法定义在原型对象中,何时将方法定义在构造函数上
实例方法和静态方法:
实例方法: 必须该类型的子对象才能调用的方法
比如: arr.sort() arr.push()
何时: 只要要求必须该类型的子对象才能调用
如何: 所有放在原型对象中的方法都是实例方法
静态方法: 不需要创建该类型的子对象,任何对象都可使用的方法。
比如: Array.isArray(fun)
Array.isArray(date)
Array.isArray(obj)
何时: 不确定将来调用该函数的对象类型时
如何: 添加到构造函数对象上的方法都是静态方法。可通过构造函数.静态方法方式直接调用!
31.多态:
什么是: 一个方法在不同情况下表现出不同的状态
包括:
- 重载overload:
- 重写override:
什么是: 如果子对象觉得从父对象继承来的成员不好用,可在本地定义同名的自有成员,覆盖父对象的成员
为什么: 觉得从父对象继承来的成员不好用
何时: 只要觉得从父对象继承来的成员不好用
如何: 在本地定义同名的自有成员
32.自定义继承:
- 只修改一个对象的父对象
obj.__proto__=father
Object.setPrototypeOf(obj,father) - 修改所有子对象的父对象:
构造函数.prototype=father
时机: 在创建子对象之前换! 两种类型间的继承:
何时: 发现多个类型之间拥有部分相同的属性结构和方法定义时,都要抽象父类型出来
如何: 2步:定义抽象父类型: 2步:
- 定义构造函数保存公共的属性结构
- 定义原型对象保存公共的方法
让子类型继承父类型: 2步:
- 在子类型构造函数中借用父类型构造函数
错误: 直接调用: Flyer(fname,speed)
原因: Flyer不用.不用new调用,其中的this默认指window,Flyer中所有属性泄露到全局
正确: 用call将正确的this注入到Flyer中,代替错误的this
如何: Flyer.call(正确的this, fname,speed) - 让子类型原型对象继承父类型原型对象
Object.setPrototypeOf(子类型原型,父类型原型)
- 在子类型构造函数中借用父类型构造函数
33.ECMAScript6
严格模式:
什么是: 比普通js运行机制要求更严格的模式
为什么: 普通的js运行机制有很多广受诟病的缺陷
何时: 今后所有项目必须运行在严格模式下- 如果新项目,整个js文件启用严格模式
- 旧项目,逐个函数启用严格模式
如何:
- 在script或整个js文件顶部,添加”use strict”;
- 在函数内顶部,添加”use strict”;
规则: 4个:
- 禁止给未声明的变量赋值
- 将静默失败升级为错误
- 普通函数或匿名函数自调中的this默认不再指向window,而是undefined
- 禁止使用arguments, arguments.callee,…
补: arguments.callee 自动获得当前正在调用的函数本身
禁用,说明强烈不推荐使用递归!
34.保护对象:
保护对象的属性:
ES5将对象属性分为:
命名属性: 可用.直接访问到的属性
数据属性: 直接存储属性值的属性
保护数据属性: 4大特性:
一个属性包含四大特性:{
value: 实际保存属性值,
writable: true/false, //只读
enumerable: true/false, //不可遍历
//不是彻底隐藏,用.依然可访问!
configurable:true/false //1. 禁止删除
//2. 禁止修改其它特性
//一旦改为false,不可逆
}
获取一个属性的四大特性:
var attrs=Object.getOwnPropertyDescriptor(obj,"属性")
修改四大特性:
Object.defineProperty(obj,"属性",{
四大特性:值
})
简写: Object.defineProperties(obj,{
属性名:{
特性:值,
特性:值,
},
属性名:{
... : ...
}
})
访问器属性: 不直接存储属性值,仅提供对另一个数据属性的保护
何时: 只要对一个属性提供自定义规则的保护
如何:
添加: 只能用Object.defineProperty和defineProperties添加
四大特性: {
get(){ return this.数据属性 }
set(val){
如果验证val通过
this.数据属性=val
否则
报错
}
enumerable:
configurable:
}
如何使用: 同普通的数据属性用法一样!
在取值时,自动调用访问器属性内部的get
在赋值时,自动调用访问器属性内部的set方法,同时将等号右边的新值,交给val参数
问题: enumerable只能防住for in,防不住.,依然可用.直接修改被保护的数据属性
解决:
内部属性: 不能用.直接访问到的属性
比如: class proto
保护对象的结构: 3种
防扩展: 禁止给对象添加新属性
Object.preventExtensions(obj)
原理: 内部属性: extensible:truepreventExtensions将extensible改为false
密封: 在防扩展同时,禁止删除现有属性
Object.seal(obj)
原理: 1. 将extensible改为false,禁止扩展2. 自动将所有属性的configurable都改为false
冻结: 在密封的同时,禁止修改一切属性值
Object.freeze(obj)
原理: 1. 兼具密封的所有功能2. 又将每个属性的writable自动改为false!
Object.create()
仅用父对象,就可创建子对象,
同时还可为子对象扩展自有属性
var child=Object.create(father,{
//Object.defineProperties
属性名:{特性:值, 特性:值,
}
})
鄙视: 描述Object.create的执行原理- 创建空对象child
- 自动设置child的__proto__为father
- 为child扩展新的自有属性
35.call/apply/bind
替换函数中不想要的this!
call/apply: 立刻调用函数,并临时替换中的this为指定对象
何时: 只要调用函数时,函数中的this不是想要的就用call换成想要的
如果传入函数的参数,是以数组形式,整体传入
就用.apply(obj,arr)
bind: 基于原函数,创建一个新函数,并永久绑定this为指定对象
何时: 不会立刻调用的函数(回调函数)中的this,不是想要的,就可用bind创建一个新函数,并永久绑定this!
36.数组API:
判断:
判断数组中所有元素是否都符合条件
arr.every(function(elem,i,arr){//elem: 当前元素值 //i: 当前位置 //arr: 当前数组对象 return 判断条件
})
判断数组中是否包含符合条件的元素
arr.some(function(elem,i,arr){return 判断条件
})
遍历:
- forEach: 对原数组中每个元素执行相同的操作
arr.forEach(function(elem,i,arr){
arr[i]=新值
}) - map: 依次取出原数组中每个元素执行相同操作后,放入新数组。原数组不变
arr.map(function(elem,i,arr){
return 新值
})
过滤和汇总:
- 过滤: 复制出原数组中符合条件的元素,放入新数组返回
var subs=arr.filter(function(elem,i,arr){
return 判断条件
}) - 汇总: 将原数组中所有值统计出一个最终结论
var result=arr.reduce(function(prev,elem,i,arr){
//prev: 截止到目前,之前的临时汇总值
return prev+elem;
})
37.let: 代替var
为什么
问题1: 声明提前, 破坏程序原有执行顺序
解决: let禁止在声明之前,提前使用该变量
问题2: js没有块级作用域, 块内的变量,会污染到块外
解决: let会将当前所在if/for/while…(){}变成块级作用域
后果: 块内的let出的变量不会影响外部!
原理: 其实let就是匿名函数自调!
let与for循环,可形成闭包的效果
强调: 原来块内外都可使用的变量,出了块,就不能用了!
38.参数增强:
默认值: function fun(参数1, 参数2,…,参数n=默认值)
强调: 带默认值的参数必须定义在列表末尾
原理: 参数n=参数n||默认值;
rest: 代替了arguments
何时: 当函数,不确定参数个数时——重载
为什么: arguments的缺点:
- 类数组对象,不是数组
- 只能后去全部,不能有选择的分段获取
如何: 定义函数时: function fun(参数1,参数2,…, …数组名)
数组名, 是一个纯正的数组,且可有选择的分段获取
原理: var arr=[].slice.call(arguments[,starti]);//将类数组对象转为数组
spread: 代替apply
为什么: apply虽然可打散数组类型参数为单个值,但是必须和替换this的操作捆绑使用
何时: 只要仅需要打散数组类型参数为单个值时
如何: 调用时: fun(参数值1,参数值2,…数组)
- 箭头函数: 代替回调函数中的function
何时: 只要回调函数,都不再使用function,而是使用箭头函数
如何:
- 去function改=>
- 如果只有一个参数,可省略()
如果函数体只有一句话,则{}可省略
更简化: 如果仅有的一句话还是return,可省略return
特点: 内外共用同一个this ——代替bind
问题: 如果反而希望内外this不通用时,就不能用箭头函数
40.模板字符串: 代替+号拼接字符串
ESLint规定,不允许使用+拼接字符串
如何:
- 定义模板: 左右模板内容都必须放在“中
- 在模板中嵌入变量或表达式,动态生成内容:
模板内,可用${…}嵌入任何合法的js变量或语句
41.解构: 简化批量赋值
什么是: 将一个对象/数组中的成员和元素,分别提取出来,单独使用。
为什么: 避免反复使用对象名/数组名
何时: 只要希望将一个大的对象或数组中的每个成员单独取出使用时
如何: 3种:
- 数组解构: 下标对下标
- 对象解构: 属性对属性
- 参数解构: 属性对属性
定义函数时:
问题: 普通函数的参数列表的顺序和个数是固定的
解决: 使用对象语法定义参数列表
优点: 将来传入的参数个数,顺序与对象列表无关
调用函数: 也用对象语法传入参数
赋值过程中,采用对象结构的方式,为参数变量赋值
42.for…of 在特定情况下,代替for循环
什么是: 依次遍历数组/类数组对象中每个元素的值
vs for…in: 依次遍历关联数组/对象中每个成员的属性名
何时: 如果希望从头到尾遍历整个数组或类数组对象
如何:
for(var elem of arr){
elem
}
局限: 无法获得当前位置; 无法控制遍历的进度/顺序; 无法有选择的遍历部分
43.class: 代替传统的封装,继承,多态的语法
封装:
class Student {
constructor(sname,sage){
... ...
}
intr (){//Student.prototype.intr
}
fun (){
}
}
继承:
class Flyer {
constructor(fname,speed){
... ...
}
fly (){
... ...
}
}
class Plane extends Flyer{
constructor(fname,speed,score){
//super指向父类型构造函数,且自动替换this
super(fname,speed)
... ...
}
getScore (){
... ...
}
}
静态方法:
class User{
constructor(uname,upwd){
this.uname=uname;
this.upwd=upwd;
}
save(){//保存在User.prototype中的实例方法
console.log("保存当前对象");
}
static findOne(){//静态方法,定义在构造函数上
return new User();
}
}
var user=new User(...);
user.save();//调用实例方法
User.findOne();//调用静态方法
44.Promise: 解决: 回调地狱
什么是callback hell: 由于使用参数传递回调函数,导致步骤多时,参数的嵌套层级很深。
何时: 只要异步调用,可能发生延迟时,都要用Promise代替传统参数callback
如何: 定义时
function 第一件事(){
return new Promise(fn=>{
第一件事的内容
fn()
})
}
function 第二件事(){
return new Promise(fn=>{
第二件事的内容
fn()
})
}
function 第三件事(){
第三件事的内容
}
调用时:
第一件事()//return Promise(fn)
.then(第二件事)//return Promise(fn)
.then(第三件事)
鄙视题:
将类数组对象复制为数组:
var arr2=Array.prototype.slice.call(arguments)
将类数组对象复制为数组,并选取指定位置的剩余元素
var arr2= Array.prototype.slice.call(arguments,starti)相当于arguments.slice(starti)
其实更简单的: var arr2= [].slice.call(arguments,starti)
promise中的错误处理:
其实: new Promise(可接收2件事).then( ) .catch( )
new Promise((正常函数,出错函数)=>{
如果顺利执行: 调用正常() 否则 调用出错()
})
等待多个任务完成
前提: 每个任务都必须都返回Promise
如何: Promise.all([task1(), task2(),... ]).then(()=>{所有任务完成后才执行的任务})
- 47 ↩