闭包

 

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式就是在一个函数内部创建另一个函数

 

闭包可以用于设计私有的方法和变量,避免全局变量污染,一般应该避免在全局作用域下定义过多的变量及函数。

 

闭包的缺点是会常驻内存,会增大内存使用量,使用不当容易造成内存泄漏,所以只有在绝对必要的情况下才使用闭包。

 

function fn() {

var a = 0;

a++;

return a;

}

console.log(fn());//输出: 1

console.log(fn());//输出: 1

 

以上代码每次调用完 fn() 后,函数内的a变量就会被从内存中销毁,故每次输出的结果都是1,a变量定义在函数内部,函数外部无法访问。如此声明的变量有两个特点:私有、无法长期存在。

 

var a = 0;

function fn() {

a++;

return a;

}

console.log(fn());//输出: 1

console.log(fn());//输出: 2

 

以上代码在全局环境下声明了a变量,a变量此时作为全局变量会长期存在,调用 fn() 函数时只是对全局变量a进行赋值操作。如此声明的变量有两个特点:公开、可以长期存在。

 

如果我们想要包装一个私有且可以长期存在的变量,那么可以使用闭包:

var fn = (function() {

var a = 0;

 

return function() {

a++;

return a;

}

})();

console.log(fn());//输出: 1

console.log(fn());//输出: 2

 

我们在一个外部匿名函数内声明a变量,然后返回一个内部匿名函数,此时,外部匿名函数定义的变量或方法就长期驻存于内存中,且只有这个外部匿名函数及内部匿名函数可以使用这些变量或方法。我们把外部匿名函数即刻调用,将返回结果(内部匿名函数)保存为fn,每次调用fn就会对a变量累加。用闭包包装的变量具有两个特点:私有、可以长期存在。

 

闭包只能取得包装函数中任何变量的最后一个值

 

function createFn() {

var arr1 = [];

for(var i = 0; i < 5; i++) {

arr1[i] = function() {

console.log(i);

};

}

return arr1;

}

var arr2 = createFn();

for(var i = 0; i < arr2.length; i++) {

arr2[i]();//输出的都是: 5

}

 

以上代码中,createFn() 函数内包装了一个长度为5的数组,每个数组元素保存的值是一个函数,整个 createFn() 是一个闭包,每个数组元素包装的函数引用的都是闭包内的i,所以循环结束后i的值变为5,每个包装函数内引用的i亦为5,最终逐个调用这些包装函数输出的都是5。

 

要让每个包装函数返回的值是各自的索引值,只需要添加一个作用域将每个包装函数与闭包分隔开,让每个包装函数引用的值来自这个作用域而不是闭包:

 

function createFn() {

var arr1 = [];

for(var i = 0; i < 5; i++) {

arr1[i] = (function(num) {

return function() {

console.log(num);

}

})(i);

}

return arr1;

}

var arr2 = createFn();

for(var i = 0; i < arr2.length; i++) {

arr2[i]();

}

 

正则

 

一个正则表达式包含两个部分:模式(pattern)和标志(flags)。

 

两个”/”之间的部分成为模式,最后一个”/”后的部分是标志。

 

标志有三种:

  1. g:全局模式,模式将被应用于所有字符串,而非在发现第一个匹配项时立即停止;
  2. i:不区分大小写模式;
  3. m:多行模式。

 

定义一个正则表达式:

var pattern = /at/g;//匹配字符串中所有含有”at”字符的实例

 

字符串对象的正则匹配方法

 

字符串对象与正则匹配相关的方法有match()、search() 和 replace() 三个方法:

  1. match(regexp):regexp 参数是一个正则表达式,match() 会返回一个字符串中符合正则的匹配项数组。
  2. search(regexp):参数同 match(),search() 会返回字符串中符合正则的第一个匹配项的索引。
  3. replace(regexp, newText):第一个参数同样是一个正则表达式,第二个参数是替换内容,replace() 会把字符串中符合正则的匹配项全部替换为第二个参数的内容,最后将结果返回。

 

var str = "123456abcabc";

var pattern = /a/g;

 

console.log(str.match(pattern));//输出: [“a”, “a”]

console.log(str.search(pattern));//输出: 6

console.log(str.replace(pattern, "*"));//输出: “123456*bc*bc”

 

RegExp正则实例

 

var pattern = new RegExp(“a”, “g”);  同 var pattern = /a/g;

 

正则实例对象方法:

  1. exec(str):功能与字符串对象的 match() 方法类似,不同之处在于它返回的只有第一个匹配项。
  2. test(str):只要字符串中有正确匹配到正则表达式的内容就返回 true,否则返回 false。

 

var str = "bcdeafgadfgrgert12345645213";

var pattern = new RegExp(“a”, “g”);

console.log(pattern.exec(str));//输出:[“a”]

console.log(pattern.test(str));//输出:true

 

元字符

 

元字符 说明
. 匹配换行符外的任何字符
\w 匹配字母、数字、下划线,等同于[a-zA-Z0-9_]
\s 匹配空白符
\d 匹配数字
\b 匹配单词分界
| 或匹配
^ 头匹配
$ 尾匹配

 

var str = "this is __123%%C.";

var pattern1 = /\w+/g;

var pattern2 = /\s+/g;

var pattern3 = /\d+/g;

