js 回调函数 this 丢失 闭包解决问题

之前也遇到过构造函数访问this 找不到的问题,当时的解决办法就是把this改成生成的实例化对象,比如var fo=Func(),this直接就用fo代替,这样无怎么调用都不会出现this找不到(因为没有this了!!!~_~) 

回调函数 this丢失

  举个例子:

//创建一个构造函数
var Func=function(){
	this.age=12;
	this.say=function(){
		console.log("age="+this.age);
	};
}
//生成实例化对象fo
var fo=new Func();
//调用fo的方法say
fo.say()//age=12
//创建一个回调方法,调取其他方法
function callback(cal){
	if(typeof(cal)=="function"){
		cal&cal();
    }
}
//回调函数调用fo.say(),此时的this是window ,this.age就是undefined
callback(fo.say)//age=undefined

 回调函数调用fo.say(),此时的this是window ,this.age就是undefined.

产生this丢失的现象,有两个方向可以思考1:实例的方法,this.say的含义作用是不是这个问题,2;回调函数回调的方法是只调用方法本身吗!,打断点去看下回调地方具体的参数传递,

首先我们看到fo.say这个方法显示anonymous()(匿名函数),再看cal方法显示的function(){console.log''age="+this.age)}这也显然是个匿名函数,

知识点一:

  一般一个函数的定义有三种模式

函数关键字(function)语句:

1:function fn(x){ console.log("age"); }

2:函数字面量(Function Literals):

var fn = function(x){ console.log("age");}

3:Function()构造函数:

var fn= new Function();

第1种就是最常用的方法,后两种都是把一个函数复制给变量fn,而这个函数是没有名字的,即匿名函数。

(当然字面量函数也可以是有名函数var fn=function fnx(){};此时的fnx是方法名,这个方法名是没办法外部调用的,但可以内部调用)

在构造函数中Func中this.say=function(){}是函数字面量的方法,且this.say指代的函数是匿名函数,当我们调用fo.say()这个方法时,内部的this指的就是fo,但是当我们回调时,this就不是fo而是window,

到当回调的时候,callback(cal)中的cal的指代是function(){console.log("age="+this.age);}匿名实体方法(这里其实是内存中的地址),而不是之前的fo.say,的方法体,这个有点绕,多体会两遍,cal是参数,fo.say传入后就不再是fo.say了,他传入的是function(){console.log("age="+this.age);}的地址,和fo.say()直接调用的区别在执行环境不同,,换句话就是我把方法的地址告诉你,你调用你就是他的执行环境this指的就是你的执行环境(或window 是this)

复习知识点2:

//基本类型
var a=4;
function funcA(a){
	++a;
	console.log(a)
}
funcA(a);//5
console.log(a);//4
//引用类型


var obj= new Object();
    obj.age=2;
function funcB(b){
	b.age++;
	console.log(b.age)
}
funcB(obj);//3
console.log(obj.age);//3

javascript中所有函数的参数都是按值传递的。也就是说,把函数外部的值复制到函数内部的参数,就和把值从一个变量复制到另一个变量一样.在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(命名参数或arguments对象的一个元素);在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部.(基本类型:string,number,boolean,null,undefined。引用类型:Function,Array,Object)这里的引用类型是Function,比Object多了层this执行环境的因素。

解决方法:

常规方法:

使用call,apply保存this

//创建一个构造函数
var Func=function(){
	this.age=12;
	this.say=function(){
		console.log("age="+this.age);
	};
}
//生成实例化对象fo
var fo=new Func();
//调用fo的方法say
fo.say()//age=12
//创建一个回调方法,调取其他方法
function callback(cal,obj){
	if(typeof(cal)=="function"){
		cal&cal.apply(fo);
    }
}
//回调函数调用fo.say(),此时的this是window ,this.age就是undefined
callback(fo.say,fo)//age=12

还有一种非 常规,但是看上去虽然差不多的方式但原理却很不一样:

//创建一个构造函数
var Func=function(){
	this.age=12;
	this.say=function(){
		console.log("age="+this.age);
	};
}
//生成实例化对象fo
var fo=new Func();
//调用fo的方法say
//fo.say()//age=12
//创建一个回调方法,调取其他方法
function callback(obj,cal){
	if(typeof(obj[cal])=="function"){
		obj[cal]&obj[cal]();
    }
}
//回调函数调用fo.say(),此时的this是window ,this.age就是undefined
callback(fo,"say")//age=12

 

补充说明下:

回调方法除了上面的还可以是setTimeout(fo.say,500);用立即执行函数解决也可以用bind(this)


//创建一个构造函数
var Func=function(){
	this.age=12;
	this.say=function(){
		console.log("age="+this.age);
	};
}
//生成实例化对象fo
var fo=new Func();
//调用fo的方法say
//fo.say()//age=12
//创建一个回调方法,调取其他方法
function callback(cal){
	if(typeof(cal)=="function"){
		cal&cal();
    }
}
//回调函数调用fo.say(),此时的this是window ,this.age就是undefined
//callback(fo.say)//age=undefined

setTimeout(fo.say,500);//age=undefined
用,bind(this)传进去
setTimeout(function(){
		fo.say();//age=12
	}.bind(fo),500);
//立即执行函数构建闭包保存主体
(function (obj){
	setTimeout(function(){
		obj.say();//age=12
	},500);
})(fo)

或者ajax的异步回调。在都是的时候这个原理。有问题多留言多交流

//立即执行函数构建闭包保存主体
(function (obj){
    setTimeout(function(){
        obj.say();//age=12
    },500);
})(fo)

//立即执行函数构建闭包保存主体
(function (obj){
    setTimeout(function(){
        obj.say();//age=12
    },500);
})(fo)

//立即执行函数构建闭包保存主体
(function (obj){
    setTimeout(function(){
        obj.say();//age=12
    },500);
})(fo)

重要的方法写三遍

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值