关于this
原创
©著作权归作者所有:来自51CTO博客作者凯小默的博客的原创作品,请联系作者获取转载授权,否则将追究法律责任
说明
《你不知道的JavaScript》学习笔记。
为什么要用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,那就需要给 identify() 和 speak() 显式的传入一个上下文对象。
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
随着使用模式越来越复杂,显式传递上下文对象会让代码变得越来越混乱,使用 this 则不会这样。
this 提供了一种更优雅的方式来隐式“传递” 一个对象引用, 因此可以将 API 设计得更加简洁并且易于复用。
误解
两种常见的对于 this 的错误解释。
1、指向自身
1、先看一个例子:想要记录一下函数 foo 被调用的次数。
function foo(num) {
console.log( "foo: " + num );
// 记录 foo 被调用的次数
this.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 ); // 0
console.log( count ); // NaN
显然 foo() 里的 this 不是指向那个函数对象,虽然属性名相同,跟对象却不相同。
2、再看下面两个函数
function foo() {
foo.count = 4; // foo 指向它自身
}
setTimeout( function(){
// 匿名(没有名字的) 函数无法指向自身
}, 10 );
代码分析:
- 1、
foo()
函数是具名函数,在它的内部可以使用 foo 来引用自身 - 2、传入
setTimeout()
的回调函数是匿名函数,无法从函数内部引用自身
3、解决方法
- 1、使用 foo 标识符替代 this 来引用函数对象
- 2、强制 this 指向 foo 函数对象
方法1:
function foo(num) {
console.log( "foo: " + num );
// 记录 foo 被调用的次数
foo.count++;
}
方法2:
var i;
for (i=0; i<10; i++) {
if (i > 5) {
// 使用 call(..) 可以确保 this 指向函数对象 foo 本身
foo.call( foo, i );
}
}
2、它的作用域
- this 在任何情况下都不指向函数的词法作用域。
- 在 JavaScript 内部, 作用域确实和对象类似, 可见的标识符都是它的属性。
- 作用域“对象” 无法通过 JavaScript 代码访问, 它存在于 JavaScript 引擎内部。
this到底是什么
当一个函数被调用时, 会创建一个活动记录(有时候也称为执行上下文
)。 这个记录会包含函数在哪里被调用(调用栈
)、 函数的调用方法、 传入的参数等信息。 this 就是记录的其中一个属性, 会在函数执行的过程中用到。
- this 是在运行时进行绑定的, 并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。
- this 的绑定和函数声明的位置没有任何关系, 只取决于函数的调用方式。