# this

# 默认绑定

# 全局模式下this指向window(web 环境)

// 获取全局对象,this默认为:
// web: window,self,frames
// node: global(必须显示定义global.a=1)
// worker: self
// 通用: globalThis

function foo() {
  console.log(this.a);
}
var a = 2;
foo(); // 2

# 严格模式,全局对象无法使用默认绑定

调用的时候使用window.foo()才可以正常输出

function foo() {
  "use strict";
  console.log(this.a);
}
var a = 2;
foo(); // TypeError: this is undefined
window.foo(); // 2。 谁调用,输出谁
// 函数内的全局this指向undefined,函数外的全局this指向window

# 对象方法内部的 this->最近的引用

谁调用指向谁

obj.a.b.c() -> obj.a.b

var obj = {
  a: 1,
  test: function () {
    // this指向obj
    console.log(this.a);
  },
};
obj.test(); //  1

# 绑定事件

# 绑定的事件处理函数内部的 this 指向被绑定的元素
var oBtn = document.getElementById("btn");
oBtn.onclick = function () {
  console.log(this); //  this指向oBtn
};

oBtn.addEventListener("click", this.fn);
function fn() {
  console.log(this); // 指向oBtn,如果需要改变,可以通过bind,oBtn.addEventListener("click", this.fn.bind(this));
}

# Object.defineProperty

当使用函数Object.defineProperty来定义的时候,具体的 this 还是根据定义的get函数来判断

var o = {};
Object.defineProperty(o, "a", {
  get() {
    console.log(this);
  },
});

o.a; //  o = {}

var o = {};
Object.defineProperty(o, "a", {
  get: () => {
    console.log(this);
  },
});

o.a; // window

# 显示绑定

call/apply/bind

ps: bind 只会执行第一次,之后调用无效 ps: call/apply/bind 的一个参数为空或者 null,undefined,会自动将 this 绑定成全局对象

# new 绑定

  1. 创建(或者说构造)一个全新的对象。
  2. 这个新对象会被执行[[原型]]连接。
  3. 这个新对象会绑定到函数调用的 this。
  4. 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。
function fn() {
  this.a = 1;
  this.b = 1;
  return {
    c: 1,
  };
}

var f = new fn();

console.log(f); // {c:1}

如果显示的返回对象,则this指向的新对象会被忽略。

class 内定义的 a 方法相当于原型上的方法,this.a=1相当于在实例对象定义了a, 在作用域链中优先级高于原型。

class Test {
  constructor() {
    this.a = 1;
  }
  a() {}
}
const t = new Test();
console.log(t.a); // 1

# 优先级

  1. 函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象。 var bar = new foo()
  2. 函数是否通过 call、apply(显式绑定)或者硬绑定调用?如果是的话,this 绑定的是 指定的对象。 var bar = foo.call(obj2)
  3. 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this 绑定的是那个上 下文对象。 var bar = obj1.foo()
  4. 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到 undefined,否则绑定到 全局对象。 var bar = foo()

# bind 模拟

/*
 * 思路:
 * 1.通过用法可知,输入一个函数f,调用bind方法,bind方法为f的构造函数Function的prototype绑定,返回一个函数
 * 2.原函数和新函数都可以传参数
 * 3.作为构造函数new的时候,bind指定的this会失效(指向实例后的对象),参数却存在
 * 4.原函数的prototype内的方法可以给新函数的实例用
 * 5.防止直接修改新函数的prototype来影响旧函数,可以通过空函数中转
 */

# 箭头函数

this 根据外层函数或者全局的作用域来决定,是一种继承,并且无法被修改(call/apply/bind 等),也无法被 new

通过 babel 可以知:

const a = () => {
  console.log(this);
};

// 等价于
var _this = this;

var a = function a() {
  console.log(_this);
};