JavaScript高级(2)

JavaScript高级(2)

函数的其他成员

  • arguments
    • 实参集合
  • caller
    • 函数的调用者
  • length
    • 形参的个数
  • name
    • 函数的名称
function fn(x, y, z) {
  console.log(fn.length) // => 形参的个数
  console.log(arguments) // 伪数组实参参数集合
  console.log(arguments.callee === fn) // 函数本身
  console.log(fn.caller) // 函数的调用者
  console.log(fn.name) // => 函数的名字
}

function f() {
  fn(10, 20, 30)
}

f()

高阶函数

  • 函数可以作为参数
  • 函数可以作为返回值

作为参数

function eat (callback) {
  setTimeout(function () {
    console.log('吃完了')
    callback()
  }, 1000)
}

eat(function () {
  console.log('去唱歌')
})

作为返回值

function genFun (type) {
  return function (obj) {
    return Object.prototype.toString.call(obj) === type
  }
}

var isArray = genFun('[object Array]')
var isObject = genFun('[object Object]')

console.log(isArray([])) // => true
console.log(isArray({})) // => true

函数闭包

function fn () {
  var count = 0
  return {
    getCount: function () {
      console.log(count)
    },
    setCount: function () {
      count++
    }
  }
}

var fns = fn()

fns.getCount() // => 0
fns.setCount()
fns.getCount() // => 1

作用域、作用域链、预解析

  • 全局作用域
  • 函数作用域
  • 没有块级作用域
{
  var foo = 'bar'
}

console.log(foo)

if (true) {
  var a = 123
}
console.log(a)

作用域链示例代码:

var a = 10

function fn () {
  var b = 20

  function fn1 () {
    var c = 30
    console.log(a + b + c)
  }

  function fn2 () {
    var d = 40
    console.log(c + d)
  }

  fn1()
  fn2()
}
  • 内层作用域可以访问外层作用域,反之不行。

闭包

闭包就是能够读取其他函数内部变量的函数,
由于在JavaScript语言中,只有函数内部的子函数才能读取局部变量,
由此可以把闭包简单成“定义在一个函数内部的函数”。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

闭包的用途

  • 可以在函数外部读取函数内部成员
  • 让函数内成员始终存活在内存中

一些关于闭包的例子

var arr = [10, 20, 30]
for(var i = 0; i < arr.length; i++) {
  arr[i] = function () {
    console.log(i)
  }
}

函数递归

递归执行模型

function fn1 () {
  console.log(111)
  fn2()
  console.log('fn1')
}

function fn2 () {
  console.log(222)
  fn3()
  console.log('fn2')
}

function fn3 () {
  console.log(333)
  fn4()
  console.log('fn3')
}

function fn4 () {
  console.log(444)
  console.log('fn4')
}

fn1()

计算阶乘的递归函数

function factorial (num) {
  if (num <= 1) {
    return 1
  } else {
    return num * factorial(num - 1)
  }
}

递归应用场景

  • 深拷贝

<!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>
</head>
<body>
  <script>
    // 深拷贝
    var obj1 = {
      name: 'zs',
      age: 18,
      sex: '男',
      dog: {
        name: '金毛',
        age: 2
      },
      friends: ['ls', 'ww']
    }

    // 深拷贝  把o1的成员拷贝给o2
    function deepCopy(o1, o2) {
      for (var key in o1) {
        // 获取key属性对应的值
        var item = o1[key];

        // 如果item 是对象?
        // var o = {}
        if (item instanceof Object) {
          // var o = {};
          o2[key] = {}; 
          deepCopy(item, o2[key]);
        } else if (item instanceof Array) {
          // 如果item 是数组呢?
          // var arr = [];
          o2[key] = [];
          deepCopy(item, o2[key]);
        } else {
          // 如果是简单类型
          o2[key] = o1[key];
        }
      }
    }


    var obj2 = {};

    deepCopy(obj1, obj2);

    // 修改obj1中的成员 是否会影响obj2?
    obj1.dog.name = 'xxx';
    obj1.friends[0] = 'xxx';

    console.dir(obj2);
  </script>
