之前也遇到过构造函数访问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)
重要的方法写三遍