闭包:内部函数保存到外部
当内部函数被保存到外部时,将会生成闭包。 闭包会导致原有作用域链不释放,造成内存泄漏(内存占用)
一)闭包的作用
二)闭包作用举例
1、累加器:
题目:定义一个定时器,计算点击网页的次数 这个题目非常简单,想必大家都能写出来。
var count = 0;
function addCount() {
count++;
}
document.body.addEventListener("click", addCount);
复制代码
count作为一个全局变量,其他地方都可以对它进行操作,如果其他地方对count重新赋值或者重新定义count,那么这个计时器就被破坏了。这时候,闭包就起作用了。
function addCount() {
var count = 0;
var addCount = function() {
count++;
}
return addCount;
}
document.body.addEventListener("click", addCount);
点击一次->输出1
点击两次->输出2
复制代码
2、缓存:
function eater(){
var food="apple";
var obj={
eat:function (){
if(food!=""){
console.log("i am eating "+ food);
food="";
}else{
console.log("eat emtpy ");
}
}
push:function(myFood){
food = myFood;
}
}
return obj;
}
var eat1= eater();
eat1.eat();->输出apple
eat1.eat();->输出empty
eat1.push('banana');
eat1.eat();->输出banana
复制代码
看另外一个缓存的例子:
function isFirstLoad(){
var list=[];
return function(option){
if(list.indexOf(option)>=0){
//检测是否存在于现有数组中,有则说明已存在
console.log('已存在')
}else{
list.push(option);
console.log('首次传入');
//没有则返回true,并把这次的数据录入进去
}
}
}
var ifl=isFirstLoad();
ifl("zhangsan");
ifl("lisi");
ifl("zhangsan");
复制代码
在浏览器控制台打印如下:
可以看到,如果外界想访问list变量,只能通过我定义的函数isFirstLoad来进行访问,我对想访问list的外界只提供了isFirstLoad这一个接口。至于怎么操作_list,我已经定义好了,外界能做的就只是使用我的函数,然后传几个不同的参数罢了。
最后顺便说一下,作用域链是在定义的时候就已经确定了,和谁来执行,什么时候执行均没有一毛钱关系。
3. 私有化变量:下面例子输入deng.prepareWife是undefind 形成了私有化变量
function Deng(name,wife){
//正常情况 函数里的var对象 函数执行完了就会被销毁,
但是在这里因为被this.divorce的函数使用被返回了形成了闭包,所以无法销毁。
var prepareWife="xiaozhang";
this.name=name;
this.wife=wife;
this.divorce=function(){
this.wife=prepareWife;
}
this.changePrepareWife=function(target){
prepareWife=target;
}
this.sayPraprewife=function(){
console.log(prepareWife);
}
}
var deng=new Deng('deng','xiaoliu');
复制代码
模拟实现类的私有属性的例子:
function Boy(name){
this.name = name;
var sex = 'boy';
this.saySex = function(){
console.log("my sex is "+sex)
};
}
var xiaoming = new Boy('xiaoming');
console.log(xiaoming.name);
console.log(xiaoming.sex);
xiaoming.saySex();
VM344:16 xiaoming
VM344:18 undefined
VM344:9 my sex is boy
复制代码
4. 立即执行函数解决闭包作用域问题:
立即执行函数(执行完立即销毁) 针对初始化功能的函数 定义:此类函数没有生命,在一起执行过后释放。适合做初始化工作。
function test(){
var arr=[];
for(var i=0;i<10;i++){
(function (j){
arr[j]=function(){
document.write(j+" ");//输为0,1,2,3,4,5,6,7,8,9
}
}(i));
//用立即执行函数(立即执行函数也可以生成自己的作用域)
i作为参数传给j j不会随着i改变而改变
}
return arr;
}
var myArr=test();
for(var j=0;j<10;j++){
myArr[j]();
}
复制代码
- a
- a
- a
复制代码
2. 关于闭包当中的this对象
this对象指的是什么,这个要看函数所运行的环境。如果函数在全局范围内调用 ,函数内的this指向的是window对象。对象中的方法,通过闭包如果运行的环境为window时,则this为window。因为闭包并不是该对象的方法。
var color="red";
function fn(){
return this.color;
}
var obj={
color:"yellow",
fn:function(){
return function(){//返回匿名函数
return this.color;
}
}
}
console.log(fn());//red 在外部直接调用this为window
var b=obj.fn();//b为window下的变量,获得的值为obj对象下的fn方法返回的匿名函数
console.log(b());//red 因为是在window环境下运行,所以this指缶的是window
//可以通过call或apply改变函数内的this指向
console.log(b.call(obj));//yellow
console.log(b.apply(obj));//yellow
console.log(fn.call(obj));//yellow
复制代码
通过变量可以获得上一个作用域中的this指向
var color="red";
function fn(){
return this.color;
}
var obj={
color:"yellow",
fn:function(){
var _this=this;//将this赋值给变量_this
return function(){
return _this.color;//通过_this获得上一个作用域中的this指向
}
}
}
console.log(fn());//red
var b=obj.fn();
console.log(b());//yellow
复制代码
可以通过构造方法传参来访问私有变量
function Desk(){
var str="";//局部变量str,默认值为""
this.getStr=function(){
return str;
}
this.setStr=function(value){
str=value;
};
}
var desk=new Desk();
//为构造函数的局部变量写入值。
desk.setStr("zhangPeiYue");
//获取构造函数的局部变量
console.log(desk.getStr());//zhangPeiYue
作者:前端娃娃
链接:https://juejin.im/post/5d50d5ddf265da03a715c59c
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。