JavaScript 中「我是谁」的哲学思考与实战通关指南

JavaScript 中的 this:从基础概念到应用实践

在 JavaScript 编程领域,this关键字是一个既基础又复杂的核心概念。它在函数执行时动态生成,其指向完全由函数的调用方式决定 。理解this的工作机制,对于编写高效、准确的 JavaScript 代码至关重要。接下来,

一、this 的基础概念

this是函数执行时创建的对象,它的存在赋予了函数在不同调用环境下,灵活访问对应对象属性和方法的能力,是 JavaScript 动态性的重要体现。需要明确的是,this的指向并非在函数定义时确定,而是在函数运行过程中动态绑定,这与许多编程语言存在显著差异。

在全局作用域中,this的指向因运行环境而异。在浏览器环境里,this指向window对象;而在 Node.js 环境下,this则指向global对象。例如:

javascript 复制代码
console.log(this);
// 浏览器中输出window对象
// Node.js中输出global对象

二、this 的绑定规则

this的指向由函数的调用方式决定,指向最后调用该函数的对象。

  1. 默认绑定

    当函数以独立形式调用(作为普通函数被调用 ),即不是作为对象的方法,也未使用特殊调用方式时,this遵循默认绑定规则。在非严格模式下,this指向全局对象(浏览器中的window或 Node.js 中的global);而在严格模式下,this的值为undefined

    javascript 复制代码
    function sayHello() {
     console.log(this);
    }
    sayHello();
    
    // 非严格模式下相当于window.sayHello(),函数的this指向window 输出window对象
    
    // 严格模式下,输出undefined
  2. 隐式绑定

    当函数作为对象的方法被调用时this会隐式绑定到该对象。此时,函数内部的this指向调用该方法的对象,方便函数操作对象的属性和其他方法。

    javascript 复制代码
    const person = {
      name: "Alice",
      sayName: function () {
        console.log(this.name);
      },
    };
    person.sayName();
    
    // 输出:Alice
  3. 显式绑定

    JavaScript 提供了**call() apply() bind()**方法,允许开发者显式指定函数调用时this的指向:

    • call():第一个参数为要绑定的this值,后续是函数的参数列表。

      javascript 复制代码
      function add(a, b) {
        return this.x + a + b;
      }
      
      const obj = {
        x: 10,
      };
      
      // 将add 的this指向obj 并执行函数add
      const result = add.call(obj, 5, 3);
      
      console.log(result);
      
      // 输出:18
    • apply():与call()类似,区别在于第二个参数是包含所有参数的数组。

      javascript 复制代码
      const result2 = add.apply(obj, [5, 3]);
      
      console.log(result2);
      // 输出:18
    • bind():返回一个新函数,其this指向bind()传入的对象,即使通过其他方式调用,this指向也不变。

      javascript 复制代码
      const boundAdd = add.bind(obj);
      
      const result3 = boundAdd(5, 3);
      
      console.log(result3);
      // 输出:18
  4. 构造函数绑定

    使用new关键字调用函数(构造函数)时,this指向新创建的对象。构造函数通过this为实例对象添加属性和方法,完成对象初始化。

    javascript 复制代码
    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    const bob = new Person("Bob", 30);
    console.log(bob.name);
    // 输出:Bob
    console.log(bob.age);
    // 输出:30

