三.正则表达式与元字符以及this指向20-22 (P109-P119)

50 阅读9分钟

20 初识正则表达式

<body>
    <form action="">
        <input type="text" required id="mytext">
        <input type="email">
        <input type="submit" value="submit">
    </form>
    <script>
        //正则表达式

        // js复杂类型

        //1. 字面量 //

        var reg = /abc/ //检测一个字符串里是不是包含“abc”
        
        console.log(reg)
        //2. 内置构造函数 
        var reg2 = new RegExp("abc")
        console.log(reg2)


        mytext.onblur = function(){
            console.log(mytext.value)


            console.log(reg.test(mytext.value))
        }
    </script>
</body>

21 元字符

21-1 基本元字符

1. \d 一位数字(0-9)
2. \D 包含一位非数字
3. \s 1位空白 (空格 缩进 换行\n)
4. \S 1位 非空白
5. \w 字母 数字 下划线
6. \W 非字幕数字下划线
7. . 任意内容 (换行不算)
8 . \转义字符
 <script>
        // 1 \d 一位数字(0-9)

        // var reg = /\d/  //一位数字

        // console.log(reg.test("abc")) //false
        // console.log(reg.test("123")) //true
        // console.log(reg.test("1")) //true

        // var reg = /\d\d/  //两位数字
        // console.log(reg.test("1")) //false


        // 2 \D 包含一位非数字

        // var reg = /\D/ //一位

        // console.log(reg.test("123a")) //true
        // console.log(reg.test("123"))  //false
        // console.log(reg.test("1"))  //false
        
        // var reg = /\D\D/ //两位

        // var reg = /\Dk\D/ //一位非数字k一位非数字   
        // console.log(reg.test("aka")) //true
        // console.log(reg.test("aba")) //false


        // 3. \s 1位空白 (空格 缩进 换行\n)

        // var reg = /\s/

        // console.log(reg.test("12 3a"))  //true
        // console.log(reg.test("12    3a"))  //true
        // console.log("12\n3")  //12
                                 //3
        // console.log(reg.test("12\n3")) //true
        // console.log(reg.test("1"))  //false
        // console.log(reg.test("a ba"))  //true(tab键)


        // 4. \S 1位 非空白
        // var reg = /\S/

        // console.log(reg.test("12    3a")) //true
        // console.log(reg.test("       "))  //false
        // console.log(reg.test("\n\n\n"))  //false
        // console.log(reg.test("      "))  //false


        //5 \w 字母 数字 下划线

        // var reg = /\w/

        // console.log(reg.test("&*"))  //false
        // console.log(reg.test("12abc"))  //true
        // console.log(reg.test("a"))  //true
        // console.log(reg.test("1"))  //true
        // console.log(reg.test("_"))  //true

        // var reg = /\w\w/
        // console.log(reg.test("&*"))  //false
        // console.log(reg.test("12abc"))  //true
        // console.log(reg.test("a"))  //false
        // console.log(reg.test("1"))  //false
        // console.log(reg.test("_"))  //false


        //6. \W 非字幕数字下划线

        // var reg = /\W/
        // console.log(reg.test("&*"))  //true
        // console.log(reg.test("12abc"))  //false
        // console.log(reg.test("a"))  //false
        // console.log(reg.test("1"))  //false
        // console.log(reg.test("_"))  //false

        // var reg = /\W\W/
        // console.log(reg.test("&"))  //false


        //7  . 任意内容 (换行不算)

        // var reg = /./

        // console.log(reg.test("%^*#$"))  //true
        // console.log(reg.test("123"))  //true
        // console.log(reg.test("ba\ncd"))  //true 有任意一个非换行符
        // console.log(reg.test("\n\n\n\n\n"))  //false


        //8 . \转义字符
        var reg = /\d.\d/   // 中间的点识别成了元字符 7  . 任意内容 (换行不算)

        console.log(reg.test("1.2"))  //true
        console.log(reg.test("1a2"))  //true
        // console.log(reg.test("1a2"))

        var reg = /\d\.\d/   // 1.2 2.3 加\转义字符将.转为了普通字符.

        console.log(reg.test("1.2"))  //true
        console.log(reg.test("1a2"))  //false
    </script>

21-2 边界符

1.^ 限制开头
2.$ 限制结尾边界
3.^开头结束$
<script>
        // ^ 开头
        // var reg = /^\d/  //开头必须是数字

        // console.log(reg.test("aabb2"))  //false
        // console.log(reg.test("1aabb"))  //true

        // $ 结尾边界
        // var reg = /\d$/  //结尾必须是数字

        // console.log(reg.test("aabb2"))  //true
        // console.log(reg.test("1aabb"))  //false


        // ^开头结束$

        var reg = /^adc$/

        console.log(reg.test("abc"))  //true
        console.log(reg.test("abcd"))  //false
        console.log(reg.test("dabc"))  //false
        
        var reg = /^a\dc$/
        console.log(reg.test("a6c"))  //true
    </script>

21-3 限定符

1. * 0~多次
2. + 1~多次
3. ? 0~1
4. {n} 指定次数
5. {n,} >=n 大于等于n个
6. {n,m} 在n-m个中间
 <script>
        // 1. * 0~多次

        // var reg= /\d*/

        // console.log(reg.test("abc"))  //true
        // console.log(reg.test("abc1"))  //true
        // console.log(reg.test("abc12"))  //true


        //2. + 1~多次

        // var reg= /\d+/

        // console.log(reg.test("abc"))  //false
        // console.log(reg.test("abc1"))  //true
        // console.log(reg.test("abc124vb"))  //true
        // console.log(reg.exec("abc124vb"))  //只能捕获124


        // //3. ? 0~1

        // var reg=/\d?/

        // console.log(reg.test("abc"))  //true
        // console.log(reg.test("ab1"))  //true


         //4. {n} 指定次数

        //  var reg=/\d{3}/
        
        // console.log(reg.test("aaa"))  //false
        // console.log(reg.test("ab12"))  //false
        // console.log(reg.test("ab123"))  //true
        // console.log(reg.exec("ab12345"))  //只能捕获123

        //  var reg=/a{3}/
        // console.log(reg.test("aaa"))  //true


        //5. {n,} >=n //大于等于n个

        //  var reg=/\d{3,}/  //大于等于3个

        // console.log(reg.test("aaa"))  //false
        // console.log(reg.test("ab12"))  //false
        // console.log(reg.test("ab123"))  //true
        // console.log(reg.test("ab12345"))  //true

        // console.log(reg.exec("ab12345"))  //能捕获12345


        //6. {n,m}
        var reg=/\d{3,5}/  //在3-5个中间
        //  var reg=/a{3}/

        console.log(reg.test("aaa"))  //false
        console.log(reg.test("ab12"))  //false
        console.log(reg.test("ab123"))  //true
        console.log(reg.test("ab123456"))  //true

        console.log(reg.exec("ab123456"))  //只能捕获12345

        //
        var reg2= /c{2}/

        console.log(reg2.test("abc"))  //false
        console.log(reg2.test("decc"))  //true

        var reg2= /^abc{2}$/

        console.log(reg2.test("abc"))  //false
        console.log(reg2.test("decc"))  //false
        console.log(reg2.test("332abcc4343"))  //true
        console.log(reg2.test("abcc"))  //true

        var reg2= /^abc{2}$/ //开头ab固定,c是两个
 
        console.log(reg2.test("332abcc4343"))  //false
        console.log(reg2.test("abcc"))  //true

    </script>

21-4 特殊符号

