• 【JS高级】ES6_模板字符串、let的简谈与应用_12


    目录

    一. 模板字符串

    1. 什么是模板字符串

    2. 为什么使用模板字符串

    3. 何时使用模板字符串

    4. 如何使用模板字符串

    5. 总结: ${}中能放什么,不能放什么?

    6. 示例: 使用模板字符串动态拼接字符串内容

    二. let

    1. 存在问题

    2. 示例:var缺点对程序的影响

    3. 解决办法

    4. let的优点: 2个

    5. 示例: 用let代替var

    6. 原理: 新瓶装旧酒

    7. 这才是真相

    8. 示例:let效果的替代方式

    9. let的小脾气

    10. 示例: 演示let的小脾气

    💥 扩展:this判断—8种指向

    💠 总结:知识点提炼 


    🆙【前文回顾】👉  ES5标准规范之数组高阶函数的应用_11


    一. 模板字符串

    1. 什么是模板字符串

    支持换行和动态生成内容的特殊字符串

    2. 为什么使用模板字符串

    因为+本意是算术计算中的加法计算,如果拼接字符串也用+,就会和算术计算的加法混淆或冲突

    3. 何时使用模板字符串

    今后只要一个字符串的内容包含需要根据变量动态生成的部分,都要用模板字符串代替+来动态生成字符串。

    4. 如何使用模板字符串

             (1). 整个字符串要用一对儿反引号``包裹

             (2). 在``中支持', "", 换行等。

             (3). 在``中凡是需要根据变量动态生成的部分内容都要用${}包裹

    5. 总结: ${}中能放什么,不能放什么?

             (1). ${}中能放什么: 变量、算术计算、三目、调用函数、创建对象、访问数组元素——所有有返回值的合法的js表达式都可以放在${}中

             (2). ${}中不能放什么: 程序结构(分支和循环)以及没有返回值的js表达式。

    6. 示例: 使用模板字符串动态拼接字符串内容

    5_templateString.html ⏬

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    6. <title>Documenttitle>
    7. head>
    8. <body>
    9. <script>
    10. var uname="dingding";
    11. console.log(`Welcome ${uname}`);
    12. var sex=1;
    13. console.log(`性别: ${sex==1?"男":"女"}`);
    14. var price=12.5;
    15. var count=5;
    16. //.toFixed(2)保留两位小数四舍五入
    17. console.log(`
    18. 单价: ¥${price.toFixed(2)}
    19. 数量: ${count}
    20. ====================
    21. 小计: ¥${(price*count).toFixed(2)}
    22. `);
    23. var orderTime=1602309995261;
    24. console.log(`下单时间: ${new Date(orderTime).toLocaleString()}`);
    25. var arr=[
    26. "日","一","二","三","四","五","六"
    27. // 0 1 2 3 4 5 6
    28. ]
    29. var d=new Date().getDay();
    30. // 6
    31. console.log(`今天星期${arr[d]}`);
    32. // 六
    33. script>
    34. body>
    35. html>

    运行结果:

    Welcome dingding

    性别: 男

        单价: ¥12.50

        数量: 5

        ====================

        小计: ¥62.50

       

    下单时间: 2020/10/10 下午2:06:35

    今天星期六 

    二. let

    1. 存在问题

    旧js中声明变量都用var,但是var有两个广受诟病的缺陷:

             (1). 会被声明提前——打乱了程序正常的执行顺序

             (2). 没有块级作用域:

             a. 块级作用域: 除了函数以外的if,else,else if,while等分支和循环结构的{}范围。

             b. 在旧js中,分支结构和循环结构的{}都不是作用域。

             c. 导致{}内的变量,会影响{}外部的变量!

    2. 示例:var缺点对程序的影响

    示例: 演示var的两个缺点对程序的影响——一段压根不会执行的代码,破坏了原本正常执行的代码

    番外:我们先来看一个正常执行的程序

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    6. <title>Documenttitle>
    7. head>
    8. <body>
    9. <script>
    10. var t=0;//在全局定义一个变量,累加每个函数的执行时间
    11. //定义函数时,其实只是在内存中创建一个函数对象,保存一段代码段而已,并不会立刻执行函数中
    12. //的代码段。只有调用时才会执行函数体内的代码,详情可参看函数的原理。
    13. //所以,函数此时在这里是不会执行的,因为还未调用,这里只是定义函数
    14. function fun1(){
    15. console.log(`fun1执行耗时0.3s`);
    16. t+=0.3;
    17. }
    18. function fun2(){
    19. console.log(`fun2执行耗时0.8s`);
    20. t+=0.8;
    21. }
    22. //函数fun1和函数fun2只有在调用时才会执行fun1和fun2的函数体代码
    23. //t+=0.3 → t=0+0.3=0.3
    24. fun1();//t+=0.3
    25. //t+=0.8 → t=0.3+0.8=1.1,这是t的最终值
    26. fun2();//t+=0.8
    27. console.log(`共耗时${t}s`);//0.3+0.8=1.1
    28. script>
    29. body>
    30. html>

    运行结果:

    fun1执行耗时0.3s

    fun2执行耗时0.8s

    共耗时1.1s 

    6_var.html ⏬

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    6. <title>Documenttitle>
    7. head>
    8. <body>
    9. <script>
    10. var t=0;//在全局定义一个变量,累加每个函数的执行时间
    11. function fun1(){
    12. console.log(`fun1执行耗时0.3s`);
    13. t+=0.3;
    14. }
    15. function fun2(){//是作用域,拦住var t;
    16. //var t;//被提前到这里
    17. //结果fun2中从此就有了局部变量t
    18. console.log(`fun2执行耗时0.8s`);
    19. t+=0.8;//0.8会优先加给局部变量t,不再加个全局的t。
    20. //在某次代码更新过程中,无意中添加了以下代码
    21. //不会执行的代码
    22. if(false){//不是作用域!限制不住var t
    23. //虽然这段代码不会执行,但是声明提前是在代码执行之前就会发生的
    24. //var t会被声明提前,t=new Date()留在原地
    25. var t=new Date();
    26. console.log(`今天是${t.toLocaleString()}`);
    27. }
    28. }
    29. //t+=0.3 → t=0+0.3=0.3
    30. fun1();//t+=0.3
    31. //t+=0.8 → t=t+0.3=NaN
    32. fun2();//t+=0.8
    33. //只能输出全局的t=0.3————因为调用fun2时,0.8优先加给了局部变量t,局部变量t只能在fun2内使用用
    34. console.log(`共耗时${t}s`);//t=0.3
    35. script>
    36. body>
    37. html>

    运行结果:

    fun1执行耗时0.3s

    fun2执行耗时0.8s

    共耗时0.3s 

    3. 解决办法

    今后所有变量的声明都要用let代替var。如果是常量的声明,就用const。

    4. let的优点: 2个

             (1). 不会被声明提前!

             (2). 让分支结构和循环结构的{}也变成一级作用域——块级作用域。块内的变量,不会跑到块外影响外部的程序!

    5. 示例: 用let代替var

    7_let.html ⏬

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    6. <title>Documenttitle>
    7. head>
    8. <body>
    9. <script>
    10. var t=0;//在全局定义一个变量,累加每个函数的执行时间
    11. function fun1(){
    12. console.log(`fun1执行耗时0.3s`);
    13. t+=0.3;
    14. }
    15. function fun2(){//是作用域,拦住var t;
    16. console.log(`fun2执行耗时0.8s`);
    17. t+=0.8;//程序执行到这里时,还不知道if(){}块内还有一个t变量,所以这里的t+=0.8,是加到全局变量t上的!
    18. //在某次代码更新过程中,无意中添加了以下代码
    19. //不会执行的代码
    20. if(false){//let让if后的{}也成为一级作用域,就能拦住变量t,不影响外部!
    21. //let不会被声明提前
    22. let t=new Date();
    23. console.log(`今天是${t.toLocaleString()}`);
    24. }
    25. }
    26. fun1();//t+=0.3
    27. fun2();//t+=0.8
    28. console.log(`共耗时${t}s`);//0.3+0.8=1.1
    29. script>
    30. body>
    31. html>

    运行结果:

    fun1执行耗时0.3s

    fun2执行耗时0.8s

    共耗时1.1s 

    6. 原理: 新瓶装旧酒

             (1). 可能在底层自动给重名的变量改名,来避免冲突(参看示例8_function.html 

             (2). 可能在底层自动添加匿名函数自调,来限制变量的提前!(参看示例8_function.html

    7. 这才是真相

    其实: let并没有让分支和循环的{}真的成为块级作用域:

             if(...){

                      let t=...; //会留在原地,不会提前,不会影响外部

                      var a=...;//依然会被提前,会超出if的范围,影响外部!

             }

    8. 示例:let效果的替代方式

    示例: 通过修改变量名或匿名函数自调来实现和let相同的效果:

    8_function.html ⏬

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    6. <title>Documenttitle>
    7. head>
    8. <body>
    9. <script>
    10. var t=0;//在全局定义一个变量,累加每个函数的执行时间
    11. function fun1(){
    12. console.log(`fun1执行耗时0.3s`);
    13. t+=0.3;
    14. }
    15. function fun2(){//是作用域
    16. //var _t;//因为变量名不同,所以对t+=0.8没有影响
    17. console.log(`fun2执行耗时0.8s`);
    18. t+=0.8;
    19. //在某次代码更新过程中,无意中添加了以下代码
    20. //不会执行的代码
    21. if(false){//不是作用域
    22. //两个办法: 不用let实现限制变量提前的方法
    23. //1. 修改变量名
    24. //把全局变量t直接换个名字就行了,虽然_t提前,但是不影响t
    25. //var _t=new Date();
    26. //2. 匿名函数自调方式,划分临时作用域
    27. (function(){//是作用域
    28. var t=new Date();
    29. console.log(`今天是${t.toLocaleString()}`);
    30. })();
    31. var a=10;
    32. }
    33. }
    34. fun1();//t+=0.3
    35. fun2();//t+=0.8
    36. console.log(`共耗时${t}s`);//0.3+0.8=1.1
    37. script>
    38. body>
    39. html>

    运行结果:

    fun1执行耗时0.3s

    fun2执行耗时0.8s

    共耗时1.1s 

    9. let的小脾气

             (1). 不会被声明提前,所以不允许提前使用let声明的变量!

             (2). 在同一作用域内,不能重复let两个同名的变量

             (3). 即使在全局用let声明的变量,在window中也是找不到的!

        因为let底层相当于匿名函数自调,(function(){let a=2})(),所以用let声明的变量就成了局        部变量,因此全局是没有的

    10. 示例: 演示let的小脾气

    9_let2.html ⏬

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    6. <title>Documenttitle>
    7. head>
    8. <body>
    9. <script>
    10. //var a;
    11. console.log(a);//undefined
    12. var a=10;
    13. //尝试在let b之前使用变量b
    14. //console.log(b);//报错:Cannot access 'b' before initialization
    15. //不能在初始化b变量之前使用b变量
    16. //首次声明并赋值,称作一次变量的初始化
    17. //let b=10;
    18. console.log(window.a);//10
    19. //(function(){
    20. let c=10;
    21. //尝试在let c之后重复let c
    22. //let c=100;//报错: Identifier 'c' has already been declared
    23. //变量c已经被声明过了!
    24. //尝试输出window中的c变量,查看let c是否会添加到全局window对象中。
    25. console.log(window.c);//undefined
    26. //})()
    27. script>
    28. body>
    29. html>

    运行结果:

    undefined

    10

    undefined 


    💥 扩展:this判断—8种指向

    this  8种指向: 判断this,一定不要看定义在哪儿!只看调用时!

    1. obj.fun()   this->obj

    2. fun() 或 (function(){ ... })() 或 多数回调函数 或 定时器函数   this->window

    3. new Fun()   this->new正在创建的新对象

    4. 类型名.prototype.共有方法=function(){ ... }   this->将来谁调用指谁,同第一种情况

    5. DOM或jq中事件处理函数中的this->当前正在触发事件的DOM元素对象

                                   如果需要使用简化版函数,必须$(this)

    6. 箭头函数中的this->箭头函数外部作用域中的this

    7. jQuery.fn.自定义函数=function(){ ... }   this->将来调用这个自定义函数的.前的jQuery子对象,不用再$(this)

    8. new Vue()中methods中的函数中的this->当前new Vue()对象


    💠 总结:知识点提炼 

    1. 只要验证字符串格式或查找、屏蔽敏感词时都要用正则

    (1). 最简单的正则: 一个敏感词的原文

    (2). 某一位字符上可能有多种备选字时用: [备选字列表]

    (3). 如果[]中部分字符是连续的,可用: [x-x]

             a. 一位小写字母: [a-z]

             b. 一位大写字母: [A-Z]

             c. 一位字母(大小写都行): [A-Za-z]

             d. 一位字母或数字都行: [0-9A-Za-z]

             e. 一位汉字: [\u4e00-\u9fa5]

    (4). 预定义字符集:

             a.  \d 一位数字

             b.  \w 一位数字、字母或_

             c.  \s  空格、tab、换行等空字符

             d.  .   任意字符

    (5). 如果规定一个字符集或子规则反复出现的次数时就用量词:

             a. 有明确数量边界的量词:

          1). {n}  =n 必须n个,不能多也不能少

          2). {n,m}  n个<=    <=m个

          3). {n,}    n个<=   多了不限

             b. 没有明确数量边界的量词:

          1). *   0个<= 可有可无,多了不限

          2). ?   0个或1个  可有可无,最多一个

          3). +   1个<=  至少一个,多个不限

    (6). 两个规则中选其一匹配即可: 规则1|规则2

    (7).希望将多个子规则分为一组先联合匹配,再和分组外的其他规则联合匹配:

      (多个子规则)

    (8). 匹配特殊位置: 3个

             a. 字符串的开头位置: ^

             b. 字符串的结尾位置: $

             c. 英文句子中的单词的左右边界: \b

    2. String家提供的正则相关函数: 3件事

    (1). 查找敏感词: 4种情况

          a. 查找一个固定的敏感词出现的位置:
             var i=str.indexOf("敏感词")

             // 如果找不到,返回-1

          b. 用正则查找多种敏感词出现的位置:
             var i=str.search(/正则/i)

             // 如果找不到,返回-1

          c. 查找敏感词的内容:

          1). 查找第一个敏感词的内容和位置:
          var arr=str.match(/正则/i)

          // arr: [ 0:"敏感词内容", index:敏感词位置 ]

          // 如果找不到返回null

          2). 查找所有敏感词的内容,不关心位置:
          var arr=str.match(/正则/ig)

          // arr: [ 敏感词1, 敏感词2, ...  ]

          // 如果找不到返回null

         d. 查找每个敏感词的内容和位置: reg.exec

    补: js中所有数组底层本质都是关联数组(下标都为字符串)

    1. 访问数组中元素值的标注写法:

      arr["下标"]

    2. 简写:

      a. 如果下标为自定义字符串名称,可简写为:

      arr.自定义名称的下标

      b. 如果下标为数字内容的字符串,可简写为:

      arr[数字下标]

    总结: 查找方法的返回值规律

    1. 如果原函数返回的是下标位置i,如果找不到,都返回-1

    2. 如果原函数返回的是一个数组arr或一个对象obj,如果找不到,都返回null

    3. 如果原函数返回类数组对象,如果找不到返回空类数组对象:

       { length:0 }

    (2). 替换敏感词: 2种

             a. 简单替换:
             变量=str.replace(/正则/ig, "新值")

             b. 高级替换:
             变量=str.replace(/正则/ig, function(形参){

                   return 根据本次敏感词动态生成一个新值

             })

             c. 删除敏感词:
             变量=str.replace(/正则/ig, "")

    (3). 切割字符串:

             a. 简单切割:
             var arr=str.split("切割符")

             b. 复杂切割:
             var arr=str.split(/正则/i)

             c. 打散字符串为字符数组:
             var arr=str.split("")

    3. RegExp对象: 

             (1). 创建正则表达式对象:

             a. 如果正则是固定的:
             var reg=/正则/ig

             b. 如果正则需要动态生成:
             var reg=new RegExp("正则",ig)

             (2). 验证字符串格式:
             var bool=reg.test(str)
             reg必须同时前加^后加$

             (3). 既查找每个关键词的内容又查找每个关键词的位置: (待续)

             do{

                   var arr=reg.exec(str);

                   if(arr!=null){

                                  获得本次找到的敏感词的内容(arr[0])和位置(arr.index)

                   }

             }while(arr!=null);

    4. 函数: 

    (1). 创建函数三种方式:

             a. function 函数名(形参列表){ 函数体; return 返回值 } //会被声明提前,不好

             b. var 函数名=function(形参列表){ 函数体; return 返回值 }//不会被声明提前,首选

             c. var 函数名=new Function("形参1", "形参2", ... , "函数体; return 返回值")

    函数本质:

      1). 函数也是一个对象,对象中保存着函数的函数体代码

      2). 函数名只是一个普通的变量,函数名通过函数对象地址,引用着函数对象

      3). function在底层等效于new Function()

        function 函数名(){ ... }和var 函数名=function(){}在底层都会被翻译为

        var 函数名=new Function(...)

        只不过function 函数名(){}是先提前,再翻译

        而var 函数名=function(){}是不提前,原地翻译

    (2). 重载: 今后,一件事,根据传入不同的参数值,动态执行不同的逻辑时,都用重载

    function 一个函数名(不写形参变量){

      //arguments对象自动接住所有实参值

      if(arguments.length==0){

        执行一种逻辑

      }else if(arguments.length==1){

        执行另一种逻辑

      }else{

        执行其它逻辑

      }

    }

    其中arguments是类数组对象: 和数组相比:

             a. 相同点: 也有下标,length属性,也可for循环遍历

             b. 不同点: 不是数组类型,无法使用数组家的函数

    (3). 匿名函数:

             a. 所有回调函数优先使用匿名函数——用完释放,节约内存

             b. 所有js代码都应该保存在匿名函数自调中,禁止使用全局变量,避免全局污染!

             (function(){

                   要执行的js代码

             })();

             结果: 匿名函数内的都是局部变量,不会产生全局变量。

             局部变量随匿名函数一起释放。不会污染全局。

    (4). 作用域和作用域链: (跟着视频亲自画图!!!)

             a. 作用域:

             1). 全局作用域:window,保存全局变量

             优: 可重用,缺: 随处可用, 极易被污染

             2). 函数作用域: 保存局部变量

             局部变量包括2中: 函数中var出的变量和形参变量

             优: 仅函数内可用,不会被污染,缺: 不可重用

             3). 函数作用域对象原理:

                   i. 每个函数定义时都自带好友列表,好友列表里2个格子,一个是空,一个引用window

                   ii. 调用函数时临时创建函数作用域对象保存函数局部变量。并将函数作用域对象的地址保存到函数好友列表中离自己近的格子里。

                   iii. 函数执行过程中按就近原则先在自己的函数作用域对象中找局部变量使用。如果找不到,才被迫去全局window中找变量使用.

                   iv. 函数调用后,好友列表中离自己近的格子清空,导致函数作用域对象以及内部的局部变量被释放!——所以局部变量不可重用!

             b. 作用域链: 保存一个函数所有可用的作用域对象的链式结构(好友列表)学名就叫作用域链。
             1). 作用域链保存着一个函数可用的所有变量

             2). 作用域链控制着变量的使用顺序。先局部后全局。

    5. 闭包:  
             a. 只要希望给一个函数保护一个可反复使用的专属变量,又防止这个变量被外界篡改时,都用闭包。

             b. 闭包三步:

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

          2). 外层函数妈妈用return把内层函数孩子返回到外部

          3). 外部想使用内层函数的人,必须调用外层函数,才能获得return出来的内层函数对象。并将内层函数保存在一个变量中反复使用。

             c. 闭包形成的原因: 外层函数调用后,外层函数的作用域对象被内层函数引用着无法释放,形成了闭包对象

             d. 闭包的缺点: 闭包比一般的函数占用多一块内存——外层函数的函数作用域对象。所以,用完闭包后,应该尽快释放:
          保存内层函数的变量=null

    6. 面向对象: 封装 继承 多态

    (1). 封装: 3种:

             a. 用{}创建一个对象:

             var 对象名={

                   属性名:属性值,

                   ... : ... ,

                   方法名: function(){

                                  ... this.属性名 ...

                   }

             }

             b. 用new Object():

             1). 2步:

                   i. var 对象名=new Object()

                   ii. 对象名.属性名=属性值;

                                   对象名.方法名=function(){ ... }

             2). 对象底层也是关联数组:

                   i. 都是名值对儿的集合

                   ii. 都可用[""]和.方式访问成员。

                                   如果属性名来自于变量,就只能用[],不要加""

                   iii. 访问不存在的属性,都不报错,返回undefined

                                   判断是否包含某个属性:

                               对象.属性名!==undefined

                   iv. 强行给不存在的属性赋值,都不报错,而是自动添加该属性

                                   给对象添加新属性,唯一办法,强行赋值:

                               对象名.新属性名=新值

                   v. 都可用for in遍历

             c. 只要反复创建多个相同结构的对象都用构造函数:

             1). 2步:

                   i. 定义构造函数:

                   function 类型名(形参1,形参2, ...){

                                  this.属性名1=形参1;

                                  this.属性名2=形参2;

                                  //构造函数中不要再包含方法定义定义!

                   }

                   ii. 用new 调用构造函数:

                   var 对象名=new 类型名(属性值1, 属性值2,...)

             2). new做了4件事:

                   i. 创建一个新的空对象

                   ii. 让新对象继承(_ _proto_ _)构造函数的原型对象

                   iii. 调用构造函数,传入实参,并自动替换构造函数中的this为new正在创建的新对象。构造函数中,通过强行赋值的方式为新对象添加规定的属性,并保存属性值。

                   iv. 返回新对象的地址,保存到=左边的变量中。

            3). 优点: 重用对象结构代码

            4). 缺点: 如果构造函数中包含方法定义,则每次创建新对象都会重复创建相同方法的副本。             ——浪费内存!

    (2). 继承: 

             a. 今后,只要同一类型所有子对象共用的方法和属性值,都要集中保存在构造函数的原型对象中!

          构造函数.prototype.属性名/共有方法名=属性值/function(){ ... }

             b. 自有属性和共有属性:

            1). 获取属性值:都可用"子对象.属性名"

            2). 修改属性值:

                   i. 自有属性: 子对象.自有属性名=新值

                   ii. 共有属性: 构造函数.prototype.共有属性名=新值

            c. 内置类型原型对象:

          1). 11种内置类型/对象: String, Number, Boolean, Array, Date, RegExp, Math(对象), Error, Function, Object, global(对象)

            2). 一种类型=构造函数+原型对象

                   i. 构造函数: 创建子对象

                   ii. 原型对象: 为所有子对象保存共有成员

            3). 查看该类型共有哪些API: 类型名.prototype

            4). 该类型缺少想用的方法: 类型名.prototype.共有新方法=function(){ ... }

            d. 原型链: 保存着一个对象可用的所有属性和方法。控制着属性和方法的使用顺序:先自有再共有——就近原则!

    (3). 多态 

    重点讲重写:如果子对象觉得从父对象继承来的成员不好用,可以在子对象自己内部重写和父对象同名的成员,覆盖父对象的成员,优先使用自己的。

    ******面向对象终极总结: 封装,继承,多态******

    ①封装: 创建对象,2种:

      如果只创建一个对象: {}

      如果反复创建多个相同结构的对象: 构造函数

    ②继承: 所有子对象共用的属性值和方法,都要放在构造函数的原型对象中

    ③多态: 重写: 只要觉得从父对象继承来的成员不要用,都在子对象中重写同名成员

    ④如果觉得这个父对象对象都不好用,可以自定义继承: 2种:

      1). 只换一个子对象的父对象: 2种:

      i. 子对象.__proto__=新父对象

      ii. Object.setPrototypeOf(子对象, 新父对象)

      2). 更换多个子对象的原型对象: 构造函数.prototype=新对象

    ********************************************************************

    7. 严格模式: "use strict"; 

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

    (2). 静默失败升级为错误

    (3). 普通函数调用中的this不指window,而是指undefined

    (4). 禁用arguments.callee

    总结: this 判断this时,一定不要看他定义在哪儿。必须看它在哪里以何种方式调用 4种:

    1. obj.fun()  this->点前的obj对象

    2. fun()  this->默认指window

    3. new Fun()   this->new正在创建的新对象

    4. 类型名.prototype.共有方法=function(){ ... } 

             this->将来谁调用这个函数,就指谁

             将来调用这个函数的.前的某个子对象

    8. 保护对象: 

    (1). 保护属性:

             a. 每个属性包含三个开关:

          1). writable: 控制是否可修改属性值

          2). enumerable: 控制着是否可被for in遍历到,但是只防for in不防.

          3). configurable: 控制

                   i. 是否可删除当前属性

                   ii. 是否可修改writable和enumerable两个开关

                          强调: configurable一旦改为 false,不可逆!

             b. 只修改一个属性的多个开关:

          Object.defineProperty(对象名, "属性名",{开关: true/false})

             c. 修改多个属性的多个开关:

          Object.defineProperties(对象名,{

                          属性名:{ 开关:true/false, ... },

                          ... : ...

          })

             d. 如果用自定义的规则保护属性时,只能用访问器属性: 2步:

          Object.defineProperties(对象,{

          //1). 先定义一个隐姓埋名且半隐藏的数据属性:

                   _属性名:{

                                  value: 属性的初始值,

                                  writable:true,

                                  enumerable:false,

                                  configurable:false

                   },

          //2). 再定义访问器属性保镖冒名顶替要保护的属性

                   属性名:{

                                  get:function(){

                                return this._属性名

                                  },

                                  set:function(value){ //value ← 要修改的新属性值

                                先验证value

                                如果验证通过,this._属性名=value

                                否则如果验证未通过,不但不保存新属性值,还会报错

                                  },

                                  enumerable:true,

                                  configurable:false

                   }

             })

             外界使用访问器属性时和使用普通属性一样:

             对象.属性名

             外界试图获取访问器属性值时,自动调用get()

             外界试图修改访问器属性值时,自动调用set()

    (2). 保护结构: 3个级别

             a. 防扩展: Object.preventExtensions(对象)

             b. 密封: Object.seal(对象)

             c. 冻结: Object.freeze(对象)

    9. 如果没有构造函数,也想创建子对象,继承父对象: 

    var 新子对象=Object.create(父对象,{

      自有属性:{

        value:属性值,

        开关:true或false,

        ... :...

      },

      ... : { ... }

    })

    10. 替换this: 3种: 

    (1). 在一次调用函数时,临时替换this,首选:
      函数.call(对象, 实参值,...)

    (2). 临时替换一次this,但是需要打散数组再传参时,被迫改为:

      函数.apply(对象, 数组)

    (3). 创建一个一模一样的新函数并永久绑定this和部分实参值:

      var 新函数名=原函数.bind(对象, 固定实参值, ...)

    11. 数组函数: 

    (1). 判断:

             a. 判断数组中是否所有元素都符合要求:

          var bool=arr.every(function(value,i,arr){

                          return 判断条件

          })

             b. 判断数组中是否包含符合要求的元素:

          var bool=arr.some(function(value,i,arr){

                          return 判断条件

          })

    (2). 遍历:

             a. 单纯简化for循环变量原数组中每个元素:

          arr.forEach(function(value,i,arr){

                          对当前元素执行操作

          })

             b. 保护原数组不变,返回遍历加工后的新数组

          var 新数组=arr.map(function(value, i,arr){

                          return 加工后的一个新元素值

          })

    (3). 过滤: 复制出数组中符合要求的元素放入新数组返回

      var 新数组=arr.filter(function(value,i,arr){

        return 判断条件

      })

    (4). 汇总: 遍历数组中每个元素,经过求和或其他汇总方式,统计出一个最终结论

      var 结果=arr.reduce(function(box,value,i,arr){

        return box和value计算出的新临时汇总值

      }, 起始值)

    12. ES6: ⏬

    (1). 模板字符串: 今后,只要拼接字符串,都用模板字符串代替+:

             a. 整个字符串包裹在一对儿反引号`...`中

             b. 反引号``中支持换行、""、''均可使用

             c. 反引号中需要动态生成的内容必须放在${}里

             d. ${}里:

          1). 可以放一切有返回值的合法的变量或js表达式。

          2). 不能放程序结构(分支和循环)以及没有返回值的js表达式

    (2). let: 今后,声明变量都用let代替var

             a. let的好处:

          1). 阻止声明提前

          2). 让代码块(分支和循环的{})也变成块级作用域,{}块内的变量出了{}无法使用,不会影响外部

             b. let的小脾气:

          1). 在同一作用域内禁止重复声明;

          2). 禁止提前使用;

          3). 在全局声明也不保存在window中

    如果这篇【文章】有帮助到你,希望可以给【青春木鱼】点个👍,创作不易,相比官方的陈述,我更喜欢用【通俗易懂】的文笔去讲解每一个知识点,如果有对【前端技术】感兴趣的小可爱,也欢迎关注❤️❤️❤️青春木鱼❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💕💕!   

  • 相关阅读:
    VScode+python开发,多个解释器切换问题
    阿里巴巴中国站获得淘口令真实url API 返回值说明
    8.1标识框架
    工业制造体系模型(闻)
    从 iOS 设备恢复数据的 20 个iOS 数据恢复工具
    苹果的司法总监“知法犯法,监守自盗”,涉嫌操控股市被捕
    软件机器人助力企业产地证自动化申报,提高竞争力,降低成本
    windows 部署多个tomcat详细步骤
    性能评测 | GreatDB VIP PLUGIN方案 VS MySQL InnoDB Cluster高可用方案
    vivo 短视频用户访问体验优化实践
  • 原文地址:https://blog.csdn.net/sunyctf/article/details/125943837