this在JavaScript中是一个很特别的关键字,它被自动定义在所有的函数作用域中。
为什么要使用this呢?下面我们看一个例子:
function idenitfy() {
return this.name.toUpperCase();
}
function speak() {
var greeting = 'hello' + idenitfy.call(this);
console.log(greeting);
}
var me = {
name: 'kelly'
};
var you = {
name: 'ready'
}
idenitfy.call(me); //KELLY
idenitfy.call(you); //READY
speak.call(me); //hello KELLY
speak.call(you); //hello READY
如上这段代码,idenitfy和speak可以在不同的上下文对象中重复使用,这里指的上下文是me和you。
如果不使用this的话,那么要个idenitfy和speak显示的传入一个上下文对象。
var me = {
name: 'kelly'
};
var you = {
name: 'ready'
}
function idenitfy(context) {
return context.name.toUpperCase();
}
function speak(context) {
var greeting = 'hello' + idenitfy(context);
console.log(greeting);
}
idenitfy(you); //READY
speak(me); //hello KELLY
然而,this提供了一种更加优雅的方式来隐式的传递一个对象的引用,因此可以将API设计的更加简洁并且易于复用。
关于this的理解我们先从常见的误解开始,因为你知道它是错误的后才知道它什么才是正确的。
首先,一般会从字面意思来理解,把this理解成指向函数自身。我们先思考一下下面的代码:
function foo(num) {
console.log('foo:' + num);
this.count ++;
}
foo.count = 0;
var i;
for(i=0; i<10; i++) {
if(i > 5){
foo(i);
}
}
foo(6); // foo: 6
foo(7); //foo: 7
foo(6); // foo: 8
foo(7); //foo: 9
console.log(foo.count); // 0
看下以上代码的执行情况,foo函数执行了四次,但是foo.count的值任然为0;显然this指向的并不是当前的函数。
如果要从函数对象内部引用它自身,那只有使用this是不够的,一般来说你需要通过一个指向函数对象的词法标识符来引用。
function foo() {
foo.count = 4;
}
setTimeout(function() {
//匿名,函数无法指向自身
}, 10)
如上,通过函数名来引用自身,还有一中比较老的方法就是通过arguments.callee来引用当前正在执行的函数对象。
第二种常见理解错误的是将this理解为当前函数作用域,需要明确的是this在任何情况下都不指向函数的词法作用域,在JavaScript中作用域确实和对象类似,可见的标识符都是它的属性,但是作用域对象无法通过JavaScript代码进行访问,它是存在于JavaScript引擎的内部。
那么this到底是什么?我们知道this是在运行的时候进行绑定的,并不是在编写的时候绑定的,它的上下文取决于函数调用时的各种条件,this的绑定和函数的声明位置没有任何关系,只取决于函数的调用方式。
当一个函数被调用时,会创建一个活动记录(执行上下文),这个记录会包括函数是在哪里被调用的,调用的方式,传入的参数信息等。this就是这个记录的一个属性,会在函数执行的过程中用到。
在后面我们将对this进行全面的分析。