1.() 整体
2. | 或 ,左右
3.[] 代表1个
4.[^abc] , [^]表示取反
<script>
        // 1.() 整体
        // var reg2= /(abc){2}/

        // console.log(reg2.test("abc"))  //false
        // console.log(reg2.test("decc"))  //false
        // console.log(reg2.test("332abcabc4343"))  //true
        // console.log(reg2.test("abcabc"))  //true


        // 2. | 或 ,左右
        // var reg = /a|b/
       
        // console.log(reg.test("123"))  //false
        // console.log(reg.test("1a3"))  //true
        // console.log(reg.test("12b"))  //true
        // console.log(reg.test("1ab"))  //true

        // var reg2 = /(abc|def)/  //只能管前后一个字符
        // console.log(reg3.test("abcef"))  //true
        // console.log(reg3.test("abc"))  //true
        // console.log(reg3.test("abdef"))  //true
        // console.log(reg3.test("def"))  //true

        // var reg2 = /abc|def/  //只能管前后一个字符
        // console.log(reg3.test("abc"))  //true
        // console.log(reg3.test("def"))  //true


        // var reg3 = /(abc)|def|xyz/

        // console.log(reg3.test("abc"))  //true
        // console.log(reg3.test("def"))  //true
        // console.log(reg3.test("xyz"))  //true
        // console.log(reg3.test("xy"))  /false


        //3 [] 代表1个

        var reg = /[abcdef]/  //包含其中一个即可
        console.log(reg.text("x"))  //false
        console.log(reg.text("xa"))  //ture

        var reg = /[abcdef]{3,5}/  //至少包含3-5个
        console.log(reg.text("abcd"))  //ture
        console.log(reg.text("abxyz"))  //false

        var reg = /[a-w]{3,5}/

        // console.log(reg.test("xabc"))

        console.log(reg.test("abcd"))  //false
        console.log(reg.test("abxyz"))  //ture
        console.log(reg.test("111abxy222"))  //ture

        // [a-zA-Z0-9_]  \w

        // [0-9] \d

        //4 [^abc]

        var reg2 = /[^abc]/  //[^]表示取反

        console.log(reg2.test("a"))  //false
        console.log(reg2.test("xyz"))  //true 一个不在就对
        console.log(reg2.test("abz"))  //true  
    </script>

21-5 捕获exec

1. exec() 捕获片段
2. 标识符 g全局标识符 i忽略大小写
<script>
        // test()
        // exec() 捕获片段

        // var reg = /\d{3}/

        // console.log(reg.exec("aa123aa"))  //null
        // console.log(reg.exec("aa123aa"))  //123

        var datestr = "time is from 2029-01-01 12:20:20 to 2029-11-01 12:20:20"

        // 2029/01/01  - 2029/11/01

        // var reg = /\d{4}-\d{1,2}-\d{1,2}/

        // var newdatestr = reg.exec(datestr)
        // console.log(newdatestr)
        // console.log(newdatestr[0].split("-").join("/")) 
        //只能截取遇到的第一个  2029/01/01

         // var newdatestr = reg.exec(datestr)
        // console.log(newdatestr)
        // var newdatestr = reg.exec(datestr)
        // console.log(newdatestr)
        // console.log(newdatestr[0].split("-").join("/")) 
        //同样只能截取遇到的第一个  2029/01/01


        // 标识符 g i

        //g全局标识符
        var reg = /\d{4}-\d{1,2}-\d{1,2}/g //全局标识符

        var newdatestr1 = reg.exec(datestr)
        console.log(newdatestr1)
        var newdatestr2 = reg.exec(datestr)
        console.log(newdatestr2)
        var newdatestr3 = reg.exec(datestr)
        console.log(newdatestr3)
        console.log(newdatestr1[0].split("-").join("/"))
        console.log(newdatestr2[0].split("-").join("/"))
        //2029/01/01
        //2029/11/01

        var reg = /(\d{4})-(\d{1,2})-(\d{1,2})/g //全局标识符

        var newdatestr1 = reg.exec(datestr)
        console.log(newdatestr1)
        var newdatestr2 = reg.exec(datestr)
        console.log(newdatestr2)
        var newdatestr3 = reg.exec(datestr)
        console.log(newdatestr3)
        console.log(newdatestr1[0].split("-").join("/"))
        console.log(newdatestr2[0].split("-").join("/"))
        //2029/01/01
        //2029/11/01
        //加()后()内内容也会被单独捕获,但不显示在最终结果上



        //i忽略大小写
        var myreg= /[a-z]/

        console.log(myreg.test("AA"))  //false
        console.log(myreg.exec("AA"))  //null

        var myreg= /[a-z]/i //忽略大小写

        console.log(myreg.test("AA"))  //true
        console.log(myreg.exec("AA"))  //A

        // /\d/ig  既忽略大小写,也是全局的查找
    </script>

21-6 正则表达式的两大特性

