一:关于普通函数调用的this问题

函数执行上下文中的this

1
2
3
4
function foo(){
console.log(this)
}
foo()

这段代码中this是指向全局的,那么有什么方法来改变函数执行上下文中的this呢?

1)通过函数的call方法设置。

1
2
3
4
5
6
7
8
9
let bar = {
myName : " 极客邦 ",
test1 : 1
}
function foo(){
this.myName = " 极客时间 "
}
foo.call(bar)//foo.call方法为了改变this的指向,让其指向bar。bar中myName的值更换为极客时间。
console.log(bar)

2)通过对象调用方法设置

1
2
3
4
5
6
7
8
9
10
var myObj = {
name : " 极客时间 ",
showThis: function(){
console.log(this)
}
}
myObj.showThis()//相当与myObj.showThis.call(myObj)方法调用,这里的this指向myObj这个对象。

var obj = myObj.showThis
obj()//这样调用的话myObj里的showThis中的this为window这个对象

下面介绍几种特殊的情况。

1 解析:fn函数里的this还是obj对象,但调用f()函数时,里面的this变成全局的window了。

1
2
3
4
5
6
7
8
9
10
11
var obj = {
x: 10,
fn: function() {
function f() {
console.log(this);
console.log(this.x);
}
f();
}
};
obj.fn();

2 解析:会先打印Aurelio De Rosa,之后打印John Doe。因为前一个相当于obj.prop来调用,后一个相当于全局window来调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
var fullname = 'John Doe';
var obj = {
fullname: 'Colin Ihrig',
prop: {
fullname: 'Aurelio De Rosa',
getFullname: function() {
return this.fullname;
}
}
};
console.log(obj.prop.getFullname())
var test = obj.prop.getFullname;
console.log(test());

3)通过构造函数中设置

1
2
3
4
function CreateObj(){
this.name = " 极客时间 "
}
var myObj = new CreateObj()

这里的this相当于CreateObj这个函数

二:关于立即执行函数和箭头函数以及setTimeout的this问题
1 解析:会先打印bar,bar 之后undefined和bar。立即执行函数里的this为window,所以为undefined。但是self还是为myObject这个对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
var myObject = {
foo: "bar",
func:function(){
var self = this;
console.log(this.foo);
console.log(self.foo);
(function(){
console.log(this.foo);
console.log(self.foo);
}())
}
}
myObject.func();

2 这里我们看一下另一种情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const person = {
name: 'menglinghua',
say: function (){
return function (){
console.log(this)//这里的this指向window
console.log(this.name);
};
}
};
person.say()(); // undefined
const person = {
name: 'menglinghua',
say: function (){
return () => {
console.log(this.name);
};
}
};
person.say()(); // menglinghua

3 解析:分别打印(1){x: 10, test: ƒ, test1: ƒ, test2: ƒ, test3: ƒ} 10
(2)Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …} 1
(3){x: 10, test: ƒ, test1: ƒ, test2: ƒ, test3: ƒ} 10
(4)Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …} 1
总结:箭头函数找父级作用域即可,es6的箭头函数并不会创建其自身的执行上下文,所以箭头函数中的this取决于它的外部函数。setTimeout普通写法可以认为window调用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var x = 1
var o = {
x:10,
test:function(){
console.log(this)
console.log(this.x)
},
test1:()=>{
console.log(this)
console.log(this.x)
},
test2:function(){
setTimeout(()=>{
console.log(this)
console.log(this.x)
},100)
},
test3:function(){
setTimeout(function(){
console.log(this)
console.log(this.x)
},100)
},
}
o.test()
o.test1()
o.test2()
o.test3()

那么如何解决setTimeout的这种this指向的这种问题呢?看如下这一段代码:

1
2
3
4
5
6
7
8
var name= 1;
var MyObj = {
name: 2,
showName: function(){
console.log(this.name);//这里的this指向window的,会打印1
}
}
setTimeout(MyObj.showName,1000)

两种街解决方案:如下
1)箭头函数和function函数的写法

1
2
3
4
5
6
7
8
// 箭头函数
setTimeout(() => {
MyObj.showName()
}, 1000);
// 或者 function 函数
setTimeout(function() {
MyObj.showName();
}, 1000)

2)绑定bind函数,改变内部的this指向,返回一个函数。

1
setTimeout(MyObj.showName.bind(MyObj), 1000)

三:关于构造函数new的this问题

1
2
3
4
5
6
7
8
9
10
var num1=10,num2=20;
function add(){
var num1 = 1,num2 = 2
console.log(this.num1 + this.num2)
}
add()//30,this为window
new add()//add()里this为add{},只有this.num3=30,才会向里赋值。对于var num1 = 1,num2 = 2,不会对其造成影响,所以打印出来还是NaN
var mm = add.bind({num1:200,num2:300})
mm()//500,bind改变this的指向
new mm()//还是add{}空对象,为NaN