65

前端知识点总结——JS高级(持续更新中)

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. 定义抽象父类型: 2步:

        1. 定义构造函数保存公共的属性结构
        2. 定义原型对象保存公共的方法
      2. 让子类型继承父类型: 2步:

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

    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(()=>{所有任务完成后才执行的任务})
      

    1. 47

    楷楷
    4k 声望10.5k 粉丝

    兴趣是最好的老师!