</body>
</html>
  • 遍历DOM树

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>遍历DOM树</title>
</head>
<body>
  <h1>遍历 DOM 树</h1>
  <p style="color: green;">Tip: 可以在遍历的回调函数中任意定制需求</p>
  <div>
    <ul id="list">
      <li>123</li>
      <li>456</li>
      <li>789</li>
    </ul>
    <div>
      <div>
        <span>haha</span>
      </div>
    </div>
  </div>
  <div id="demo_node">
    <ul>
      <li>123</li>
    </ul>
    <p>hello</p>
    <h2>world</h2>
    <div>
      <p>dsa</p>
      <h3>
        <span>dsads</span>
      </h3>
    </div>
  </div>
  <script>
    // 遍历指定元素下所有的子元素
    function loadTree(parent, callback) {
      for (var i = 0; i < parent.children.length; i++) {
        // 遍历第一级子元素
        var child = parent.children[i];
        // console.log(child);
        if (callback) {
          // 处理找到的子元素
          callback(child);
        }

        // 递归调用
        loadTree(child);
      }
    }

    var ul = document.getElementById('list');
    loadTree(ul, function (element) {
      element.onclick = function () {
        console.log(this.innerText);
      }
    });
  </script>
</body>
</html>

正则表达式

  • 了解正则表达式基本语法
  • 能够使用JavaScript的正则对象

正则表达式简介

正则表达式的作用

1.给定的字符串是否符合正则表达式的过滤逻辑(匹配)
2.可以通过正则表达式,从字符串中获取我们想要的特定部分(提取)
3.强大的字符串替换能力(替换)

正则表达式的特点

1.灵活性、逻辑性和功能性非常的强
2.可以迅速地用极简单的方式达到字符串的复杂控制
3.对于刚接触的人来说,比较晦涩难懂

正则表达式的测试

在线测试正则

正则表达式的组成

  • 普通字符abc 123
  • 特殊字符(元字符):正则表达式中有特殊意义的字符\d \w

常用元字符

元字符说明
\d匹配数字
\D匹配任意非数字的字符
\w匹配字母或数字或下划线
\W匹配任意不是字母,数字,下划线
\s匹配任意的空白符
\S匹配任意不是空白符的字符
.匹配除换行符以外的任意单个字符
^表示匹配行首的文本(以谁开始)
$表示匹配行尾的文本(以谁结束)

限定符

限定符说明
*重复零次或更多次
+重复一次或更多次
?重复零次或一次
{n}重复n次
{n,}重复n次或更多次
{n,m}重复n到m次

其他
[] 字符串用中括号括起来,表示匹配其中的任一字符,相当于或的意思
[^] 匹配除中括号以内的内容
\ 转义符
| 或者,选择两者中的一个。注意|将左右两边分为两部分,而不管左右两边有多长多乱
() 从两个直接量中选择一个,分组
eg:gr(a|e)y匹配gray和grey
[\u4e00-\u9fa5] 匹配汉字

验证手机号:

^\d{11}$

验证邮编:

^\d{6}$

验证日期 2012-5-01

^\d{4}-\d{1,2}-\d{1,2}$

验证邮箱 xxx@itcast.cn:

^\w+@\w+\.\w+$

验证IP地址 192.168.1.10

^\d{1,3}\(.\d{1,3}){3}$

JavaScript 中使用正则表达式

创建正则对象

方式1:

var reg = new RegExp('\d', 'i');
var reg = new RegExp('\d', 'gi');

方式2:

var reg = /\d/i;
var reg = /\d/gi;

参数

标志说明
i忽略大小写
g全局匹配
gi全局匹配+忽略大小写

正则匹配

// 匹配日期
var dateStr = '2015-10-10';
var reg = /^\d{4}-\d{1,2}-\d{1,2}$/
console.log(reg.test(dateStr));

正则提取

// 1. 提取工资
var str = "张三:1000,李四:5000,王五:8000。";
var array = str.match(/\d+/g);
console.log(array);

// 2. 提取email地址
var str = "123123@xx.com,fangfang@valuedopinions.cn 286669312@qq.com 2、emailenglish@emailenglish.englishtown.com 286669312@qq.com...";
var array = str.match(/\w+@\w+\.\w+(\.\w+)?/g);
console.log(array);

