函数闭包
闭包(closure)
是JavaScript语言的一个难点,也是JavaScript的一个特色,很多高级的应用都要依靠闭包来实现。
// 1.里面可以访问外面的变量
var num = 10;
function outer() {
console.log(num);
}
outer();
//2. 外面想访问里面的变量怎么办?
function outer() {
var num = 10;
return num; // num + 20;
}
var res = outer();
console.log(res);
//3. 外面想操作修改这个变量怎么办??
// 上面的例子只是返回,有多少返回多少,就算你在这里运算也是
// 返回多少就是多少,也是死的
function outer() {
var num = 10;
function inner(n) {
num = n;
console.log(num);
}
// 这里依然是内部操作者的
inner(50)
}
outer();
//4. 终极版 : 外面想操作函数内部的数据
function outer() {
var num = 10;
function inner(n) {
num = n;
console.log(num);
}
return inner;
}
var f = outer();
f(60);
闭包的概念
百度百科 : 闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
维基百科 : 闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数
总结 : 在JavaScript中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。
**闭包中包含了内部函数的代码,以及所需外部函数中的变量的引用 **
产生闭包的条件
// 当内部函数访问了外部函数的变量的时候,就会形成闭包。
// scope 作用域
function outer() {
var num = 10;
function inner() {
console.log(num); // 产生
console.log(11); // 不产生
}
return inner;
}
outer()();
闭包的应用
计数器闭包的应用
需求:统计一个函数的调用次数
var count = 0;
function fn(){
count++;
console.log("我被调用了,调用次数是"+count);
}
fn();
fn();
fn();
缺点:count是全局变量,不安全。
使用闭包解决这个问题!!!!
function outer(){
var count = 0;
function add(){
count++;
console.log("当前count"+count);
}
return add;
}
var result = outer();
result();
result();
result();
闭包的作用:
- 把变量保护起来 ()
- 这些变量的值始终保持在内存中 ==> 应用
私有变量
使用闭包实现私有变量的读取和设置
function outer(){
var num = 10;
function set_num(n){
num = n;
}
function get_num(){
return num;
}
return {
set_num:set_num,
get_num:get_num
}
}
var obj = outer();
obj.set_num(2000);
console.log(obj.get_num());
【抓娃娃游戏案例.html】
闭包存在的问题
闭包占用的内存是不会被释放的,因此,如果滥用闭包,会造成内存泄漏的问题。闭包很强大,但是只有在必须使用闭包的时候才使用。
js的垃圾回收机制
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Memory_Management
- 内存:计算机中所有程序的运行都是在
内存
中进行的,因此内存的性能对计算机的影响非常大,运行程序需要消耗内存,当程序结束时,内存会得到释放。 - javascript分配内存:当我们定义变量,javascript需要分配内存存储数据。无论是值类型或者是引用类型,都需要存储在内存中。
- 垃圾回收:当代码执行结束,分配的内存已经不需要了,这时候需要将内存进行回收,在javascript语言中,
垃圾回收机器
会帮我们回收不再需要使用
的内存。
引用记数法清除
引用记数垃圾收集:如果没有引用指向某个对象(或者是函数作用域),那么这个对象或者函数作用域就会被垃圾回收机制回收。
var o = {
name:"zs"
}
//对象被o变量引用 ,引用记数1
var obj = o; //变量被o和obj引用,引用记数2
o = 1; //o不在引用对象了, 引用记数1
obj = null; //obj不在引用对象了,引用记数0,可以被垃圾回收了。
标记清除法清除
使用引用计数法进行垃圾回收的时候,会出现循环引用导致内存泄漏的问题。因此现代的浏览器都采用标记清除法来进行垃圾回收。
这个算法假定设置一个叫做根(root)的对象(在Javascript里,根是全局对象Window)。定期的,垃圾回收器将从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和所有不能获得的对象。
从2012年起,所有现代浏览器都使用了标记-清除垃圾回收算法。
闭包占用内存释放
function outer(){
var count = 0;
function fn(){
count++;
console.log("执行次数"+count);
}
return fn;
}
var result = outer();
result();
result = null;//当函数fn没有被变量引用了,那么函数fn就会被回收,函数fn一旦被回收,那么outer调用形成的作用域也就得到了释放。
思考: 面试题
点击不同的按钮,打印对应不同的下标:
var buttons = document.querySelectorAll('button'); console.log(buttons);
// 方法1 : buttons[i].index = 1; // 方法2 : 如果面试有需求,只能用闭包
for ( var i = 0 ; i < buttons.length ; i++) { (function (i) { // var i = i; // 为什么可以了 //1. 这里就相当于 console.log(i) //0---9 //2. 这里是自调用一个外函数,,里面有个i, 然后最里面有个 function // 其实就是一个闭包 //3. 每一次调用否分配一个空间,每个空间里,都有一个变量i 和 一个内函数 buttons[i].onclick = function () { console.log(i); } })(i); }每隔一秒钟打印一个数字: 1, 2,3,4,5,6,7,8,9,10 ..... setTimeout打印
for ( var i = 1 ; i <= 10 ; i++) {
// i 又流失了,,应该保存起来
// 点击和这个异步都是遍历之后会执行的
// 闭包
(function (i) {
setTimeout(function () {
console.log(i);
},i*500)
})(i);
}
-
正则表达式
正则表达式:用于匹配规律规则的表达式,正则表达式最初是科学家对人类神经系统的工作原理的早期研究,现在在编程语言中有广泛的应用,经常用于表单校验,高级搜索等。
创建正则表达式
构造函数的方式
var regExp = new RegExp(/\d/);
正则字面量
var regExp = /\d/;
正则的使用
/\d/.test("aaa1");
元字符
正则表达式由一些普通字符和元字符组成,普通字符包括大小写字母、数字等,而元字符则具有特殊的含义。
常见元字符
特殊字符换 http://www.w3school.com.cn/js/js_special_characters.asp
优先级
|`表示或,优先级最低
()
优先级最高,表示分组
字符类的元字符
[]
在正则表达式中表示一个字符的位置,[]里面写这个位置可以出现的字符。
console.log(/[abc]/);//匹配a,b,c
[^]
在中扩号中的^表示非的意思。 是否包括除了XX以外的字符串
//^表示该位置不可以出现的字符
//[^0]:除了0以外的字符
console.log(/[^0]/.test("1aaa000"));
console.log(/[^0]/.test("a"));
[a-z]
[1-9]
表示范围
console.log(/[a-z]/.test("d"));//小写字母
console.log(/[A-Z]/.test("d"));//大写字母
console.log(/[0-9]/.test("8"));//数字
console.log(/[a-zA-Z0-9]/);//所有的小写字母和大写字母以及数字
边界类元字符
我们前面学习的学习的正则只要有满足的条件的就会返回true,并不能做到精确的匹配。
^表示开头 []里面的^表示取反
$表示结尾
console.log(/^chuan/.test("dachuan"));//必须以chuan开头
console.log(/chuan$/.test("chuang"));//必须以chuan结尾
console.log(/^chuan$/.test("chuan"));//精确匹配chuan
//精确匹配chuan,表示必须是这个
console.log(/^chuan$/.test("chuanchuan"));//fasle
量词类元字符
量词用来控制出现的次数,一般来说量词和边界会一起使用
//量词用来控制出现次数的
//console.log(/a/.test("abc"));
//console.log(/^a/.test("abc"));
//console.log(/^a$/.test("abc"));
*
表示能够出现0次或者更多次,x>=0;+
表示能够出现1次或者多次,x>=1?
表示能够出现0次或者1次,x=0或者x=1{n}
表示能够出现n次{n,}
表示能够出现n次或者n次以上{n,m}
表示能够出现n-m次
思考:如何使用{}来表示*+?
正则的使用
注意 , 学习目的
正则测试
验证座机
- 比如010-12345678 0797-1234567
- 开头是3-4位,首位必须是0
- -后面是7-8位
var phoneReg = /^0\d{2,3}-\d{7,8}$/;
验证姓名
- 只能是汉字
- 长度2-6位之间
- 汉字范围[\u4e00-\u9fa5]
var nameReg = /^[\u4e00-\u9fa5]{2,6}$/;
验证QQ
- 只能是数字
- 开头不能是0
- 长度为5-11位
var qqReg = /^[1-9]\d{4,10}$/;
验证手机
- 11位数字组成
- 号段13[0-9] 147 15[0-9] 177[0178] 18[0-9]
var mobileReg = /^(13[0-9]|147|15[0-9]|17[0178]|18[0-9])\d{8}$/;
验证邮箱
- 前面是字母或者数字
- 必须有@
- @后面是字母或者数字
- 必须有.
- .后面是字母或者数字
var emailReg = /^\w+@\w+(\.\w+)+$/;
正则替换 replace
var str = " 123AD asadf asadfasf adf ";
1 替换掉字符串中的所有空白
2. 将所有的ad替换成xx i:忽略大小写
3. 将所有的ad/AD替换成xx
var str = abc,efg,123,abc,123,a
4. 所有的逗号替换成句号
var jsonStr = '[{"name":"张三",score:80},{"name":"张三",score:90},{"name":"张三",score:81}]';
5. 把所有成绩都修改成100分
正则匹配 match
//需求:
var str = "我的手机号是:18511241111, 我的女朋友的手机号是:13211111111,我的前女友的手机号是:18522223333,我的前前女友的手机号是:18511112293";
//需求:把字符串中所有的手机号找出来。
console.log(str.match(/1[3-9]\d{9}/g));
正则提取 exec => 数组
//今天是2018-05-11, 要求;得到年月日;
var str = "今天是2018-05-11, 要求;得到年月日"
// 提取
// var reg = /(\d{4})-(\d{2})-(\d{2})/;
var reg = /\d{4}-\d{2}-\d{2}/;
字符串总结:
//正则表达式只有:2个: test:测试 exec:提取
reg.test()
reg.exec()
//字符串有两个方法: replace match: 支持参数传正则
str.replace()
str.match();
//正则的使用:
//1. 字符串的replace: 正则的替换
//2. 字符串的匹配:match: 匹配某个字符串中所有符合规律的字符串。
//3. 正则的测试:test: 表单校验,判断某个字符串是否符合正则的规律
//4. 正则的提取: 提取匹配的字符串的每一个部分。 ()进行分组
← sass的使用 说说CSS学习中的瓶颈 →