函数的其他成员
- 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>