// 3. 分组提取  
// 3. 提取日期中的年部分  2015-5-10
var dateStr = '2016-1-5';
// 正则表达式中的()作为分组来使用,获取分组匹配到的结果用Regex.$1 $2 $3....来获取
var reg = /(\d{4})-\d{1,2}-\d{1,2}/;
if (reg.test(dateStr)) {
  console.log(RegExp.$1);
}

// 4. 提取邮件中的每一部分
var reg = /(\w+)@(\w+)\.(\w+)(\.\w+)?/;
var str = "123123@xx.com";
if (reg.test(str)) {
  console.log(RegExp.$1);
  console.log(RegExp.$2);
  console.log(RegExp.$3);
}

正则替换

// 1. 替换所有空白
var str = "   123AD  asadf   asadfasf  adf ";
str = str.replace(/\s/g,"xx");
console.log(str);

// 2. 替换所有,|,
var str = "abc,efg,123,abc,123,a";
str = str.replace(/,|,/g, ".");
console.log(str);

案例:验证表单

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>表单验证</title>
</head>

<body>
    <label for="txtQQ">QQ号:<input type="text" id="txtQQ"><span></span></label><br>
    <label for="txtEmail">邮箱:<input type="text" id="txtEmail"><span></span></label><br>
    <label for="txtPhone">手机:<input type="text" id="txtPhone"><span></span></label><br>
    <label for="txtBirth">生日:<input type="text" id="txtBirth"><span></span></label><br>
    <label for="txtName">姓名:<input type="text" id="txtName"><span></span></label><br>
    <script>
        // 1.验证QQ号
        addCheck('txtQQ', /^\d{5,12}$/, '请输入正确的QQ号格式');
        addCheck('txtEmail', /^\w+@\w+(\.\w+)+$/, '请输入正确的邮箱格式');
        addCheck('txtPhone', /^[1-9]\d{10}$/, '请输入正确的手机号格式');
        addCheck('txtBirth', /^\d{4}-\d{1,2}-\d{1,2}$/, '请输入正确的日期格式');
        addCheck('txtName', /^[\u4e00-\u9fa5]{0,}$/, '请输入2-4个汉字');

        // 文本框的验证封装成一个函数
        // 第一个参数是元素的id
        // 第二个参数 正则表达式对象 RegExp
        // 第三个参数 是提示的文本
        function addCheck(elementId, reg, tip) {
            var element = document.getElementById(elementId);
            element.onblur = function () {
                var span = this.nextElementSibling;
                // 验证
                if (!reg.test(this.value)) {
                    span.innerText = tip;
                    span.style.color = 'red';
                } else {
                    span.innerText = '';
                    span.style.color = '';
                }
            }
        }

        // onchange 改变
    //     var txtQQ = document.getElementById('txtQQ');
    //     // txtQQ.onchange = function () {
    //     //     console.log("111");
    //     // }
    //     // 当光标离开文本框的时候
    //     txtQQ.onblur = function () {
    //         // 验证用户的输入是否是QQ号
    //         var reg = /^\d{5,12}$/;
    //         var span = this.nextElementSibling;
    //         // 检测输入的文本是否匹配指定的模式(正则表达式)
    //         if (!reg.test(this.value)) {
    //             //  不匹配 在文本框后面的span中进行相应的提示

    //             span.innerText = '请输入正确的QQ格式';
    //             span.style.color = 'red';
    //         } else {
    //             // 匹配
    //             span.innerText = '';
    //             span.style.color = '';
    //         }
    //     }
    </script>
</body>

</html>

这篇文章有 622 个评论

  1. Adultfriendfindfer

    Please let me know if you’re looking for a article author for your
    weblog. You have some really good posts and I feel I would
    be a good asset. If you ever want to take some of the load off, I’d really
    like to write some articles for your blog in exchange for a
    link back to mine. Please shoot me an e-mail if interested.
    Kudos!

  2. Social Media Marketing

    Wow, amazing blog structure! How long have you been blogging for? you made running a blog look easy. The overall look of your site is fantastic, let alone the content material!!

  3. airiz ped

    I absolutely agree with your opinions.

发表评论