this对象是在运行时,基于函数的执行环境绑定的。指向大致分为四种:
1)对象的方法调用,this = 该对象;
2)普通函数,this = window;
3)构造器;
4)Function.prototype.call/apply
1、作为对象的方法调用
var a = 2
var obj = {
a: 1,
getValue: function(){
console.log(this.a)
},
// 箭头函数 改变this指向 this = window
getArrowValue: () => {
console.log(this.a)
}
}
// getValue方法是作为obj对象的属性被调用的,this = obj
obj.getValue() // 1
obj.getArrowValue() // 2
// 属于普通函数调用,this = window
var f1 = obj.getValue
f1() // 2
如果对象中的方法返回一个匿名函数,涉及到闭包,情况就不一样了。
var a = 2
var obj = {
a: 1,
getValue: function(){
return function(){
console.log(this.a)
}
}
}
obj.getValue()() // 2
函数被调用时,会创建一个执行环境和相应的作用域链,得到两个变量:this、arguments。
内部函数在搜索这两个变量时,只会搜索到其活动对象为止。
解决这类问题,可以在匿名函数外定义一个变量,把this传给变量,
getValue: function(){
const self = this
return function(){
console.log(self.a)
}
}
2、普通函数调用
上述 var f1 = obj.getValue;f1() 属于普通函数调用,this是指向全局对象的。
3、构造器调用
JS没有类,但是可以从构造器中创建对象,使用new运算符,返回对象,通常情况,构造器里的this是
指向返回的这个对象的。
但是,如果构造器显示的返回一个object类型的对象,返回结果会是该对象;
const MyClass = function() {
this.name = 'qwe';
return {
name: 'asd'
}
}
const obj = new MyClass()
console.log(obj.name) // asd
4、Function.prototype.call/apply调用
在一个对象的上下文中应用另一个对象的方法;
作用一样,都是动态的改变this的执行,并立即执行函数。是传入参数的形式不同,第一个参数都是指定函数体内this对象的指向。
(A对象调用B对象的方法)
call是列表:B.call(A, args1,args2)
apply是数组:B.apply(A, arguments)
let obj1 = {
name: 'qwe',
getName: function() {
return this.name
}
}
const obj2 = {
name: 'asd'
}
console.log(obj1.getName()) // qwe
// this指向obj2
console.log(obj1.getName.call(obj2)) // asd
A.apply(null,[1,2,3]) 第一个参数传null,非严格模式下,函数体内的this会指向全局对象(node:global,浏览器:window)
this.name = 'zxc'
let obj1 = {
name: 'qwe',
getName: function() {
return this.name
}
}
console.log(obj1.getName()) // qwe
console.log(obj1.getName.call(null)) // zxc
在这补充一下call和apply的用途
5、箭头函数this指向
箭头函数的this是在定义函数时绑定的,不是在执行过程中绑定的。
简单的说,函数在定义时,this就继承了定义函数的对象。
箭头函数是没有this的,没有构造函数,不能使用arguments
let obj={
a:222,
fn:function(){
setTimeout(()=>{console.log(this.a)});
},
fn1:function(){
setTimeout(function(){console.log(this.a)})
}
};
obj.fn();//222
obj.fn1(); // undefined
fn1() 里的 this 指向 obj ,但传给 setTimeout 的是普通函数, this 指向是 window ,输出 undefined。
fn()传给 setTimeout 的是箭头函数,箭头函数没有 this ,向上层作用域查找到fn。fn的 this 指向 obj ,所以 setTimeout 里面的箭头函数的 this ,指向 obj输出 222 。
eg1:
在事件函数里,有一个内部函数func,在事件函数内部调用func,func体内的this会指向window,而不是我们想要的事件函数的this
(ps:参考了JS设计模式和小红书)
eg2
var name = "big window"
function test(){
var name = "this window"
function fn(){
console.log(this.name)
}
function fn1(){
console.log(this.name)
}
var obj = {
name: "this object",
getName: function(fn){
fn && fn() // 传参调用
fn1() // 直接调用
console.log(this.name)
return function(){
return this.name
}
}
}
console.log(obj.getName(fn)())
}
test()
// big window
big window
this object
big window