首先看一段代码,你能说出控制台的打印结果吗?
var o = {
m : function(){
console.log(this === o);
var self = this;
f();
function f(){
console.log(this === o);
console.log(self === o);
}
}
};
o.m();
不卖关子,结果是true, false , true。
要弄清楚这个问题,要从函数定义说起。
函数定义有函数语句和函数表达式2种方式,最明显的区别是函数表达式会赋值给一个变量。
//函数语句 ---- 计算阶乘的递归函数
function factorial(x){
if(x<=1) return 1;
return x * factorial(x-1);
}
// 函数表达式,注意我们把它赋值给了一个变量
//函数表达式可以包含名称,这在递归时很有用
var f = function fact(x){
if( x <= 1 ) return 1;
return x * fact(x-1);
}
更多的区别是:声明语句可以在定义之前调用。以表达式定义的函数,无法在定义之前调用。因为变量声明可以提前,但是变量赋值不会提前。
然后我们要明白函数调用的几种方式,不同方式调用函数this有区别。有四种方式来调用函数:作为函数调用、作为方法调用、作为构造函数调用和通过函数的apply()和call()方法调用。
这里用到了前两种方法。
作为函数调用,ES3和非严格模式下ES5规定,this的值是全局对象;严格模式下,this则是undefined
作为方法调用,方法是保存在对象属性里的函数。方法调用的this值是该对象。
这里控制台打印第一条语句时是调用o.m(),m是对象o的一个方法,因此这里是作为方法调用。
控制台打印第二条语句时是调用 f() 方法,是作为函数调用,所以this 指向全局对象或是undefined,而不是指向对象 o 自身,因此全等判断的结果为false。
如果在嵌套函数里想访问外部函数的this值,需要将this值保存在一个变量里,比如这里的“ var self = this; ” ,这个变量和内部函数都在同一个作用域内。这就是控制台打印第三条语句结果为true的原因。
可以直接打印出this查看指代的内容: