在 JavaScript 中如何让 this 保持正确的指向

对象的方法中 this 的指向

以一个代码例子,来对切入对对象的方法中 this 的指向的讨论,例子如下:

javascript 复制代码
const obj = {
  prop: 'I am an object',
  logProp: function() {
    const func = function(){
        console.log(this.prop);
    }();
  }
};
obj.logProp()// 期望打印 obj 的 prop 属性, I am an object

方案一:使用闭包

实现方式:

javascript 复制代码
const obj = {
  prop: 'I am an object',
  logProp: function() {
    let context = this;
    const func = function(){
        console.log(context.prop);
    }();
  }
};
obj.logProp()

原始代码:

javascript 复制代码
const obj = {
  prop: 'I am an object',
  logProp: function() {
    const func = function(){
        console.log(this.prop);
    }();
  }
};
obj.logProp()// 期望打印 I am an object

原始代码可以理解为:

javascript 复制代码
const temp  = function(){
  console.log(this.prop);
}

const obj = {
  prop: 'I am an object',
  logProp: function() {
    temp(); // 相当于在全局作用域直接调用temp函数。
  }
};
obj.logProp()

浏览器中 JavaScript 函数执行的方式是当前执行函数入栈,执行结束则出栈。

执行 logProp 函数后,这一函数已经出栈,temp 函数入栈,没有历史栈,相当于在全局作用域直接调用 temp 函数,因此 this 指向全局对象,而不是 obj 对象。

因此在外层函数 logProp 中定义一个变量 context ,保存指向 obj 的 this,在 func 中使用这个变量。logProp函数出栈时,因为 func 中用到了 context,因此这个变量会留在栈内,这就是闭包。而 func 中可以通过这个变量,访问到指向 obj 的 this。

方案二:使用箭头函数

实现方式:

javascript 复制代码
const obj = {
  prop: 'I am an object',
  logProp: function() {
    const func = ()=>{
        console.log(this.prop);
    };
    func();
  }
};
obj.logProp()

箭头函数没有自己的 this 对象,对于普通函数来说,内部的 this 指向函数运行时所在的对象,但是箭头函数没有自己的 this 对象,内部的 this 就是定义时上层作用域中的 this。也就是说,箭头函数内部的this指向是固定的,固定指向函数定义时的作用域

方案三:换绑 this

普通函数可以使用 bind、call、apply 来换绑this。

API 作用
bind bind()方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。
call 函数实例的call方法,可以指定函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。
apply apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数。

在本文给出的代码示例问题中,用 bind 或 call 即可满足需求。

用 bind 实现

实现方式:

javascript 复制代码
const obj = {
  prop: 'I am an object',
  logProp: function() {
    const func = function(){
        console.log(this.prop);
    }.bind(this);
    func();
  }
};
obj.logProp()

bind 的具体实现:

javascript 复制代码
Function.prototype.bind = function(context, args){
    if(typeof this !=='function'){
        throw new Error('Function.prototype.bind - what is trying to be bound is not callable')
    }
    const self = this;
    const func = function(){
        self.call(this instanceof self?self:context, args.concat(Array.prototype.slice.call(arguments)) )
    }
    const fNOP = function(){}
    fNOP.prototype = this.prototype;
    func.prototype = new fNOP();
    return func;
}

用 call 实现

javascript 复制代码
const obj = {
  prop: 'I am an object',
  logProp: function() {
    const func = (function(){
        console.log(this.prop);
    }).call(this)
  }
};
obj.logProp()

call 的具体实现

javascript 复制代码
function myCall(context, ...args){
    let context = context || window;
    context.fn = this;
    const res = eval('context.fn(...args)');
    delete context.fn;
    return res;
}

新创建的实例中this的指向

javascript 复制代码
function MyClass() {
  this.prop = 'I am a property';
}
const instance = MyClass();
console.log(instance); // 错误,this指向全局对象而不是新创建的实例

解决方案:使用 new 操作符。

javascript 复制代码
function MyClass() {
  this.prop = 'I am a property';
}
const instance = new MyClass();
console.log(instance); // 正确,this 指向新创建的实例

new 操作符做了什么?

  1. 创建一个空对象,作为将要返回的对象实例。
  2. 将这个空对象的原型,指向构造函数的prototype属性。
  3. 将这个空对象赋值给函数内部的this关键字。
  4. 开始执行构造函数内部的代码。
javascript 复制代码
function objectFactory() {
  const args = [].slice.call(arguments);
  const constructor = args.shift();
  const context = Object.create(constructor.prototype);
  const result = constructor.apply(context, args);
  const flag = result !== null && typeof constructor === "object";
  return flag ? result : context;
}
let actor = _new(Person, "张三", 28);

结束语

以上就是对"在 JavaScript 中如何让 this 保持正确指向"的介绍,读者朋友可以在浏览器中测试本文中的代码,实际操作收获更多,感谢大家的阅读。

参考

JavaScript 教程:wangdoc.com/javascript/...

ES6 入门教程:es6.ruanyifeng.com/

相关推荐
恋猫de小郭1 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅8 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅9 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅9 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅10 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊10 小时前
jwt介绍
前端