var pattern4 = /\b/g;

var pattern5 = /is|123/g;

 

var pattern6 = /^this/g;

var pattern7 = /C\.$/g;

console.log(str.match(pattern7));

 

反义字符

 

反义字符 说明
[^x] 匹配”x”以外的所有字符,”x”为任意字符
[^xyz] 匹配”x”、”y”、”z”以外的所有字符
\W 匹配字母、数字、下划线以外的任意字符
\S 匹配空格以外的任意字符
\B 匹配单词边界以外的任意字符
\D 匹配数字以外的任意字符

 

var str = "ABC123";

var pattern1 = /[^\d]/g;

console.log(str.match(pattern1));

 

转义字符

 

 

转义字符 说明
\n 匹配换行符
\r 匹配回车符

 

重复匹配

 

匹配字符 说明
+ 重复出现一次以上
? 重复出现零次或一次
{n} 重复出现n次
{n,m} 重复出现n到m次,n<m

 

var str = "123abc12ab1a";

var pattern1 = /\d+/g;

var pattern2 = /\d{2}/g;

var pattern3 = /\d{2,3}/g;

console.log(str.match(pattern3));

 

常用正则表达式

 

  1. 匹配中文字符:/[\u4e00-\u9fa5]/
  2. 匹配电子邮箱:/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/
  3. 匹配手机号码:/^1[3,4,5,7,8]\d{9}$/

 

代码清单:

"use strict";

 

// //局部变量:私有、无法长期存在

// //当执行完函数后,函数内的局部变量就会自动销毁

// function fn1() {

//     var a = 0;

//     a++;

//     return a;

// }

// console.log(fn1());//输出:1

// console.log(fn1());//输出:1

 

 

// //全局变量:公开、长期存在

// //fn2()只是给全局变量赋值

// var a = 0;

// function fn2() {

//     a++;

//     return a;

// }

// console.log(fn2());//输出:1

// console.log(fn2());//输出:2

 

 

// //闭包包装的变量:私有、长期存在

// var fn3 = (function() {

//     var a = 0;

//     return function() {

//         a++;

//         return a;

//     }

// })();

// console.log(fn3());//输出:1

// console.log(fn3());//输出:2

 

 

// //使用闭包包装接口

// var fn4 = (function() {

//     var a = 0,

//         b = 0,

//         c = 0;

//     return {

//         addA: function() {

//             a++;

//             return a;

//         },

//         addB: function() {

//             b++;

//             return b;

//         },

//         addC: function() {

//             c++;

//             return c;

//         }

//     };

// })();

// console.log(fn4.addA());

// console.log(fn4.addB());

// console.log(fn4.addC());

// console.log(fn4.addA());

 

 

// //每个数组元素包装函数引用的是闭包环境下的i,i最后变为5,所以这五个函数输出的都是5(最后i的值)

// function create1() {

//     var arr1 = [];

//     for(var i = 0; i < 5; i++) {

//         arr1[i] = function() {

//             console.log(i);

//         }

//     }

//     return arr1;

// }

// var arr2 = create1();

// for(var i = 0; i < arr2.length; i++) {

//     arr2[i]();

// }

 

 

// //将五个包装函数各用一个新的闭包包装起来,每个闭包内的num值就是大闭包对应的i的值,包装函数获取的就是这个值,所以最后能输出各自的索引号

// function create2() {

//     var arr1 = [];

//     for(var i = 0; i < 5; i++) {

//         arr1[i] = (function(num) {

//             return function() {

//                 console.log(num);

//             }

//         })(i);

//     }

//     return arr1;

// }

// var arr3 = create2();

// for(var i = 0; i < arr3.length; i++) {

//     arr3[i]();

// }

 

 

// var str = "bcdeafgadfgrgert12345645213";

// var pattern = /a/g;

// console.log(str.match(pattern));

// console.log(str.search(pattern));

// console.log(str.replace(pattern, "*"));

//

// //屏蔽敏感词

// var str1 = "fuck";

// var pattern1 = /[uc]/g;

// console.log(str1.replace(pattern1, "*"));

//

// console.log(pattern.exec(str));

// console.log(pattern.test(str));

 

 

// var str = "this is __123%%C.";

// var pattern1 = /\w+/g;

// var pattern2 = /\s+/g;

// var pattern3 = /\d+/g;

// var pattern4 = /\b/g;

// var pattern5 = /is|123/g;

//

// var pattern6 = /^this/g;

// var pattern7 = /C\.$/g;

// console.log(str.match(pattern7));

 

 

// var str = "ABC123";

// var pattern1 = /[^\d]/g;

// console.log(str.match(pattern1));

 

// var str = "123abc12ab1a";

// var pattern1 = /\d+/g;

// var pattern2 = /\d{2}/g;

// var pattern3 = /\d{2,3}/g;

// console.log(str.match(pattern3));

 

// var str1 = "哈sda水da货啊";

// var pattern1 = /[\u4e00-\u9fa5]/g;

// console.log(str1.match(pattern1));

//

// var str2 = "wjt13415156317@yahoo.com";

// var pattern2 = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/g;

// console.log(pattern2.test(str2));

//

// var str3 = "13415156317";

// var pattern3 = /^1[3,4,5,7,8]\d{9}$/g;

// console.log(pattern3.test(str3));

 

欢迎留言