三、函数调用方式与 this 指向

  1. 普通函数调用

    形如fn()的普通函数调用,在非严格模式下等同于window.fn()this指向window;严格模式下,this指向undefined

    javascript 复制代码
    function sayHi() {
      console.log(this);
    }
    
    sayHi();
    
    // 非严格模式下输出window对象
    
    // 严格模式下输出undefined
  2. 对象方法调用

    当函数作为对象的方法被调用,如obj.fn()this隐式绑定到obj对象,便于函数访问和操作obj的属性与方法。

    javascript 复制代码
    const user = {
      name: "Alice",
    
      sayName: function () {
        console.log(this.name);
      },
    };
    // 输出:Alice
    user.sayName();
  3. 构造函数调用

    通过new关键字调用构造函数,this绑定到新创建的实例对象,用于初始化实例属性和方法。

    javascript 复制代码
    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    
    const tom = new Person("Tom", 25);
    // 输出:Tom
    console.log(tom.name);
    // 输出:25
    console.log(tom.age);
  4. 箭头函数调用

    箭头函数(() => {})本身没有thisthis继承自外层作用域(定义时的作用域),在定义时就已确定,不会动态绑定。

    当sayHello作为对象方法被person掉用时,sayHello中的this指向person对象。而setTimeout中的箭头函数会捕获外层作用域的this,而此时外层的this指向的是person,因此箭头函数中的this应该指向person。

    javascript 复制代码
    const person = {
      name: "Bob",
      sayHello: function () {
        setTimeout(() => {console.log(this.name)}, 1000);
      },
    };
    
    person.sayHello();
    
    // 输出:Bob
  5. 事件回调函数调用

    在 DOM 事件处理中,如btn.onclick = function() {}this通常指向触发事件的 DOM 元素但使用箭头函数作为回调时,因箭头函数无自身this,会继承定义时作用域的this,可能导致指向错误。

    html 复制代码
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
      </head>
      <body>
        <button id="myBtn">Click Me</button>
    
        <script>
          const myBtn = document.getElementById("myBtn");
    
          // 传统函数作为事件回调,this指向按钮元素
          myBtn.addEventListener("click", function () {
            console.log(this); // 指向DOM
          });
    
          // 箭头函数作为事件回调,this指向window对象(非严格模式下)
          myBtn.addEventListener("click", () => {
            console.log(this); // 指向window
          });
        </script>
      </body>
    </html>

四、this 指向问题的解决方法

在实际开发中,经常会遇到this指向不符合预期的情况,以下是常见的解决手段:

  1. 变量保存法

    通过var _this = this;this的值保存在一个变量(如_this)中,利用作用域链,让内部函数能正确访问外部函数的this

    javascript 复制代码
    var a = {
      name: "张三",
      func2: function () {
         setTimeout(function () {
          //这里的this指向的是window,因为setTimeout是全局函数,所以this指向window 而全局中没有func1,所以会报错
          this.func1();
          }, 1000);
       },
        
      func4: function () {
        var _this = this;
        setTimeout(function () {
          _this.func1();
        }, 1000);
      },
    };
    
    a.func4()  // 输出结果为张三
    a.func2() //
  2. call、apply、bind 方法

    使用callapplybind方法显式指定this指向:

    • callapply在调用函数时改变this指向;

    • bind返回一个新函数,其this永久绑定,可延迟执行。

    javascript 复制代码
    var a = {
      name: "张三",
    
      func1: function () {
        console.log(this.name);
      },
    
      func2: function (a, b) {
        console.log(a, b, this.name);
      },
    };
    
    const b = a.func2;
    
    b.call(a, 1, 2);
    b.apply(a, [1, 2]);
    
    const c = b.bind(a);
    c(3, 4);
相关推荐
cos39 分钟前
从像素到粒子:p5.js 图像转动态粒子的设计与实现
前端·javascript·webgl
造糖主义3 小时前
vue-el-upload上传组件自定义删除-预览按钮遮罩层,不受原有的上传打开文件夹
前端·javascript·vue.js
小猫会后空翻3 小时前
XSS相关理解
前端·xss
brzhang4 小时前
我十几个项目都是这套Flutter 快速开发框架,今天开源了,从此你只用关心业务了
前端·后端·架构
qziovv4 小时前
控制Vue对话框显示隐藏
javascript·vue.js·elementui
BLACK5955 小时前
Nuxt3中PC端与移动端适配的三种方式(含Nuxt官网同款实现方式)
前端·vue.js·nuxt.js
小宁爱Python5 小时前
TypeScript 泛型详解:从基础到实战应用
前端·javascript·typescript
鱼樱前端5 小时前
一文讲解时下比较火的Rust语言之-rust开发环境搭建
前端·javascript
Moment6 小时前
Next.js 15.4 正式发布:Turbopack 全面稳定,预热 Next.js 16 😍😍😍
前端·javascript·node.js
虚!!!看代码6 小时前
uni-app 跳转页面传参
前端·vue.js·uni-app