this 的值是运行时计算出来的

let user = { name: "John" };
let admin = { name: "Admin" };

function sayHi() {
  alert( this.name );
}

// 在两个对象中使用相同的函数
user.f = sayHi;
admin.f = sayHi;

// 这两个调用有不同的 this 值
// 函数内部的 "this" 是“点符号前面”的那个对象
user.f(); // John(this == user)
admin.f(); // Admin(this == admin)

admin['f'](); // Admin(使用点符号或方括号语法来访问这个方法,都没有关系。)

没有对象的情况下

  • 在严格模式下,函数中的 this 是 undefined。
  • 在非严格模式下,this 是全局对象(浏览器中是 window 对象)。
function showThis() {
  console.log(this);
}

showThis(); // 在非严格模式下,this指向全局对象

箭头函数没有自己的this

let user = {
  firstName: "Ilya",
  sayHi() {
    let arrow = () => console.log(this.firstName);
    arrow();
  }
};
user.sayHi(); // Ilya

调用函数时指定this

function say(phrase) {
  alert(this.name + ': ' + phrase);
}
let user = { name: "John" };
let admin = { name: "Admin" };
say.call(user, "Hello"); // John: Hello
say.call(admin, "Hello"); // Admin: Hello
say.apply(user, ["Hello"]); // John: Hello
say.apply(admin, ["Hello"]); // Admin: Hello
say.bind(user, "Hello")(); // John: Hello
say.bind(admin, "Hello")(); // Admin: Hello

例子

在对象字面量中使用 “this”

function makeUser() {
  return {
    name: "John",
    ref: this
  };
}

let user = makeUser();

alert( user.ref.name ); // 结果是什么?

因为在调用 makeUser 函数时,不是通过对象调用的,所以 thisundefined。因此,user.refundefined,访问 user.ref.name 会导致错误。

反例:

function makeUser() {
  return {
    name: "John",
    ref() {
      return this;
    }
  };
}

let user = makeUser();

alert( user.ref().name ); // John

这里正常的原因是 ref 是一个方法,通过 user.ref() 调用时,this才被确定下来。

创建一个计算器

创建一个有三个方法的 calculator 对象:

  • read() 提示输入两个值,并将其保存为对象属性,属性名分别为 a 和 b。
  • sum() 返回保存的值的和。
  • mul() 将保存的值相乘并返回计算结果。
let calculator = {
  // ……你的代码……
};

calculator.read();
alert( calculator.sum() );
alert( calculator.mul() );
let calculator = {
  read(a,b){
    this.a = +prompt();
    this.b = +prompt();
  },
  sum(){
    return this.a + this.b
  },
  mul(){
    return this.a * this.b
  }
};

calculator.read();
alert( calculator.sum() );
alert( calculator.mul() );

链式(调用)

有一个可以上下移动的 ladder 对象:

let ladder = {
  step: 0,
  up() {
    this.step++;
  },
  down() {
    this.step--;
  },
  showStep: function() { // 显示当前的 step
    alert( this.step );
  }
};

现在,如果我们要按顺序执行几次调用,可以这样做:

ladder.up();
ladder.up();
ladder.down();
ladder.showStep(); // 1
ladder.down();
ladder.showStep(); // 0
let ladder = {
  step: 0,
  up() {
    this.step++;
    return this;
  },
  down() {
    this.step--;
    return this;
  },
  showStep: function() { // 显示当前的 step
    alert( this.step );
    return this
  }
};