构造函数
大写开头的函数, 需要配合new使用, 一般用作模板
new的作用
实例成员就是绑定在this实例对象上的属性和方法
静态成员就是绑定在构造函数身上的属性和方法(谁绑定谁调用)
prototype是构造函数特有的, 为了让实例对象共享方法, 节省内存
__proto__
是对象特有的, 为了调度更多的方法(口诀: 对象.__proto__
指向了 构造函数.prototype)
constructor是构造函数.prototype原型对象上的一个属性, 指回构造函数本身, 用于检测一个原型对象属于哪个构造函数的
原型链: 通过对象.__proto__
逐级向上查找的过程叫原型链
typeof和instanceof都能判断某个对象的类型, instanceof判断更准确(原理是对象.__proto__
指向 构造函数.prototype)
属性继承 - 子构造函数内, 父构造函数.call(this) - 如果有参数继续在后面传递
方法继承 - 子构造函数.prototype = Object.create(父构造函数.prototype)
并且子构造函数.prototype.constructor = 子构造函数
class类的本质就是ES5的构造函数+prototype原型
语法: function 函数名() {}
fn();
function fn(){
console.log("我是函数");
console.log(this); // window
}
语法: var 变量名 = function(){}
var fn2 = function(){
console.log("我是函数2");
console.log(this); // window
}
fn2();
// 注意函数表达式 没有变量提升
语法: key对应的value值是一个函数体
var obj = {
fn: function(){
console.log("对象里的属性-函数");
console.log(this); // obj
}
}
obj.fn();
语法: 给事件绑定函数
document.onclick = function(){
console.log("dom绑定事件 - 处理函数");
console.log(this); // document
}
document.addEventListener("click", function(){
console.log("事件监听 - 处理函数");
console.log(this); // document
})
语法: 传入定时器/计时器中的一个函数体
setInterval(function(){
console.log("计时器执行");
console.log(this); // window
}, 1000);
setTimeout(function(){
console.log("定时器执行");
console.log(this); // window
}, 1000);
语法: function 大写名开头的函数名(){}
function Person(){
console.log("构造函数 调用");
console.log(this); // this指向实例对象
}
new Person();
语法: function(){} - 没有名字的函数
常用: 对象里的value或者参数使用 - 也叫函数体
// 我是匿名函数
var a = function(){
console.log("我是匿名函数");
console.log(this); // window
}
setTimeout(a, 1000);
// 这里都是匿名函数的情况
// 常用作, 当做参数传递给别人 (函数体)
语法
解析规则: ()() 加上()是调用前面的函数体执行, 如果不及时加分号, JS解析会报错
重要: 写立即执行函数, 最后必须加分号
// 立即执行函数
(function(){
console.log("我是1");
console.log(this); // window
})();
(function(){
console.log("我是2");
}());
!function(){
console.log("我是3");
}();
// 立即执行函数传参
(function(num){
console.log("我是1");
console.log(num);
})(100);
(function(num){
console.log("我是2");
console.log(num);
}(200));
!function(num){
console.log("我是3");
console.log(num);
}(300);
语法: 在函数内, 调用当前函数
// 定义函数, 调用时, 在函数内再次调用当前函数, 产生递归
// function myFn(){
// console.log("函数调用");
// myFn();
// }
// myFn();
// 问题: 递归死循环了, 出不来了..
// 解决: 注意留好出口, 看下面例子
// 例如: 用递归函数 - 输出5到1
function sum(m){
if (m <= 0) {
return; // 出口 - 停止递归(防止代码往下执行)
}
console.log(m);
console.log(this);
sum(--m);
}
sum(5);
this指向调用者 -> window
高阶函数本身是一个函数, 它可接受/返回函数体, 是对其他函数进行操作
把函数作为参数,或者把函数作为返回值的的函数,称为高阶函数
// 语法学习:
// 1. 函数作为形参:
// 定义高阶函数myFn, 形式参数fn的值是函数体
function myFn(fn){
fn();
}
// 调用高阶函数myFn - 传入参数是一个函数体
myFn(function(){
console.log("myFn调用执行 - 传入一个函数体给fn, 然后fn()调用下面函数体执行了 - 这里打印");
});
// 2. 函数作为返回值 - (了解)
function getHobby(){
return function(){
console.log("返回了一个函数体");
}
}
var theFn = getHobby(); // 得到高阶函数内返回的function
theFn(); // 导致内部return后的函数执行
// 自己使用时, 多出现在回调函数情况
this指向调用者 - window
在高阶函数中, 其实你就已经使用了回调函数
// 语法: my是高阶函数, fn参数的值是function(){}函数体
function my(fn){
fn(); // 这里调用外部传入进来的函数 - 回调外部的函数体执行 - 这个动作就叫回调函数
}
my(function(){
console.log("函数执行");
})
// 执行顺序:
// 声明函数function my
// 调用my()执行 -> 传入函数体 -> fn变量
// my()函数执行 -> 调用fn() -> 回调了外面函数体执行
// 使用场景: 例如数组的所有方法(filter, map, forEach, every, some等), 还有addEventListener, 还有计时器, 定时器 (高阶函数都是使用的回调函数概念)
变量作用域
全局变量, 局部变量(函数内var的), 当函数内部执行完毕, 会销毁函数内所有声明的变量
语法: 内层函数, 引用外层函数上的变量, 形成闭包
// 内层函数引用外层函数变量, 形成闭包
var liList = document.querySelectorAll("#myUL>li");
for (var i = 0; i < liList.length; i++) {
liList[i].onclick = function(){
console.log(i);
}
} // 这里没有闭包 - 所以i的值是全局的i, 点击谁都是liList的长度
for (var j = 0; j < liList.length; j++) {
function myFn(ind){
el.onclick = function () {
console.log(ind); // 内层函数 - 引用外层函数上声明的变量ind - 导致myFn函数执行完, ind不会被回收 - 这里形成闭包
}
}
myFn(j);
}
浏览器调试闭包
闭包会造成外层函数(执行10次), 函数不会被回收, 因为它的ind的值被引用了
解决方式:
这3个方法都用函数.调用
// 1. call方法
function Student(theName, theAge){
// 构造方法
this.name = theName;
this.age = theAge;
}
var stu = {
className: "114"};
Student.call(stu, "小花", 18); // 使用call方法, 执行Student方法, 传入stu对象, 蹭下来2个属性和传入的值
console.log(stu);
// 2. apply方法
function Student2(theName, theAge){
this.name = theName;
this.age = theAge;
}
var stu2 = {
className: "114"};
Student2.apply(stu2, ["小花", 39]); // 使用apply方法, 执行Student2方法, 传入stu2对象, 蹭下来2个属性和传入的值 (注意传值, 必须使用数组格式)
console.log(stu2);
// 3. bind方法
function Student3(theName, theAge){
this.name = theName;
this.age = theAge;
}
var stu3 = {
className: "114"};
var fn = Student3.bind(stu3, "小花", 10); // 使用bind不会马上调用函数执行, 而是返回一个this值指向stu3的函数
fn(); // 调用执行, 给传入的stu3对象, 绑定属性
console.log(stu3);
// 总结:
// call, apply, bind 都可以给对象绑定额外的属性和值
// call, apply, bind 一般配合构造函数使用
// call 和 apply 会马上调用函数执行, 但是apply传参必须是数组格式
// bind 不会马上调用函数执行, 会返回一个函数, 手动调用
方式 | 代码 | this指向 | 备注 |
---|---|---|---|
默认绑定 | fn() / 定时器/ 计时器 | window | 前面默认有window. |
隐式绑定 | 事件调用函数 / 函数方法调用 | 调用者 | 调用者.函数名() |
new绑定 | new 构造函数() | 新对象 | 返回这个新对象 |
硬绑定 | 使用call / apply / bind 方法 | 传入的参数 | call和apply马上执行函数, bind会返回一个函数 |
总结: 除了硬绑定和new, 其余的都看调用者是谁
练习1: 闭包使用 - 给10个li绑定鼠标移入事件, 移入打印索引
var liList = document.querySelectorAll("li");
for (var i = 0; i < liList.length; i++) {
function myFn(ind) {
liList[ind].onclick = function () {
console.log(ind);
}
}
myFn(i);
}
练习2: 递归函数 - 用递归函数求5的阶乘 myFn(5) (5 * 4 * 3 * 2 * 1)
function sumFn(num){
if (num == 0) {
return num;
}
return num + sumFn(--num);
}
var result = sumFn(5);
console.log(result);
内存地址
代码是存储在硬盘上的 -> 浏览器上运行 -> 把代码被读取到内存中(参与CPU的执行) -> 显示结果到页面上
计算机内存中, 主要分为两大块
声明(var)变量, 会在栈区开辟一个空间, 里面存储的要么是基础类型的值, 要么是数组/对象的堆地址
赋值动作
var a = 10;
var b = a; // 基础类型, 单纯值复制
var obj = {
// obj保存的实际上是堆内存地址
age: 18
};
var obj2 = obj; // obj变量的内存地址, 赋予给obj2变量
把一个引用类型里的内容, 拷贝到另一个新的引用类型中
只拷贝第一层的内容 - 浅拷贝
var obj = {
age: 18,
grade: {
math: 99,
chinese: 80,
english: 89
}
};
var newObj = {
}; // 一个新的对象
for (var prop in obj) {
// 把obj里的key和value都拿过来
newObj[prop] = obj[prop]; // 如果是基础类型就是单纯的值复制, 如果是引用类型保存的是堆内存地址(互相引用着同一个空间)
}
// 测试深层是否还是同一个内存地址互相影响
newObj.grade.math = 60;
console.log(obj); // {age: 18, grade: { math: 60, chinese: 80, english: 89}}
// 总结:
// 浅拷贝, 只拷贝第一层的内存
// 如果第二层还是个引用类型, 拷贝的都是内存地址 (内部还是互相影响)
for…in 知识点铺垫
// 1. for...in知识点铺垫
// for (var k in obj){}
// for...in... 既能遍历对象, 也能遍历数组
// 对象遍历的是key, 数组遍历出来的是下角标索引
var o = {
age: 18,
sex: "男"
}
for (var prop in o) {
console.log(prop);
}
var arr = [10, 55, 22];
for (var prop in arr) {
console.log(prop);
}
深拷贝实现
// 2. 把obj对象 - 拷贝到一个新的对象里
var oldObj = {
age: 18,
color: ["yellow", "blue"]
};
var newObj = {
};
function deepClone(newObj, oldObj) {
// {}, {age:18, color: ["yellow", "blue"]}
for (var k in oldObj) {
var value = oldObj[k];
newObj[k] = value;
}
}
deepClone(newObj, oldObj);
newObj.color[0] = "green";
console.log(oldObj); // 发现修改的是newObj, 但是oldObj的第二层数组被影响了 (我们想要的是互不影响的2个对象)
// 3. 深拷贝 - 如果是数组类型
var oldObj = {
age: 18,
color: ["yellow", "blue"]
};
var newObj = {
};
function deepClone(newObj, oldObj) {
// {}, {age:18, color: ["yellow"]}
for (var k in oldObj) {
var value = oldObj[k];
if (value instanceof Array) {
// 如果当前的value值是数组类型, 不能直接赋予到newObj对应的key上, 而应该给一个新的数组(保证和原来的数组不是同一个)
newObj[k] = [];
// (难点-核心)但是发现value的值是["yellow", "blue"] - 我们可以再次调用deepClone在遍历这个数组
deepClone(newObj[k], value);
} else {
newObj[k] = value;
}
}
}
deepClone(newObj, oldObj);
console.log(newObj);
newObj.color[0] = "green";
console.log(oldObj); // 数组没问题了
// 4. 深拷贝 - 如果内层又是对象类型
var oldObj = {
age: 18,
color: ["yellow", "blue"],
grade: {
math: 99,
chinese: 80,
english: 89
}
};
var newObj = {
};
function deepClone(newObj, oldObj){
for (var k in oldObj) {
var value = oldObj[k];
if (value instanceof Array) {
newObj[k] = [];
deepClone(newObj[k], value);
} else if (value instanceof Object) {
// 如果当前的值又是个对象-把这个对象看成像oldObj一样, 是不是要调用deepClone啊
// 那再给当前的key, 一个新的对象(相当于newObj一样), 再传入进deepClone里就ok了
newObj[k] = {
};
deepClone(newObj[k], value);
}
else {
newObj[k] = value;
}
}
}
deepClone(newObj, oldObj);
console.log(newObj);
newObj.grade.math = 1000;
console.log(oldObj); // 原来的对象并未受到影响
// 总结:
// 1. 递归的使用可以用在不确定层次的情况下来使用
// 2. 每次递归函数都是独立执行的, 与上次函数执行无关
// 3. 递归无论有没有return, 执行完了都要回到上次调用的地方
什么是正则表达式
var str = "chuanzhi_12345678-heihei";
// 判断这个字符串是否符合既有数字,字母,下划线,中划线以及长度在0-16位的代码
// 能写出来但是很麻烦, 而正则表达式只需要写几个字符就能作为规则来进行匹配
其他语言也会使用正则表达式,本节主要是利用JavaScript 正则表达式完成验证
// 方式1: 通过RegExp() 构造函数创建
var reg1 = new RegExp(/xyz/);
console.log(reg1);
// 方式2: 通过字面量(语法糖) - 创建正则对象
var reg2 = /xyz/;
console.log(reg2);
// 总结:
// 常用字面量方式来创建, 正则对象
连续出现过目标字符串
var reg = /xyz/;
var str = "xzsdafxy0zsdyzxsdfxy5zsdxyzfsadfsdxy4zfy";
// test() 正则对象方法,用于检测字符串是否符合该规则,该对象会返回 true 或 false,其参数是测试字符串
console.log(reg.test(str));
var reg2 = /123/;
var str2 = "1sssss2ss3";
console.log(reg2.test(str2));
// 必须出现过123连续的
用户描述规则出现在的位置 (开头还是末尾)
开头是否为连续的目标字符串
结尾是否为连续的目标字符串
// 1. 先要判断开头是否是xyz
var reg = /^xyz/;
var str = "xyzsdfsdfsdfsdfsdfsdxyzsdfasdfsadf";
console.log(reg.test(str));
// 2. 判断结尾是否是xyz
var reg2 = /xyz$/;
var str2 = "xxxxhahhaxyz";
console.log(reg2.test(str2));
// 3. 这种写法是, 精确匹配(中间没有任何匹配符号)
var reg3 = /^xyz$/;
var str3 = "xyzxxxhahhaxyz";
console.log(reg3.test(str3));
这个是或者的意思
// 以xyz开头, 或者以xyz结尾
var reg = /^xyz|xyz$/;
var str = "xyzxxxhahhaxyz";
console.log(reg.test(str));
// 只要匹配其中一项就返回true
var reg2 = /傻|笨蛋|可爱/;
var str = "这里有一个非常可爱的小姑娘";
console.log(reg2.test(str));
// 表示有一系列字符可供选择,只要匹配其中一个就可以了[多选1] - [abcdefg]
var reg1 = /xyz/;
var str1 = "weweewrx0234afa";
console.log(reg1.test(str1)); // false
var reg1 = /[xyz]/;
console.log(reg1.test(str1)); // true
// 例1:
var rg = /[abc]/; // 只要包含有a 或者 包含有b 或者包含有c 都返回为true
console.log(rg.test('andy'));//true
console.log(rg.test('baby'));//true
console.log(rg.test('color'));//true
console.log(rg.test('red'));//false
var rg1 = /^[abc]/; // 只要以a/b/c开头的, 都为true
console.log(rg1.test('ab')); // true
console.log(rg1.test('a')); // true
console.log(rg1.test('bfff'));//true
console.log(rg1.test('csdfsdf'));//true
console.log(rg1.test('eabcf'));//false
var reg1 = /^[abc]$/; // 完整匹配其中的一个
console.log(reg1.test("abc")); // false
console.log(reg1.test("a")); // true
console.log(reg1.test("b")); // true
console.log(reg1.test("c")); // true
console.log(reg1.test("abc123abc")); // false
词符用来设定某个模式出现的次数
量词 | 解释 |
---|---|
* | 重复0次或更多次【>=0次】 |
+ | 重复1次或更多次【>=1次】 |
? | 至少重复0次或1次 |
{n} | 连续重复至少n次 |
{n,m} | 连续重复至少n到m次 (注意不能有空格中间) |
// a出现0-多次
console.log(/a*/.test("hello"));
// b出现1-多次
console.log(/b+/.test("good bye"));
// c出现0或者1次
console.log(/c?/.test("chinese"));
// d出现0-2次
console.log(/d{0,2}/.test("brother"));
// 必须是数字的组合
var reg = /^[0123456789]+$/;
console.log(reg.test("1203123123"));
// 使用范围量词 - 改写
var reg = /^[0-9]+$/;
console.log(reg.test("1203123123"));
// 必须是纯英文(大小写都可以)
var reg = /^[a-zA-Z]+$/;
console.log(reg.test("asdfsadfsadafsdaf"));
// 判断身份证号 - 精准匹配
var reg = /^[0-9Xx]{15,18}$/;
console.log(reg.test("211002197702011"));
// 预定义:正则预先定义好的一些字母规则
// 1. \d ----> [0-9]
var reg = /^\d*$/
console.log(reg.test("123")); // true
// 2. \D ----> [0-9]以外所有字符
var reg = /^\D*$/
console.log(reg.test("abc")); // true
// 3. \w ----> [a-zA-Z0-9_] (匹配包括下划线的任何单词字符, 不包括-字符)
var reg = /^\w+$/
console.log(reg.test("home_33hh")); // true
// 4. \W ----> [a-zA-Z0-9_]以外的字符
var reg = /^\W+$/
console.log(reg.test("你好")); // true
// 5. \s ----> 特殊字符:空格, 回车符, 换行符, 制表符(tab键)
var reg = /^\s*$/;
console.log(reg.test(`
`)); // true (注意这里故意打的回车)
// 6. \S ----> 除了以上字符以外, 都可以
var reg = /^\S*$/;
console.log(reg.test("你好,我在北京顺义;"));
// 其他的预定义规则:
// 1. 中文:
// \u4e00 是 一
// \u9fa5 是 龥
// \xxxxx 是unicode编码,正好是中文编码的开始和结束的两个字
console.log(/^[\u4e00-\u9fa5]{2,8}$/.test("会飞的企鹅"));
// 2. 密码, 必须是6到16位数字或大小写字母或中划线或下划线组成
var reg = /^[a-zA-Z0-9_-]{6,16}$/;
// 3. 手机号
var reg = /^1[345678]\d{9}$/;
// ^ $ 从头到尾精确模式
// 必须1开头
// 第二部分 [345678] :这6个数字中选出一个!
// 剩余部分:\d{9} 出现9次
console.log(reg.test("13411112222"));
// 4. QQ验证 - 开头是1到9, 最少5位
var reg = /^[1-9]\d{4}$/;
console.log(reg.test(45671));
// 字符串的replace方法中, 可以传入正则表达式
var str = "老师讲课真有激情, 学习千万不能学成书呆子, 这个人有点gay, GaY";
console.log(/(激情|呆子|gay)+/.test(str));
// 屏蔽傻, 激情等词汇
console.log(str.replace(/(激情|呆子|gay)+/, "*"));
// 引出ig的使用
// 正则后, 加g 全局替换(都替换), 加i 忽略大小写
console.log(str.replace(/(激情|呆子|gay)+/gi, "*"));
正则 - 特点
灵活性、逻辑性和功能性非常的强
可以迅速地用极简单的方式达到字符串的复杂控制
不太好理解规则, 犹如火星文一样
实际开发,一般都是直接复制写好的正则表达式. 但是要求会使用正则表达式并且根据实际情况修改正则表达式
// 需求: 输入手机号, 监测是否符合正则判断表达式, 符合后才可以点击发送验证码, 然后做倒计时效果
// 思路: 监测手机号输入框的改变, 影响发送验证码按钮的状态, 给发送验证码按钮绑定点击事件, 做验证码倒计时效果
var thePhone = document.getElementById("phone");
var getCodeBtn = document.getElementById("getCode");
thePhone.oninput = function(){
if(/^1[345678]\d{9}$/.test(this.value)){
getCodeBtn.disabled = false;
} else {
getCodeBtn.disabled = true;
}
}
getCodeBtn.onclick = function () {
getCodeBtn.disabled = true;
thePhone.disabled = true;
var i = 3;
getCodeBtn.value = '验证码已发送' + i;
var timer = window.setInterval(function () {
i--;
getCodeBtn.value = '验证码已发送' + i;
if (i === 0) {
window.clearInterval(timer);
getCodeBtn.value = '获取验证码';
thePhone.disabled = false;
getCodeBtn.disabled = false;
}
}, 1000);
}
实际开发时 - 可以百度找到正则表达式 - 直接使用 (但是要学会读懂和修改)
问题: 什么是闭包
答案: 内层函数引用外层函数中声明的变量就会形成闭包
code:
function fn(){
var a = 100;
function closure(){
console.log(a); // 引用了外层声明的函数
}
closure();
}
fn();
图示:
问题: 什么是内存泄漏
答案: 内存泄漏指任何对象在您不再拥有或需要它之后仍然存在
code:
var seconds = 5;
var t = setInterval(function(){
if (--seconds == 0) {
div.innerHTML = "http://www.itheima.com";
}
}, 1000);
// 虽然内容改了, 但是计时器还在内存中运行, 就会造成内存泄露
问题: 哪些操作会造成内存泄漏
答案:
第一句: 垃圾回收器对变量和对象引用计数, 为0时回收此变量内存
第二句: 意外的全局变量, 会导致内存泄露
第三局: 定时器或计时器或事件监听, 不销毁会导致内存泄露
第四局: 闭包, 控制台打印, 互相引用(在两个对象彼此引用且彼此保留时)
code:
var t = setInterval(function () {
var f = setInterval(function(){
console.log("你好");
}, 1000);
}, 1000);
// 每隔1秒都创建了1个计时器 - 而且内部f计时器从未销毁过
图示: (蓝色表示分配的内存)
问题: call和apply,bind的区别
答案:
第一句: call, apply, bind目的修改函数this的值
第二句: call支持若干参数列表, apply方法接受包含多个参数的数组
第三句: call和apply会马上调用函数执行, 而bind创建一个新的函数并返回, 需要手动调用执行
code
// 1. call方法
function Person(tName, tAge){
this.name = tName;
this.age = tAge;
}
Person.prototype.say = function(){
console.log("人类会说话");};
var per1 = {
};
Person.call(per1, "小黑", 20);
console.log(per1);
// 2. apply方法
function Person(tName, tAge){
this.name = tName;
this.age = tAge;
}
Person.prototype.say = function(){
console.log("人类会说话");};
var per2 = {
};
Person.apply(per2, ["小黑", 20]);
console.log(per2);
// 3. bind方法
function Person(tName, tAge){
this.name = tName;
this.age = tAge;
}
Person.prototype.say = function(){
console.log("人类会说话");};
var per3 = {
};
var newThisFn = Person.bind(per3, "小黑", 20);
newThisFn();
console.log(per3);
// 回答下面打印的结果是多少
function test(){
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = function(){
console.log(i);
}
}
return arr;
}
var myArr = test();
for (var j = 0; j < 10; j++) {
myArr[j]();
}
// 提示: i变量虽然释放不掉, 但是i可以被修改 (注意执行的时机和顺序)
// 解释: test只执行一次, var i 是test作用域下的一个变量 (然后一直被for修改), 最终i的值是10, 所以下面调用arr[i]后面函数体执行时, 根据作用域链向test作用域下找到i访问, 所以都是10
函数类型 | 语法 | 例子 | 特点 | this指向 |
---|---|---|---|---|
函数声明 | function 函数名() {} |
function fn() {} | 有变量提升 | 调用者(window) |
函数表达式 | var 变量名 = function(){} | var fn = function(){} | 没有变量提升 | 调用者(window) |
对象里函数 | {键: function() {}} | {fn: function(){}) | 调用者(对象) | |
事件处理函数 | 1. 事件源.事件类型 = function(){} 2. 事件源.addEventListener(“事件 类型”, function(){}) |
1. btn.onclilck= function(){} 2. btn.addEventListener(“click”, function(){}) |
调用者(事件源) | |
定时器 | setTimeout(function(){}) | setTimeout(function(){}) | 调用者(window) | |
计时器 | setInterval(function(){}) | setInterval(function(){}) | 调用者(window) | |
构造函数 | function 大写开头名() {} | function Person(){} | 配合new使用 | new的新对象 |
匿名函数 | function (){} | function (){} | 一般配合别人使用 | 调用者(得具体看在哪里用) |
立即执行函数 | (function(){}) (); | (function(){}) (); | 结尾必须写分号 | 调用者(window) |
递归函数 | function 函数名(){ 函数名() } 函数名() | function myFn() { myFn() } myFn() | 留好出口 | 调用者(window) |
高阶函数 | 1. function 函数名(形参A) {} 2. function 函数名() { return 函数体} |
— | 参数/返回值是函数体的 - 就是高阶函数 | 调用者(window) |
回调函数 | function a (b) { b() } a(function(){}); |
— | 1. 调用函数A, 传入函数体B 2. 在A中会回调函数体B执行 |
调用者(window) |
元字符 | 示例 | 解释 | 备注 |
---|---|---|---|
具体字符 | /abc/ | 匹配连续出现的abc | 至少出现过abc |
^ | /^abc/ | 以具体连续字符开头 | 至少开头是abc |
$ | /def$/ | 以具体连续字符结尾 | 至少结尾是def |
/^xxx$/ | 精准匹配 | 所有字符都需要满足xxx位置条件 | |
| | /我|你/ | 或者关系 | 至少出现过其中一个一次 |
[] | /[xyz]/ | 一组或者关系 | 至少匹配所包含的任意一个字符 |
* | /a*/ | 0次 - 多次 | 可有可无 |
+ | /a+/ | 1次 - 多次 | 至少出现1次 |
? | /a?/ | 0次 - 1次 | 至少0-1次 相当于{0,1} 只要连续出现过0或1次 |
{n,m} | /e{2,3}/ | 前面表达式至少2-3次 | 连续出现2-3次 |
- | /0-9/ | 连字符(前提连续的) | 匹配这个范围内的任意字符 |
\d | /\d/ | 匹配数字, 相当于[0-9] | 匹配数字 |
\w | /\w/ | 匹配字符, 相当于[a-zA-Z0-9_] | 匹配字符 |
\s | /\s/ | 匹配特殊字符[\t \r \n \v \f] | 匹配特殊字符 |
[\u4e00-\u9fa5] | [\u4e00-\u9fa5] | 这是第一个文字和最后一个文字的Unicode编码 | 匹配所有中文任意一个 |
g | //g | 全局匹配 | 全文匹配 |
i | //i | 忽略大小写 | 大小写都可以匹配 |
身份证匹配: (15和18位的)
var idCardReg = /(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}[0-9Xx]$)/
QQ号码: (5-10位)
var qqReg = /^[1-9][0-9]{4,9}$/
手机号码:
var phoneReg = /^((134\d{4})|((13[0-3|5-9]|14[1|5-9]|15[0-9]|16[2|5|6|7]|17[0-8]|18[0-9]|19[0-2|5-9])\d{8}))$/
如有不足,请多指教,
未完待续,持续更新!
大家一起进步!