面试题库 词条目录
前端Wiki/面试题库/JavaScript/JS 进阶题

this 指向与 call / apply / bind

this 是函数运行时的“当前对象”,由调用方式决定:默认调用指向 window(严格模式下 undefined);方法调用指向调用者;构造函数指向新实例;箭头函数没有自己的 this,继承外层词法作用域。call / apply / bind 都是显式指定 this:call 与 apply 立即执行(参数逐个传 / 数组传),bind 返回一个永久绑定的函数。

面试常考“箭头函数能否 new”:不能,它没有 prototype 与 this 机制,new 会直接报错。另一个高频追问:bind 返回的函数再 call 改 this 无效 —— bind 的绑定是永久的(内部用 bind 后的函数已记录 this)。

  • this 四规则:默认、隐式(方法调用)、显式(call/apply/bind)、new
  • 箭头函数没有 this,继承定义时的外层作用域
  • call / apply 立即执行,bind 返回新函数且绑定不可再改
JS
// 默认调用
function show() { console.log('this =', this === window ? 'window' : this); }
show();                       // window(非严格模式)

// 方法调用:this 指向调用者
const obj = { name: '小明', say() { console.log(this.name); } };
obj.say();                    // 小明
const fn = obj.say;
fn();                         // undefined(this 丢失)

// call / apply / bind 显式指定
function greet(g, p) { console.log(g + ',' + this.name + ',' + p); }
greet.call({ name: '小红' }, '你好', '吃了吗');          // 立即执行,逐个传参
greet.apply({ name: '小刚' }, ['嗨', '在吗']);           // 立即执行,数组传参
const bound = greet.bind({ name: '小亮' }, '哈喽');      // 返回新函数
bound('干嘛呢');

// 箭头函数:this 继承外层,call 改不动
const arrow = { say: () => console.log('箭头 this 是全局:', this === window) };
arrow.say();                    // true
arrow.say.call({ name: 'X' });  // 仍然 true

// 手写 call(面试常考)
Function.prototype.myCall = function (ctx, ...args) {
  ctx = ctx == null ? window : Object(ctx);   // 基本类型装箱
  const key = Symbol();                       // 唯一键防覆盖原属性
  ctx[key] = this;
  const res = ctx[key](...args);
  delete ctx[key];
  return res;
};
greet.myCall({ name: '手写' }, '嘿', '不吃饭');
本节要点this 由调用方式决定;call / apply / bind 显式指定(bind 永久);箭头函数没有 this。