js验证开始日期不能大于结束日期_现代前端进阶系列教程之(七):js语言篇高级前端知识点总结——JS高级...

11f414d6713b85a561f6ef3e647b425e.png

1.字符串

什么是: 连续存储多个字符的字符数组
相同: 1. 下标 2. .length 3. 遍历

4. 选取: slice(starti[, endi])

不同: 类型不同 API不通用
API: 所有字符串API都无权修改原字符串,总是返回新字符串

  1. 大小写转换:
    统一转大写: 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种:

  1. 查找一个固定的关键词出现的位置:
    var i=str.indexOf("关键词"[,fromi])
    在str中,fromi位置后,找下一个"关键词"出现的位置
    如果找到,返回关键词第一个字的下标位置
    如果没找到,返回-1
    说明: fromi可省略,默认从0开始

    var i=str.lastIndexOf("关键词");
    在str中,查找"关键词"最后出现的位置

    问题: 只能查找一个固定的关键词
    卧我草/操/艹/槽
    微 信 w x wei xin
    解决: 用正则查找:

  2. 判断是否包含关键词:
    var i=str.search(/正则/)
    返回值: 如果找到,返回关键词的位置

    如果没找到,返回-1

    问题: 默认,所有正则都区分大小写
    解决: 在第二个/后加i ignore 忽略
    问题: 只能获得位置,无法获得本次找到的敏感词的内容

  3. 获得关键词的内容: 
    var arr=str.match(/正则/i);
    2种情况:

    1. 不加g的情况: 只能返回第一个找到的关键词内容和位置: [ 0: "关键词内容", index: 位置 ]

    2. 加g: 返回所有找到的敏感词的内容,保存在数组中。g: global

强调: 如果找不到,返回null

警告: 凡是一个函数可能返回null!都要先判断不是null,才能用!

问题: 只能获得关键词内容,无法获得位置

  1. 即找每个关键词内容,又找每个关键词位置: 
    reg.exec()

5.替换:

什么是: 将找到的关键词替换为指定的内容
如何: 2种:

  1. 简单替换: 将所有敏感词无差别的替换为统一的新值
    str=str.replace(/正则/,"替换值")

  2. 高级替换: 根据每个敏感词的不同,分别替换不同的值
    str=str.replace(/正则/,function(kw){

     //kw: 会自动获得本次找到的一个关键词
    return 根据kw的不同,动态生成不同的替换值

    })

衍生: 删除关键词:
str=str.replace(/正则/,"")

6.正则表达式: Regular Expression

什么是: 描述一个字符串中字符出现规律的规则的表达式
何时: 2种:

  1. 查找关键词:

  2. 验证:

如何: 正则表达式语法:

  1. 最简单的正则其实是关键词原文:

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. 选择: 或
    规则1|规则2
    何时: 只要在两个规则中任选其一匹配

  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个:

  1. 字符串开头: ^

  2. 字符串结尾: $
    比如: 开头的空字符: ^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种:

  1. 直接量: var reg=/正则/ig
    何时: 只要正则表达式的规则是固定不变的。
    问题: 正则表达式时固定不变的,不支持动态生成

  2. new: var reg=new RegExp("正则","ig");
    何时: 只要需要动态生成正则表达式

API: 2个:

  1. 验证: var bool=reg.test(str)
    问题: 默认,只要找到匹配的内容,就返回true,不要求完整匹配!
    解决: 今后,凡是验证必须前加^,后加$

  2. 查找: 即找每个关键词位置,又获得每个关键词内容
    var arr=reg.exec(str)
    在str中查找下一个关键词的位置和内容
    返回值: arr:[ 0: 内容, index: 位置 ]
    如果找不到,返回null
    如果找所有: 只要用while反复调用reg.exec即可,exec可自动跳到下一个查找位置

14.Math

