1.1 为什么要用this
以在不同的上下文对象中重复使用函数,不用针对每个对象编写不同版本的函数。
示例代码
function identify() {
return this.name.toUpperCase();
}
function speak() {
var greeting = "Hello, I'm " + identify.call(this);
console.log(greeting);
}
var me = {
name: "Kyle"
};
var you = {
name: "Reader"
};
identify.call(me); // KYLE
identify.call(you); // READER
speak.call(me); // Hello, 我是 KYLE
speak.call(you); // Hello, 我是 READER
不使用this的情况下,需要给函数传递一个上下文对象,比如
function identify(context) {
return context.name.toUpperCase();
}
function speak(context) {
var greeting = "Hello, I'm " + identify(context);
console.log(greeting);
}
var me = {
name: "Kyle"
};
var you = {
name: "Reader"
};
identify(you); // READER
speak(me); //hello, 我是 KYLE
1.2 误解
1.2.1 指向自身
this 并不指向函数自身
console.log(window.count) //undefined
function foo(num) {
console.log("foo: " + num);
// 记录 foo 被调用的次数
this.count++;
}
foo.count = 0; // 向foo函数本身添加一个属性count,但是调用时的this并不是指向foo函数
var i;
for (i = 0; i < 10; i++) {
if (i > 5) {
foo(i);
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo 被调用了多少次?
console.log(foo.count); // 0 -- WTF?
console.log(window.count)//NaN
要从函数内部指向或引用函数自己,必须使用函数自身的标识符
- 具名函数可以通过名字指向自身
- 匿名函数无法指向自身
function foo() {
foo.count = 4; // foo 指向它自身
}
setTimeout( function(){
// 匿名(没有名字的)函数无法指向自身
}, 10 );
所以,需要解决上面count的问题,有两种方式
一、使用 foo 标识符替代 this 来引用函数对象
function foo(num) {
console.log( "foo: " + num );
// 记录 foo 被调用的次数
foo.count++;
}
foo.count=0
var i;
for (i=0; i<10; i++) {
if (i > 5) {
foo( i );
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo 被调用了多少次?
console.log( foo.count ); // 4
二、强制 this 指向 foo 函数对象,使用call函数
function foo(num) {
console.log( "foo: " + num );
// 记录 foo 被调用的次数
// 注意,在当前的调用方式下(参见下方代码),this 确实指向 foo
this.count++;
}
foo.count = 0;
var i;
for (i=0; i<10; i++) {
if (i > 5) {
// 使用 call(..) 可以确保 this 指向函数对象 foo 本身
foo.call( foo, i );
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo 被调用了多少次?
console.log( foo.count ); // 4
1.2.2 它的作用域
需要明确的是,this 在任何情况下都不指向函数的词法作用域。
function foo() {
var a = 2;
console.log(this, this.bar);//window对象,bar函数
this.bar();
}
function bar() {
console.log(this);//window对象
console.log(this.a);//undefined
}
foo();
这里和书的行为不一致
- 书中说this.bar()不能成功,实际上Eage中成功调用了
- 书中说foo()会抛出引用异常,实际在Eage中打印了undefined
1.3 this到底是什么
this 是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。
- this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式
- 当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this 就是记录的其中一个属性,会在函数执行的过程中用到。