this是什么?
this 是 JavaScript 中的一个关键字。this指代当前函数的运行环境。它通常被运用于函数体内,依赖于函数调用的上下文条件,与函数被调用的方式有关。它指向谁,则完全是由函数被调用的调用点来决定的。
所以,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象
let a=10;
let obj={
a:1,
foo:function(){
console.log(this.a)
}
}
let foo=obj.foo;
obj.foo()// 1 这里的this是在obj的环境中 所以指向obj
foo()//10 这里的this则在全局环境中运行 指向windows
this的原理
理解 this 的原理,有助于帮我们更好地理解它的用法。JavaScript 语言之所以有 this 的设计,跟内存里面的数据结构有关系。 举个例子:
var obj = { foo: 5 };
上面的代码将一个对象赋值给变量obj。JavaScript 引擎会先在内存里面,生成一个对象{ foo: 5 },然后把这个对象的内存地址赋值给变量obj。
也就是说,变量obj是一个地址(reference)。后面如果要读取obj.foo,引擎先从obj拿到内存地址,然后再从该地址读出原始的对象,返回它的foo属性。
原始的对象以字典结构保存,每一个属性名都对应一个属性描述对象。举例来说,上面例子的foo属性,实际上是以下面的形式保存的。

var obj = { foo: function () {} };
这时,JavaScript 引擎会将函数单独保存在内存中,然后再将函数的地址赋值给 foo 属性的 value 属性。

又因为,JavaScript 允许在函数体内部,引用当前环境的其他变量。所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。
this的用法
函数中的用法
简单调用
这是函数的最通常用法,属于全局性调用,因此 this 就代表全局对象 window。
function f1(){
return this;
}
//在浏览器中:
f1() === window; //在浏览器中,全局对象是window
严格模式
在严格模式下,this将保持他进入执行环境时的值,所以下面的this将会默认为undefined。
function f2(){
"use strict"; // 这里是严格模式
return this;
}
f2() === undefined; // true
call或apply方法
要想把 this 的值从一个环境传到另一个,就要用 call 或者apply 方法。
// 将一个对象作为call和apply的第一个参数,this会被绑定到这个对象。
var obj = {a: 'Custom'};
// 这个属性是在global对象定义的。
var a = 'Global';
function whatsThis(arg) {
return this.a; // this的值取决于函数的调用方式
}
whatsThis(); // 'Global'
whatsThis.call(obj); // 'Custom'
whatsThis.apply(obj); // 'Custom'
bind方法
调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。
function f(){
return this.a;
}
var g = f.bind({a:"azerty"});
console.log(g()); // azerty
var h = g.bind({a:'yoo'}); // bind只生效一次!
console.log(h()); // azerty
var o = {a:37, f:f, g:g, h:h};
console.log(o.a, o.f(), o.g(), o.h()); // 37, 37, azerty, azerty
箭头函数
箭头函数没有自己的this,arguments,**因此箭头函数的this是继承父执行上下文里面的this **
var i=1000;
var obj2 = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
let fn=()=>{
console.log(this.i, this)
}
fn()
}
}
obj2.b(); //1000 Window
obj2.c(); //obj2 10
都是通过obj调用匿名函数为何打印出来的this不同呢?
因为this是继承自父执行上下文!!中的this,obj.b的箭头函数本身所在的对象为obj,obj的父执行上下文为Window,因此obj.b的this指向Window
注意:简单对象(非函数)是没有执行上下文的!
obj2.c的父执行上下文为obj,所以obj2.c中this指向obj2
作为对象中的方法
当函数作为对象里的方法被调用时,它们的 this 是调用该函数的对象。
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //12
}
}
}
o.b.fn();//12
this 的绑定只受最靠近的成员引用的影响。因此fn中的this指向b
作为构造函数
当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。
function C(){
this.a = 37;
}
var o = new C();
console.log(o.a); // logs 37 this指向 o
function C2(){
this.a = 37;
return {a:38};
}
o = new C2();
console.log(o.a); // logs 38
在刚刚的例子中(C2),因为在调用构造函数的过程中,手动的设置了返回对象,与this绑定的默认对象被丢弃了。