什么是: 保存数学计算的常量和API的对象
何时: 进行算术计算
如何: 
创建: 不用创建,所有API都用Math直接调用
API:

  1. 取整: 
    上取整: Math.ceil(num)
    下取整: 
    Math.floor(num)
    parseInt(str) 去掉字符串结尾非数字字符(单位)
    四舍五入取整: 
    Math.round(num)
    优: 返回数字类型,可直接计算
    缺: 不能随意指定小数位数
    n.toFixed(d) 
    优: 可随意指定小数位数
    缺: 返回字符串类型,不能直接做加法
    自定义round

  1. 乘方和开平方:
    Math.pow(底数,幂)
    Math.sqrt(num)

  2. 最大值和最小值
    Math.max(值1, 值2,...)
    Math.min(值1, 值2,...)
    问题: 不支持数组
    解决: Math.max(...arr)

  3. 随机数: 
    Math.random() 0~1 随机小数
    公式: 在min到max之间取一个随机整数
    parseInt(Math.random()*(max-min+1)+min)
    简写: 在0~max之间取一个随机整数
    parseInt(Math.random()*(max+1))

  4. 三角函数: 
    已知角度,求边长,用三角函数: sin cos tan
    已知边长,求角度,用反三角函数: asin acos atan
    仅以atan: 
    var 弧度=Math.atan(对边长/邻边长)

    360角度=2π弧度

    问题: atan无法区分角度的象限
    解决: Math.atan2(对边长, 邻边长);

15.Date:

什么是: 保存一个时间,提供操作时间的API
何时: 只要在程序中存储时间或操作时间,都用date
如何: 
创建: 4种:

  1. 创建日期对象,并自动获得客户端当前系统时间
    var now=new Date();

  2. 创建日期对象,保存自定义时间
    var now=new Date("yyyy/MM/dd hh:mm:ss");

  3. 用毫秒数创建日期对象:
    var date=new Date(ms)

  4. 复制一个日期对象: 
    问题: 日期的计算都是直接修改原日期对象
    解决: 如果希望同时保留计算前后的开始和结束时间,都要先复制开始时间,再用副本计算结束时间
    var date2=new Date(date1)

本质: 起始日期对象内部保存的是一个巨大的毫秒数:

1970年1月1日至今的毫秒数

文字存储日期的问题:

1. 有时区问题:
2. 不便于计算:

毫秒数存储日期:

1. 不受时区的干扰: 
2. 便于计算:

总结: 将来在网络中传输或在数据库中存储时间,都用毫秒数

16.API:

  1. 8个单位: 
    FullYear Month Date Day
    Hours Minutes Seconds Milliseconds

  2. 每个单位上都有一对儿get/set方法:
    getXXX() 负责获得单位的值
    setXXX() 负责修改单位的值
    特例: Day 不能修改,没有setDay()

  3. 取值范围: 
    Month: 0~11 计算机中的月份总是比现实中小1
    Date: 1~31 
    Day: 0~6 
    Hours: 0~23 
    Minutes/Seconds: 0~59

日期计算:

  1. 两日期相减: 得到的是毫秒差
    何时: 计算时间段或计算倒计时

  2. 对任意单位做加减: 3步:

    1. 获得单位的当前值

    2. 做加减

    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种:

  1. 声明: function 函数名(参数列表){

          函数体;
    return 返回值;
    }

    参数: 调用函数时,接收传入函数的数据的变量
    何时: 如果函数自身必须某些数据才能正常执行时,就必须定义参数,从外部接收必须的数据
    返回值: 函数的执行结果
    何时: 如果调用者需要获得函数的执行结果时
    调用: var 返回值=函数名(参数值列表);
    问题: 声明提前: 在程序开始执行前,先将var声明的变量和function声明的函数,提前到当前作用域的顶部集中创建。赋值留在原地。
    解决:

  2. 直接量: var 函数名=function (参数列表){
    特点: 不会被声明提前
    揭示: 函数名其实只是一个变量

      函数其实是一个保存代码段的对象
    函数名通过对象地址引用函数对象
  3. new : 
    var 函数名=
    new Function("参数1","参数2",...,"函数体")

20.重载overload:

什么是: 多个相同函数名,不同参数列表的函数,在调用时,可根据传入的参数不同,自动执行不同的操作。
为什么: 为了减少API的数量,减轻调用者的负担
何时: 只要一项任务,可能根据传入参数的不同,执行不同的流程时。
如何: js语法默认不支持重载!

 因为: js中不允许多个同名函数,同时存在。最后一个函数会覆盖之前的。
变通实现: arguments
什么是: 每个函数中,自动包含的,接收所有传入函数的参数值的类数组对象
类数组对象: 长得像数组的对象
vs 数组: 相同: 1. 下标, 2. .length, 3. 遍历
不同: 类型不同, API不通用

21.匿名函数:

什么是: 定义函数时,不指定函数名
为什么: 节约内存 或 划分临时作用域
何时:

  1. 只要一个函数,希望调用后,立刻自动释放!

  2. 划分临时作用域:

如何:

  1. 回调: 定义函数后,自己不调用,而是传递给另一个函数去调用

  2. 自调: 定义函数后,立刻调用自己。
    何时: 今后所有js代码必须都放在匿名函数自调中,避免全局污染。

22.垃圾回收:

什么是垃圾: 一个不再被任何变量使用的对象
什么是垃圾回收: js引擎会自动回收不再被使用的对象的空间。
为什么: 内存空间都是有限的!
垃圾回收器: 专门负责回收垃圾对象的小程序——js引擎自带
如何:

  1. 程序执行时,垃圾回收器伴随主程序执行而执行。

  2. 每创建一个对象,垃圾回收器就会记录对象被几个变量引用着.

  3. 如果发现一个对象不再被任何变量应用,则自动回收该对象的存储空间。

好的习惯: 只要一个对象不再使用,就要赋值为null

23.作用域和作用域链

作用域(scope): 一个变量的可用范围
为什么: 避免内部的变量影响外部
本质: 是一个存储变量的对象
包括: 2种:

  1. 全局作用域: window
    保存全局变量: 随处可用,可反复使用

  2. 函数作用域: ?
    保存局部变量: 仅在函数内可用,且不可重用!

24.函数生命周期:

  1. 程序开始执行前
    在内存中创建执行环境栈(数组): 用于保存正在调用的函数任务。
    在执行环境站中添加第一条记录: 调用浏览器主程序
    创建全局作用域对象window: 2个作用:

    1. 保存浏览器自己需要的数据和对象
    2. 作为程序的全局作用域对象,保存全局变量
  2. 定义函数时:
    在window中定义函数名变量
    创建函数对象保存函数定义
    函数名变量引用函数对象
    函数对象的scope属性,又指回了函数创建时的作用域

  3. 调用函数时
    在执行环境栈中添加了本次函数调用的记录
    创建本次函数调用的函数作用域对象AO
    在AO中添加函数的局部变量
    设置AO的parent指向函数的scope
    执行环境栈中的函数调用记录,引用AO
    变量的使用顺序: 先用局部,再用全局

  4. 函数调用后
    本次函数调用的记录从执行环境栈中出栈
    导致AO被释放, 导致所有局部变量都释放

25.作用域链:

什么是: 由多级作用域对象,逐级引用形成的链式结构
2个作用:

  1. 保存所有变量

  2. 控制着变量的使用顺序!

26.闭包closure:

什么是: 即重用一个变量,又保护变量不被污染的一种机制
为什么: 全局变量和局部变量都具有不可兼得的优缺点:
全局变量: 优: 可重用, 缺: 易被污染
局部变量: 优: 仅函数内可用,不会被污染

缺: 不可重用!

何时: 只要一个变量,可能被重用,又不想被篡改
如何: 3步:

  1. 用外层函数包裹要保护的变量和内层函数

  2. 外层函数将内层函数返回到外部

  3. 调用外层函数,获得内层函数的对象,保存在外部的变量中——形成了闭包

闭包形成的原因: 外层函数调用后,外层函数的函数作用域对象无法释放
主动使用闭包: 为一个函数绑定一个专属的变量
鄙视: 画简图

  1. 找受保护的变量,并确定其最终值

  2. 找内层函数对象
    外层函数向外返回内层函数对象: 3种:

    1. return function(){}

    2. 全局变量=function(){}

    3. return arr/obj{function(){...}}

27.OOP

什么是对象: 内存中存储多个数据的独立存储空间都称为一个对象。
什么是面向对象: 程序中都是用对象结构来描述现实中一个具体事物。
为什么: 为了便于大量数据的维护和查找
何时: 几乎所有js程序,都使用面向对象的方式开发
如何: 三大特点: 封装,继承,多态
封装: 用对象来集中描述现实中一个具体事物的属性和功能
为什么: 便于维护和查找
何时: 今后只要使用面向对象的方式开发,都要先封装对象,再按需使用对象的属性和功能。
如何: 3种:

  1. 用{}: 
    var obj={
    属性名:值,

    ... : ... ,

    //方法名:function(){...},
    方法名 (){...},
    }
    其中: 事物的属性值会成为对象的属性

        对象的属性本质是保存在对象中的一个变量
    事物的功能会成为对象的方法!
    方法的本质是保存在对象中的一个函数

    如何访问对象的成员: 
    访问对象的属性: 对象.属性名
    调用对象的方法: 对象.方法名()
    问题: 对象自己的方法中要使用对象自己的属性
    错误: 直接用属性名,报错: 找不到变量

    为什么: 默认,不加.就使用的变量,只能在作用域链中查找,无法自动进入对象中

    解决一: 对象名.属性名

    问题: 对象名仅是一个普通的变量名,可能发生变化。

    正确解决: this.属性名
    this: 自动指正在调用当前方法的.前的对象

    为什么: 不受对象名变量的影响
    何时: 只要对象自己的方法向访问对象自己的属性时,都必须加this.

js中对象的本质,其实就是一个关联数组

  1. 用new: 
    var obj=new Object(); //创建空对象 等效于{}
    obj.属性名=值;
    obj.方法名=function(){
    ... this.属性名 ...
    }

和关联数组一样,js中的对象也可随时添加新属性和方法。
问题: 反复创建多个相同结构的对象时,重复代码太多,导致不便于维护
解决:

  1. 用构造函数:
    构造函数: 描述一类对象统一结构的函数
    为什么: 为了重用结构代码!
    何时: 只要反复创建相同结构的多个对象时,都用构造函数
    如何: 2步:

    1. 定义构造函数
      function 类型名(属性参数列表){
      this.属性名=属性参数;
      this. ... = 属性参数;
      this.方法名=function(){

      this.xxx

      }
      }

    2. 调用构造函数创建新对象
      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种:

  1. 判断原型对象: 
    obj.__proto__==Array.prototype
    Array.prototype.isPrototypeOf(obj)

  2. 判断构造函数:
    obj.constructor==Array
    obj instanceof Array

问题: 不严格, 不但检查直接父对象,且检查整个原型链

  1. 判断对象内部的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.多态:

什么是: 一个方法在不同情况下表现出不同的状态
包括:

  1. 重载overload:

  2. 重写override: 
    什么是: 如果子对象觉得从父对象继承来的成员不好用,可在本地定义同名的自有成员,覆盖父对象的成员
    为什么: 觉得从父对象继承来的成员不好用
    何时: 只要觉得从父对象继承来的成员不好用
    如何: 在本地定义同名的自有成员

32.自定义继承:

  1. 只修改一个对象的父对象
    obj.__proto__=father
    Object.setPrototypeOf(obj,father)

  2. 修改所有子对象的父对象:
    构造函数.prototype=father
    时机: 在创建子对象之前换!

  3. 两种类型间的继承: 
    何时: 发现多个类型之间拥有部分相同的属性结构和方法定义时,都要抽象父类型出来
    如何: 2步:

    1. 在子类型构造函数中借用父类型构造函数
      错误: 直接调用: Flyer(fname,speed)
      原因: Flyer不用.不用new调用,其中的this默认指window,Flyer中所有属性泄露到全局
      正确: 用call将正确的this注入到Flyer中,代替错误的this
      如何: Flyer.call(正确的this, fname,speed)

    2. 让子类型原型对象继承父类型原型对象
      Object.setPrototypeOf(子类型原型,父类型原型)

    3. 定义构造函数保存公共的属性结构

    4. 定义原型对象保存公共的方法

    5. 定义抽象父类型: 2步:

    6. 让子类型继承父类型: 2步:

33.ECMAScript6

  1. 严格模式:
    什么是: 比普通js运行机制要求更严格的模式
    为什么: 普通的js运行机制有很多广受诟病的缺陷
    何时: 今后所有项目必须运行在严格模式下

    1. 如果新项目,整个js文件启用严格模式

    2. 旧项目,逐个函数启用严格模式

如何:

  1. 在script或整个js文件顶部,添加"use strict";

  2. 在函数内顶部,添加"use strict";

规则: 4个:

  1. 禁止给未声明的变量赋值

  2. 将静默失败升级为错误

  3. 普通函数或匿名函数自调中的this默认不再指向window,而是undefined

  4. 禁止使用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种

  1. 防扩展: 禁止给对象添加新属性
    Object.preventExtensions(obj)
    原理: 内部属性: extensible:true

    preventExtensions将extensible改为false
  2. 密封: 在防扩展同时,禁止删除现有属性
    Object.seal(obj)
    原理: 1. 将extensible改为false,禁止扩展

    2. 自动将所有属性的configurable都改为false
  3. 冻结: 在密封的同时,禁止修改一切属性值
    Object.freeze(obj)
    原理: 1. 兼具密封的所有功能

     2. 又将每个属性的writable自动改为false!
  1. Object.create()
    仅用父对象,就可创建子对象, 
    同时还可为子对象扩展自有属性
    var child=Object.create(father,{
    //Object.defineProperties
    属性名:{

    特性:值,
    特性:值,

    }
    })
    鄙视: 描述Object.create的执行原理

    1. 创建空对象child

    2. 自动设置child的__proto__为father

    3. 为child扩展新的自有属性

35.call/apply/bind

替换函数中不想要的this!
call/apply: 立刻调用函数,并临时替换中的this为指定对象
何时: 只要调用函数时,函数中的this不是想要的就用call换成想要的
如果传入函数的参数,是以数组形式,整体传入
就用.apply(obj,arr)
bind: 基于原函数,创建一个新函数,并永久绑定this为指定对象
何时: 不会立刻调用的函数(回调函数)中的this,不是想要的,就可用bind创建一个新函数,并永久绑定this!

36.数组API:

判断:

  1. 判断数组中所有元素是否都符合条件
    arr.every(function(elem,i,arr){

    //elem: 当前元素值
    //i: 当前位置
    //arr: 当前数组对象
    return 判断条件

    })

  2. 判断数组中是否包含符合条件的元素
    arr.some(function(elem,i,arr){

    return 判断条件

    })

遍历:

  1. forEach: 对原数组中每个元素执行相同的操作
    arr.forEach(function(elem,i,arr){
    arr[i]=新值
    })

  2. map: 依次取出原数组中每个元素执行相同操作后,放入新数组。原数组不变
    arr.map(function(elem,i,arr){
    return 新值
    })

过滤和汇总:

  1. 过滤: 复制出原数组中符合条件的元素,放入新数组返回
    var subs=arr.filter(function(elem,i,arr){
    return 判断条件
    })

  2. 汇总: 将原数组中所有值统计出一个最终结论
    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的缺点:

  1. 类数组对象,不是数组

  2. 只能后去全部,不能有选择的分段获取

如何: 定义函数时: function fun(参数1,参数2,..., ...数组名)
数组名, 是一个纯正的数组,且可有选择的分段获取
原理: var arr=[].slice.call(arguments[,starti]);//将类数组对象转为数组
spread: 代替apply
为什么: apply虽然可打散数组类型参数为单个值,但是必须和替换this的操作捆绑使用
何时: 只要仅需要打散数组类型参数为单个值时
如何: 调用时: fun(参数值1,参数值2,...数组)

  1. 箭头函数: 代替回调函数中的function


何时: 只要回调函数,都不再使用function,而是使用箭头函数
如何:

  1. 去function改=>

  2. 如果只有一个参数,可省略()

  3. 如果函数体只有一句话,则{}可省略

    更简化: 如果仅有的一句话还是return,可省略return

特点: 内外共用同一个this ——代替bind
问题: 如果反而希望内外this不通用时,就不能用箭头函数

40.模板字符串: 代替+号拼接字符串

ESLint规定,不允许使用+拼接字符串
如何:

  1. 定义模板: 左右模板内容都必须放在``中

  2. 在模板中嵌入变量或表达式,动态生成内容:
    模板内,可用${...}嵌入任何合法的js变量或语句

41.解构: 简化批量赋值

什么是: 将一个对象/数组中的成员和元素,分别提取出来,单独使用。
为什么: 避免反复使用对象名/数组名
何时: 只要希望将一个大的对象或数组中的每个成员单独取出使用时
如何: 3种:

  1. 数组解构: 下标对下标

  2. 对象解构: 属性对属性

  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(第三件事)

鄙视题:

  1. 将类数组对象复制为数组:
    var arr2=Array.prototype.slice.call(arguments)
    将类数组对象复制为数组,并选取指定位置的剩余元素
    var arr2= Array.prototype.slice.call(arguments,starti)

    相当于arguments.slice(starti)

    其实更简单的: var arr2= [].slice.call(arguments,starti)

  2. promise中的错误处理:
    其实: new Promise(可接收2件事)

    .then( ) .catch( )

    new Promise((正常函数,出错函数)=>{

    如果顺利执行:
    调用正常()
    否则
    调用出错()

    })

  3. 等待多个任务完成
    前提: 每个任务都必须都返回Promise
    如何: Promise.all([

       task1(), task2(),...
    ]).then(()=>{所有任务完成后才执行的任务})

最后

  • 欢迎加我微信(qzpope),拉你进技术群,长期交流学习...

  • 欢迎关注「科技前沿技术群」,认真学前端,做个有专业的技术人...

9fc95fe0cc898ee8b0246e85627f71a8.png 点个在看支持我吧,转发就更好了

好文我在看

3604af59f3cbc084f46afd997fef12b8.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值