1. 懒惰 每次从字符串开始的地方找 解决:使用全局标识符g
2. 贪婪 把符合规则的最大可能性匹配出来
3. 非贪婪?
<script>
        //1.懒惰, 解决 使用全局标识符g

        //2.贪婪

        // var reg = /\d{1,4}/

        // console.log(reg.text("aa123456bb")) //true
        // console.log(reg.exec("aa123456bb")) //1234 能拿多少拿多少

        //3.非贪婪?

        var reg = /\d{1,4}?/

        console.log(reg.exec("aa123456bb")) //1  尽可能少的拿


        /*
            *? 非贪婪  //*贪婪
            +? 非贪婪
            ?? 非贪婪
            {n,}? 非贪婪
            {n,m}? 非贪婪,按最小的n满足
        */


        var str = `<p class="active"><span>kerwin</span></p>`

        var myreg = /<p.*>/ //贪婪
        console.log(myreg.exec(str)) //`<p class="active"><span>kerwin</span></p>`


        var myreg = /<p.*?>/ //非贪婪
        console.log(myreg.exec(str)) //<p class="active">
    </script>

21-7 正则与字符串方法

1.replace替换
2.search查找
3.match捕获内容
<script>
        // 正则.test(字符串)
        // 正则.exec(字符串)


        //字符串.replace替换  search查找  match捕获内容

        //replace
        
        // var newstr = str.replace("a","*")  //只能替换第一个
        // var newstr = str.replace(/a/g,"*")  //可以替换全局
        // console.log(newstr)


        //search

        // console.log(str.search("a"))
        // console.log(str.search(/a/))
        // console.log(str.search(/ax/))


        //match 捕获内容
        var datestr = "time is from 2029-01-01 12:20:20 to 2029-11-01 12:20:20"

        // console.log(str.match("ad"))

        console.log(datestr.match(/(\d{4})-(\d{1,2})-(\d{1,2})/g))
    </script>

案例:密码强度验证

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    form {
      width: 500px;
      padding: 20px;
      border: 3px solid #333;
      margin: 50px auto;
    }

    form > label {
      width: 100%;
      height: 70px;
    }

    form > label > input {
      width: 100%;
      box-sizing: border-box;
      padding-left: 30px;
      font-size: 20px;
      height: 50px;
    }

    form > p {
      width: 100%;
      margin-top: 10px;
      display: flex;
      justify-content: space-between;
    }

    form > p > span {
      width: 30%;
      background-color: #ccc;
      color: #fff;
      height: 30px;
      font-size: 20px;
      line-height: 30px;
      text-align: center;
    }

    form > p > span:nth-child(1).active {
      background-color: red;
    }

    form > p > span:nth-child(2).active {
      background-color: orange;
    }

    form > p > span:nth-child(3).active {
      background-color: green;
    }
  </style>
