JavaScript深入浅出-this

this跟作用域并没有什么关系,this指向的是调用者!
自己已经踏入这个坑好多次了…总是以为this跟作用域有关系.

全局的this(浏览器)

1
2
3
4
console.log(this)//window
console.log(this===window)//true
this.a=37;
console.log(window.a)//37

一般函数的this(浏览器)

1
2
3
4
5
6
7
8
9
10
function f1(){
return this
}
f1()===window//true,global object
---
function f2(){
'use strict';
return this
}
f2()===undefined;//true

作为对象方法的函数this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var o={
prop:37,
f:function(){
return this.prop
}
}
console.log(o.f());//logs 37
---
var o={prop:37};
function independent(){
return this.prop
}
o.f=independent;
console.log(o.f())//logs 37

对象原型链上的this

1
2
3
4
5
6
7
8
9
var o={
f:function(){
return this.a+this.b
}
}
var p=Object.create(o);
p.a=1;
p.b=4;
console.log(p.f());//5

p的原型是o,p.f()调用的是原型链上的方法,当调用的时候原型链上的this也可以指向p这个对象

get/set方法与this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function modulus(){
return Math.sqrt(this.re*this.re+this.im*this.im)
}
var o={
re:1,
im:-1,
get phase(){
return Math.atan2(this.im,this.re);
}
}
Object.defineProperty(o,'modulus',{
get:modulus,
enumerable:true,
configurable:true
})
console.log(o.phase,o.modulus);//logs -0.78 1.4142

get,set方法会指向对象方法,get中间不要用:分割

构造器中的this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function MyClass(){
this.a=37;
}
var o=new MyClass();
console.log(0.a);//37
function C2(){
this.a=37;
return {
a:38
}
}
o=new C2();
console.log(0.a)//38

用new作为构造器去构造,this会指向MyClass空对象,默认的this会作为返回值,
C2中 new构造的时候this会指向原型为MyClass.prototype这样一个空对象,最后函数的返回值,如果没写return或者return基本类型 会将this作为返回值,
如果返回的是一个对象,会将对象作为返回值
在构建的时候也就是o=new C2()其中this指向的是MyClass
但构建完毕后也就是单独执行o;会this指向return的object

call/apply方法中的this

1
2
3
4
5
6
7
8
9
10
11
12
function add(c,d){
return this.a+this.b+c+d;
}
var o={a:1,b:3};
add.call(o,5,7);//1+3+5+7=16
add.apply(0,[10,20]);//1+3+10+20=34
function bar(){
console.log(Object.prototype.toString.call(this))
}
bar.call(7)//'[object Number]'

改变函数的this指向 原本bar 函数this指向的是window,传递了一个7也就是this指向了[object Number]

bind方法与this

1
2
3
4
5
6
7
8
9
function f(){
return this.a;
}
var g=f.bind({a:'test'});
console.log(g())//test;
var o={a:37,f:f,g:g};
console.log(o.f(),o.g());//37,test

bind不会对原方法的作用域进行修改,仅仅是针对bind调用者/赋值者进行绑定