在JavaScript中为什么会存在this,它是什么?有什么用?在JavaScript中为,this为什么会发生变化?
在面向对象的编程语言中,我们常常能够在函数或者方法中使用this或者self等关键词,在这里self/this指当前所在对象。
让我们先以一个实际例子开始:
在面向对象语言中,以Objective-C为例,我们先定义一个类。
main.m
@interface ClassA : NSObject
@property(nonatomic,copy)NSString * name;
-(void)sayName;
+(void)SayHello;
@end
@implementation ClassA
-(void)sayName {
// 伪代码
NSLog(self.name);
}
+(void)SayHello {
NSLog(@"class say hello");
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"Hello, World!");
ClassA * obj = [[ClassA alloc]init];
obj.name = @"zhang san";
[obj sayName];
}
return 0;
}
现说结果:上面的代码会打印zhang san。
在这里,self就代表着obj,也就是方法sayName 所在的对象。
在Objective-C中,你可以在实例方法(-开头)中直接调用self,但是在类方法(+开头)中调用selfXcode会报错。
上面说了,在OC的类方法中是不能直接调用self关键字。因为OC被设计为一个纯粹面向对象的语言,是不存在函数这一概念的,只有对象和方法。
在JavaScript中就不一样了。JavaScript并不是一个纯粹的面向对象语言,它即支持面向对象编程又支持函数式编程的范式。因此,函数被设计为一等公民,可以直接执行,可以把函数赋值给变量和对象的属性,也可以当作参数传入其他函数,或者作为函数的结果返回。它可以独立于对象而存在。
同时,javaScript为了支持面向對象的编程范式,因此在函数中内置了关键字this,通过this可以拿到函数当前的执行对象。代码如下:
function test () {
console.log(this.name)
}
const name = 'li si'
test()
在浏览器中,上面的代码会打印li si。此时,函数没有处于对象中,那么他是如何找到this的呢?这里不得不提及一个概念,那就是环境。是的,在JS中,函数的执行可以不依赖对象,直接依赖环境。在这里,函数是在一个隐式的全局环境中被调用,这个环境不但定义了 test 函数和 name 变量,同时也调用了test,然后this的指向就呼之欲出了。
上面两段代码中无论是self还是this都没有作为参数,直接被传入,但是在方法/函数执行时,却能找到这个值,这是语言(运行时)引擎的功劳。我们可以看作self,this被隐式传入了函数之中,引擎运行时会自动查找当前运行的对象/环境。
从上得知,以下几个问题的答案
- this是什么?答:语言内置的关键字,被隐式传入函数/方法中,运行时引擎会自动查找。
- this代表什么?答:当前方法/函数运行时所在的对象/环境。
- 在JavaScript中,this为什么会发生变化,而面向对象语言中不会?答:因为JS中,this的存在不受限制,函数的调用不受限制。this代表运行时所处对象,当执行时所处对象发生变化时,this也就发生变化了。而在面向对象语言中,self关键字只存在于对象的方法中,且只能被对象本身调用,所以只代表定义时所处的对象。
一些注意事项
- 函数中定义函数,this不指向外部,而指向顶层对象。
- 回调函数中的this指向会发生改变,因为回调函数的调用对象发生了变化
var o = {
f1: function () {
console.log(this);
var f2 = function () {
console.log(this);
};
return f2
}
}
o.f1()()
// Object
// Window
var o = new Object();
o.f = function () {
console.log(this === o);
}
// jQuery 的写法
// 回调函数被DOM对象调用
$('#button').on('click', o.f);
// false