</head>
<body>
  <form>
    <label>
      <input type="text">
    </label>
    <p>
      <span ></span>
      <span ></span>
      <span ></span>
    </p>
  </form>

  <script>
    var oinput =document.querySelector("input")
    var reg1 = /\d/
    var reg2 = /[a-z]/i
    var reg3 = /[!@#$%^&*()]/

    var ospan = document.querySelectorAll("span")
    oinput.oninput = function(evt){
      console.log(this.value)
      // console.log(evt.target.value)
      var level = 0

      if(reg1.test(this.value)) level++
      if(reg2.test(this.value)) level++
      if(reg3.test(this.value)) level++

      // console.log(level)
      for(var i=0;i<ospan.length;i++){
        ospan[i].classList.remove("active")
        if(i<level){
          ospan[i].classList.add("active")
        }
      }
    }
  </script>
</body>
</html>

22. this 关键字

22-1 this指向

  • 每一个函数内部都有一个关键字是 this 可以让我们直接使用的

  • 重点: 函数内部的 this 只和函数的调用方式有关系,和函数的定义方式没有关系

  • 函数内部的 this 指向谁,取决于函数的调用方式

全局定义的函数直接调用,this => window
```javascript
function fn() {
  console.log(this)
}
fn()
// 此时 this 指向 window
```
对象内部的方法调用,this => 调用者
```javascript
var obj = {
  fn: function () {
    console.log(this)
  }
}
obj.fn()
// 此时 this 指向 obj
```
定时器的处理函数,this => window
```javascript
setTimeout(function () {
  console.log(this)
}, 0)
// 此时定时器处理函数里面的 this 指向 window
```
事件处理函数,this => 事件源
```javascript
div.onclick = function () {
  console.log(this)
}
// 当你点击 div 的时候,this 指向 div
```
自调用函数,this => window
```javascript
(function () {
  console.log(this)
})()
// 此时 this 指向 window
```

22-2 改变this指向

call 和 apply 和 bind

  • 刚才我们说过的都是函数的基本调用方式里面的 this 指向
  • 我们还有三个可以忽略函数本身的 this 指向转而指向别的地方
  • 这三个方法就是 call / apply / bind
  • 是强行改变 this 指向的方法

1.call

  • call 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向

  • 语法: 函数名.call(要改变的 this 指向,要给函数传递的参数1,要给函数传递的参数2, ...)

    var obj = { name: 'Jack' }
    function fn(a, b) {
      console.log(this)
      console.log(a)
      console.log(b)
    }
    fn(1, 2)
    fn.call(obj, 1, 2)
    
    • fn() 的时候,函数内部的 this 指向 window
    • fn.call(obj, 1, 2) 的时候,函数内部的 this 就指向了 obj 这个对象
    • 使用 call 方法的时候
      • 会立即执行函数
      • 第一个参数是你要改变的函数内部的 this 指向
      • 第二个参数开始,依次是向函数传递参数

2.apply

  • apply 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向

  • 语法: 函数名.apply(要改变的 this 指向,[要给函数传递的参数1, 要给函数传递的参数2, ...])

    var obj = { name: 'Jack' }
    function fn(a, b) {
      console.log(this)
      console.log(a)
      console.log(b)
    }
    fn(1, 2)
    fn.call(obj, [1, 2])
    
    • fn() 的时候,函数内部的 this 指向 window
    • fn.apply(obj, [1, 2]) 的时候,函数内部的 this 就指向了 obj 这个对象
    • 使用 apply 方法的时候
      • 会立即执行函数
      • 第一个参数是你要改变的函数内部的 this 指向
      • 第二个参数是一个 数组,数组里面的每一项依次是向函数传递的参数

3.bind

  • bind 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向

  • 和 call / apply 有一些不一样,就是不会立即执行函数,而是返回一个已经改变了 this 指向的函数

  • 语法: var newFn = 函数名.bind(要改变的 this 指向); newFn(传递参数)

    var obj = { name: 'Jack' }
    function fn(a, b) {
      console.log(this)
      console.log(a)
      console.log(b)
    }
    fn(1, 2)
    var newFn = fn.bind(obj)
    newFn(1, 2)
    
    • bind 调用的时候,不会执行 fn 这个函数,而是返回一个新的函数
    • 这个新的函数就是一个改变了 this 指向以后的 fn 函数
    • fn(1, 2) 的时候 this 指向 window
    • newFn(1, 2) 的时候执行的是一个和 fn 一摸一样的函数,只不过里面的 this 指向改成了 obj
    <button id="btn">click</button>
    <script>
        // call apply bind 
        var name = "1111111111111111111111"

        var obj1 = {
            name:"obj1",
            getName:function(a,b,c){
                console.log("getName1",this.name)
                console.log("参数",a,b,c)
            }
        }
        var obj2 = {
            name:"obj2",
            getName:function(){
                console.log("getName2",this.name)
            }
        }

        // console.log(obj1)
        // obj1.getName()
        // obj2.getName()

        // call 执行函数, 并改变this执行为函数的第一个参数
        // 支持多个参数
        obj1.getName.call(obj2,1,2,3)  //参数 1 2 3


        // apply 执行函数, 并改变this执行为函数的第一个参数
        // 只支持两个参数, 第二个参数是一个数组
        obj1.getName.apply(obj2,[1,2,3])  //参数 1 2 3


        // obj1.getName.call(window)

        //bind 改变this指向为函数的第一个参数,不会自动执行函数
         // 支持多个参数
        var fun1 = obj1.getName.bind(obj2,1,2,3)

        console.log(fun1)

        fun1() //手动执行


        btn.onclick = handler.bind(window)

        function handler(){
            console.log(11111,this)
        }
    </script>