前言
在代码之中,我们经常会遇到this,一般都会说它指的是函数上下文,本文从各个场景说明this含义。
可能指向有哪些呢?
全局对象
在大环境中,this指向全局对象,比如浏览器环境的this是window对象,vue组件中的this指向的是vue对象。(不考虑node环境) 备注:如果你在浏览器环境中的函数使用this,然后直接调用函数而不是实例化,此时的this是window而不是函数(非严格模式下)。
function fn1(){
console.log(this);
}
fn1();//window
var app=new Vue(){
data:{
}
methods:[
test:function(){
console.log(this);//vue
}
]
};
作为对象的属性
说明,对象中的属性函数中的this指向的是对象本身,但是当你把它的函数部分当做函数的时候,this又会指向浏览器的window(浏览器环境下);
// 对象属性函数中的this指的是当前对象
var name="app"
var o={
name:'test',
sayName:function(){
console.log(this.name);
}
}
o.sayName();//test
// 赋值对象属性中的函数时 此时函数为普通函数,获取的this是window
var sayName2=o.sayName;
sayName2();//app
//对象属性函数中在定义函数,此时的this也是window.
var person={
sayName:function(){
(function(){
console.log(this);
})()
}
}
person.sayName();//window
// 临时赋值this到闭包函数中
var person={
sayName:function(){
var that=this;
(function(that){
console.log(that);
})(that)
}
}
person.sayName();//sayName(){}
作为 call/apply/bind 方法的调用
其中call,apply是改变上下文的,本身不是专门做继承的,这点要理解好。(bind绑定的是新函数,后面补充说明),注意call是对象指向加参数列表,apply是对象指向加数组。
var animal=function(name){
this.name=name;
this.yell=function(){
return this.name;
}
}
var dog=function(name){
animal.call(this,name);
}
var xiaogou=new dog('xiaogou');
console.log(xiaogou.yell());//xiaogou
作为构造函数使用
此时必须通过new关键字实例化,this才会指向新建的对象,如果按照普通函数执行,就会指向window,如第一种情况的描述。另外需要注意的是,如果函数显性的返回一个对象,那么返回的将是你定义的对象,而不是this对象,只有在返回非对象类型或者不返回时返回的才是this对象。
var animal=function(name){
this.name=name;
this.yell=function(){
return this.name;
}
}
var dog=new animal("dog");
console.log(dog.yell());//dog
//返回普通数据类型或者不返回时
var myClass=function(){
this.name='anne'
return 'danny'
}
var obj=new myClass()
alert(obj.name)//anne
// 返回对象类型时
var myClass2=function(){
this.name='anne'
return {
name :'danny'}
}
var obj=new myClass2()
alert(obj.name)//danny
箭头函数
箭头函数里面 this 始终指向外部对象,因为箭头函数没有 this,因此它自身不能进行new实例化,同时也不能使用 call, apply, bind 等方法来改变 this 的指向。(如果两个箭头函数都换成常规函数,那么就会变成指向window)
var person = {
name: 'Abby',
sayName: function() {
return (() => {
console.log(this); //Object {name: "Abby"}
console.log(this.name); //Abby
})()
}
}
person.sayName();
严格模式
在严格模式下,在全局环境中执行函数调用的时候 this 并不会指向 window 而是会指向 undefined
'use strict';
function person() {
console.log(this); //undefined
};
person();
setTimeout、setInterval中的this
javascript 高级程序设计》中写到:“超时调用的代码都是在全局执行域中执行的”。setTimeout/setInterval 执行的时候,this 默认指向 window 对象,除非手动改变 this 的指向。
var name = 'Jane';
function Person(){
this.name = 'Abby';
this.sayName=function(){
console.log(this); //window
console.log(this.name); //Jane
};
setTimeout(this.sayName, 10);
}
var person=new Person();
构造函数 prototype 属性
var name = 'Jane';
function Person(){
this.name = 'Abby';
}
Person.prototype.sayName = function () {
console.log(this); // Person {name: "Abby"}
console.log(this.name); // Abby
}
var person = new Person();
person.sayName();
在 Person.prototype.sayName 函数中,this 指向的 person 对象。即便是在整个原型链中,this 也代表当前对象的值。
页面事件
在相关的元素交互事件中,this指向的是触发事件的元素,同样你也可以在需要的时候把当前元素当做参数传入,当然如果不传,也可以通过event.target等语法拿到元素。比如:
<span onclick="event(this)"></span>
$("button").click(function(){
console.log(this) ;//指向的是当前元素
})