Skip to content

this 指针

前言

  • 在 JavaScript this 是一个绕不开的话题,随着 ES6 的出现给 this 又增加的一定的难度,今天一步步分析的下 this 的指向问题

全局环境

  • 在浏览器全局环境下的 this 始终指向 (window===self) 对象,并且用 var 声明的全局变量会挂载到 window 属性上,let、const 不会
js
var a = 10;
let b = 20;
console.log(this === window); // true
console.log(window === self); // true
console.log(window.a); // 10
console.log(window.b); // undefined

函数直接调用中的 this

严格模式

  • 在严格模式下函数直接调用,this 会指向 undefined
js
function f() {
  "use strict"; // 这里是严格模式
  console.log(this === undefined); // true
}
f();

非严格模式

js
function f() {
  console.log(this === window); // true
}
f();

对象中的 this

  • 对象中的 this,除箭头函数,this 不是在当前定义的地方,而是在被调用时离函数最近的地方,谁调用我 this 就指向谁
js
let obj = {
  name: "hulei",
  age: 18,
  getName() {
    return this.name;
  },

  getAge() {
    return this.age;
  },
};

// 因为是obj调用的所有this指向obj
console.log(obj.getName()); // hulei
let getAge = obj.getAge;
// getAge在全局的window对象上,其实最终通过window.getAge(),因为this上没有age,所以undefined
console.log(getAge()); // undefined

构造函数中 this

  • 构造函数函数返回的不是对象,则 this 是当前的实例对象
  • 如果返回的是一个对象,则 this 指向返回的对象
js
function F1() {
  this.age = 18;
}

var f1 = new F1();
console.log(f1.age); // 18

function F2() {
  this.age = 19;
  return { age: 20 };
}

var f2 = new F2();
console.log(f2.age); // 20

call & apply 可以改变 this 的指向注意:箭头函数是无法通过call & apply改变,下面会介绍到

js
function fn() {
  console.log(this.name); // hulei
}

var user = { name: "hulei" };

fn.call(user); // hulei

箭头函数的 this

  • 箭头函数的 this 一般情况下在定义的时候指向上层函数或者对象的 this
js
var age = 20;
let obj = {
  age: 21,
  getAge1() {
    // 普通函数谁调用有this就指向谁
    console.log(this.age); // 21
  },
  getAge2: () => {
    // 箭头函this在定义的时候指向上层对象的 this,obj的this是window
    console.log(this.age); // 20
  },
  getAge3: () => {
    const getAge = () => {
      // 箭头函指向上层函数的的 this
      // 此时getAge3也是一个箭头函数,他的上层对象的this是window
      console.log(this.age); // 20
    };
    getAge();
  },
};
obj.getAge1(); // 21
obj.getAge2(); // 20 
obj.getAge3(); // 20

普通函数、构造函数的中箭头函数 this 指向

普通函数调用箭头函数 this 指向 window

js
function fn() {
  let fn1 = function () {
    console.log(this); // window
  };
  // 在函数中箭头函数的this,分2种情况,普通调用,和实例化调用
  let fn2 = () => {
    console.log(this); // window
  };
  fn1();
  fn2();
}
fn();

构造函数调用箭头函数 this 指向构造函数的实例

js
function fn() {
  let fn1 = function () {
    console.log(this); // window
  };
  let fn2 = () => {
    console.log(this); //  指向构造函数的实例 fn
  };
  fn1();
  fn2();
}

let f = new fn();

总结:

  • 在浏览器环境下,全局的 this 指向 window===self,用 var 声明的全局变量会挂载到 window 属性上,let、const 不会

  • this 的指向在定义的时候确认不了,只有在被调用的时候才能确定,this 一般情况下,被谁调用 this 就指向谁

  • 箭头函数的 this 一般情况下在定义的时候指向上层函数或者对象的 this

    在函数中分为 2 种情况,普通调用和实例化调用

    call 无法改变箭头函数的 this

this 案例 1

js
let point = {
  x: 20,
  moveTo: function (x) {
    var moveX = function (x) {
      // 此时函数this是指向window
      // window.x = x
      this.x = x;
    };
    moveX(x);
  },
  getX: function () {
    // 谁调用就指向谁,此时指向point
    return this.x;
  },
  getXx: () => {
    // 在定义的时候this指向上层对象的this,此时point的this是window
    return this.x;
  },
};
point.moveTo(1);
console.log(point.getX()); // 20
console.log(point.getXx()); // 1

// let const 不会挂载到全局属性上
let a = 100;
let o = {
  a: 10,
  f1: function () {
    // 普通函数谁调用我,this指向谁
    console.log(this.a);
  },
  f2: () => {
    // 在定义的时候this指向上层对象的this,此时o的this是window
    // 因为let const 不会挂载到window上所以(a)是undefined
    console.log(this.a);
  },
  f3: function () {
    // 因为f3谁调用就指向谁,this已经指向o
    // 箭头this指向上层函数的this
    setTimeout(() => {
      console.log(this.a);
    }, 0);
  },
};

o.f1(); // 10
o.f2(); // undefined
o.f3(); // 10

this 案例 2

js
const obj = {
  f1() {
    // f1的this在定义的的时候无法确定,所以这个只有在被调用的时候才能确定箭头函数的this
    // f1被obj所调用,所以this是obj
    // 箭头函数在定义的时候指向上层函数的this,所以是obj
    const fn = () => {
      console.log("this1", this);
    };
    fn();
    // call 无法改变箭头函数的 this
    fn.call(window);
  },
  f2: () => {
    const fn = function () {
      console.log("this2", this); // window
    };
    fn();
    fn.call(this); // window 无法改变箭头函数的this
  },
};
obj.f1(); // obj
obj.f2(); // window

let {f1} = obj;
f1() // window => 等价window.f1()

this 案例 3

js
class Foo {
  // 原型方法
  fn1() {
    console.log("this1", this);
  }
  // 实例方法
  fn2 = () => {
    console.log("this2", this);
  };

  // 函数方法
  static fn3() {
    console.log("this3", this);
  }
}

// es5 --------------------------------
function Foo() {
  this.fn2 = () => {
    console.log("this2", this);
  };
}

Foo.prototype.fn1 = function () {
  console.log("this1", this);
};
Foo.fn3 = function () {
  console.log("this3", this);
};

const f = new Foo();
f.fn1(); // 当前实例
f.fn2(); // 当前实例
Foo.fn3(); // 当前类

箭头函数

  • 箭头函数没有自己的 this
  • 也没有 prototype
  • 也没有 arguments
  • 无法创建箭头函数的实例