JS底层知识中的this:掌握函数执行上下文的艺术

在JavaScript的世界里,this关键字扮演着至关重要的角色,它决定了函数执行时的上下文环境。从基础的默认和隐式绑定,到复杂的显示绑定和箭头函数特性,this的行为随着函数调用的方式而变化,深刻影响着代码的行为和逻辑。理解 this 的工作方式对于编写高质量、可维护的代码至关重要。本文将深入探讨 this 的概念、不同场景下的行为以及如何控制其绑定。

1. this 的基本概念

this 是一个特殊的关键字,在函数内部使用时,它引用的是函数执行时的上下文对象。this 指向的具体值取决于函数是如何被调用的。为了让对象中的函数有能力访问对象中的自己的属性,this可以显著的提升代码质量,减少上下文参数的传递

2. this 的指向规则

  • 默认绑定 :当函数作为普通函数调用时(不作为任何对象的方法),也就是当一个函数独立调用时,不带任何修饰符的调用,this 指向全局对象(在浏览器中是 window)。但在严格模式下(use strict),this 将是 undefined

    Javascript 复制代码
    function foo() {
        console.log(this);
    }
    foo(); // 在非严格模式下输出 window 对象,在严格模式下输出 undefined
  • 隐式绑定 :当一个函数被某个对象所拥有,或者函数被某个上下文对象调用时,该函数中的this指向该上下文对象

    Javascript 复制代码
    var obj = {
        a: 1,
        foo: function () {
            console.log(this); // 输出 {a: 1, foo: [Function: foo]}
        }
    };
    obj.foo();
  • 隐式丢失 :当一个函数被赋值给另一个变量再调用,那么this 的绑定会丢失,导致默认绑定。 但是如果一个函数被多个对象链式调用时,this 会指向最近的那个对象。

    Javascript 复制代码
    var obj = {
        a: 1,
        foo: function () {
            console.log(this.a);
        }
    };
    var bar = obj.foo;
    bar(); // 输出 undefined (因为 `this` 变为全局对象)
  • 显示绑定 :通过 call, apply, 和 bind 方法可以显式地设置函数调用时的 this 值。将函数的this掰弯到一个对象中

    Javascript 复制代码
    function foo(x, y) {
        console.log(this.a, x + y);
    }
    var obj = { a: 1 };
    foo.call(obj, 1, 2); // 输出 1 3
    foo.apply(obj,[1,2])//输出 1 3
    const bar = foo.bind(obj,1,2);//bind 也可以
    bar()
  • new绑定 :使用 new 关键字调用函数时,this 指向新创建的对象实例。

    Javascript 复制代码
    function Person() {
        this.name = '平平';
    }
    let p = new Person();
    console.log(p.name); // 输出 "平平"

3. 箭头函数中的 this

箭头函数没有自己的 this 绑定;它们继承自外层作用域的 this。这意味着箭头函数内部的 this 通常与定义它的上下文有关,而不是调用它的上下文。

Javascript 复制代码
var obj = {
    a: 1,
    foo: function () {
        const fn = () => {
            console.log(this.a);
        };
        fn(); // 输出 1,这里的 `this` 是 `obj`
    }
};
obj.foo();

手写 call 方法

为了更深入地理解 this 的绑定,我们可以通过手写 call 方法来模拟 JavaScript 内置的 call 功能。

Javascript 复制代码
Function.prototype.mycall = function (context) {
    const context=arguments[0]
    const args = Array.from(arguments).slice(1);
    context.fn=this;
    const res = context.fn(...args);
    delete context.fn;
    return res;
};

function foo() {
    console.log(this.a);
}

var obj = { a: 1 };
foo.mycall(obj); // 输出 1

结尾

掌握 this 的行为对于JavaScript开发者来说是至关重要的,因为它直接影响着函数的执行上下文和数据的访问。掌握了this的机制,开发者能够更加灵活地操纵函数,构建出更高效、更具可读性和可维护性的代码结构。无论是处理DOM事件、构造类方法还是实现闭包,对this的理解都是必不可少的技能。

这次我们不仅探索了this在不同场景下的表现,还亲手实现了简单的call方法,加深了对this绑定机制的理解。不过,理解this并非一蹴而就的过程,而是需要不断实践和思考的旅程。继续加油吧

如果你对本文有任何疑问或见解,欢迎留言讨论。期待在前端开发的学习旅程中,与你一起加油!

相关推荐
LvManBa6 分钟前
Vue学习记录之三(ref全家桶)
javascript·vue.js·学习
深情废杨杨33 分钟前
前端vue-父传子
前端·javascript·vue.js
司篂篂2 小时前
axios二次封装
前端·javascript·vue.js
姚*鸿的博客2 小时前
pinia在vue3中的使用
前端·javascript·vue.js
Jiaberrr4 小时前
JS实现树形结构数据中特定节点及其子节点显示属性设置的技巧(可用于树形节点过滤筛选)
前端·javascript·tree·树形·过滤筛选
我码玄黄5 小时前
THREE.js:网页上的3D世界构建者
开发语言·javascript·3d
爱喝水的小鼠5 小时前
Vue3(一) Vite创建Vue3工程,选项式API与组合式API;setup的使用;Vue中的响应式ref,reactive
前端·javascript·vue.js
小晗同学5 小时前
Vue 实现高级穿梭框 Transfer 封装
javascript·vue.js·elementui
WeiShuai5 小时前
vue-cli3使用DllPlugin优化webpack打包性能
前端·javascript
forwardMyLife5 小时前
element-plus的面包屑组件el-breadcrumb
javascript·vue.js·ecmascript