严格模式(Strict Mode)对 `this` 绑定的影响

好的,各位靓仔靓女们,欢迎来到今天的“this的奇幻漂流记”特别节目!我是你们的老朋友,人称“代码界段子手”的程序员小P。今天,咱们要聊点硬核的,但保证让你们笑出腹肌——关于“严格模式下 this 的那些事儿”。

准备好了吗?系好安全带,咱们的飞船即将起飞,目的地:this 的宇宙深处!🚀

开场白:this,你这个磨人的小妖精!

在 JavaScript 的浩瀚星空中,this 绝对是颗闪耀又令人头疼的星星。它就像一个百变的间谍,身份成谜,一会儿指着这个,一会儿指着那个,搞得我们晕头转向。尤其是在严格模式下,它更是变得冷酷无情,稍不留神,就会给你一个意想不到的“惊喜”(错误)。

所以,今天咱们的任务,就是揭开 this 在严格模式下的神秘面纱,让它乖乖听话,为我们所用。

第一幕:什么是严格模式?(Strict Mode 简介)

首先,我们要搞清楚什么是严格模式。简单来说,它就像 JavaScript 的“纪律委员”,开启之后,会强制执行更严格的语法规则,消除一些 JavaScript 的“历史遗留问题”,提高代码的安全性、可读性和执行效率。

开启严格模式的方法很简单,只需要在脚本或函数的开头加上一句:

"use strict";

就像给你的代码穿上了一身铠甲,让它更加坚不可摧!💪

第二幕:this 的基本绑定规则(回顾)

在深入了解严格模式对 this 的影响之前,我们先来回顾一下 this 的基本绑定规则。总共有四种:

  1. 默认绑定 (Default Binding): 在非严格模式下,如果 this 的指向无法通过其他规则确定,它会默认指向全局对象(浏览器中是 window,Node.js 中是 global)。

  2. 隐式绑定 (Implicit Binding): 当函数作为对象的方法被调用时,this 指向调用该方法的对象。

  3. 显式绑定 (Explicit Binding): 通过 callapplybind 方法,我们可以显式地指定 this 的指向。

  4. new 绑定 (new Binding): 当使用 new 关键字调用函数时,会创建一个新的对象,并将 this 指向这个新对象。

这些规则就像四个武林高手,各有绝招,决定着 this 的最终归属。

第三幕:严格模式下的 this:冷酷杀手!

现在,主角登场了!让我们来看看严格模式是如何“调教” this 的。

重点来了!敲黑板! 📝

在严格模式下,最显著的变化就是:默认绑定失效了!

也就是说,在非严格模式下,如果 this 无法通过其他规则确定,它会默认指向全局对象。但在严格模式下,它会直接变成 undefined

这就像原本有个“备胎”,现在直接被“一脚踹开”了!💔

举个例子:

// 非严格模式
function sayHello() {
  console.log(this); // window (浏览器) 或 global (Node.js)
}

sayHello();

// 严格模式
"use strict";

function sayHelloStrict() {
  console.log(this); // undefined
}

sayHelloStrict();

可以看到,在严格模式下,sayHelloStrict() 函数中的 this 变成了 undefined

为什么会这样呢?

这是因为严格模式旨在消除全局对象的“污染”,避免意外地修改全局变量。将 this 设置为 undefined 可以强制开发者更加明确地指定 this 的指向,避免潜在的错误。

其他绑定规则的影响:

  • 隐式绑定: 隐式绑定在严格模式下仍然有效。也就是说,当函数作为对象的方法被调用时,this 仍然指向调用该方法的对象。

    "use strict";
    
    const obj = {
      name: "小P",
      sayHello: function() {
        console.log(this.name); // 小P
      }
    };
    
    obj.sayHello();
  • 显式绑定: 显式绑定在严格模式下也仍然有效。你可以使用 callapplybind 方法来显式地指定 this 的指向。

    "use strict";
    
    function sayHello(greeting) {
      console.log(greeting + ", " + this.name);
    }
    
    const obj = {
      name: "小Q"
    };
    
    sayHello.call(obj, "你好"); // 你好, 小Q
    sayHello.apply(obj, ["Hello"]); // Hello, 小Q
    
    const boundSayHello = sayHello.bind(obj, "Hola");
    boundSayHello(); // Hola, 小Q
  • new 绑定: new 绑定在严格模式下也仍然有效。使用 new 关键字调用函数时,会创建一个新的对象,并将 this 指向这个新对象。

    "use strict";
    
    function Person(name) {
      this.name = name;
    }
    
    const person = new Person("小R");
    console.log(person.name); // 小R

总结:严格模式下 this 的行为

绑定类型 非严格模式下的 this 严格模式下的 this
默认绑定 全局对象 (window/global) undefined
隐式绑定 调用方法的对象 调用方法的对象
显式绑定 显式指定的对象 显式指定的对象
new 绑定 新创建的对象 新创建的对象

第四幕:实战演练:避免踩坑指南

了解了理论知识,接下来咱们来点实际的。看看在实际开发中,如何避免在严格模式下踩坑。

  1. 全局函数: 如果你在严格模式下定义了一个全局函数,并且没有显式地指定 this 的指向,那么 this 将会是 undefined

    解决方法:可以使用 callapplybind 方法来显式地指定 this 的指向。或者,可以将函数定义为对象的方法。

    "use strict";
    
    function globalFunction() {
      // console.log(this); // undefined
      console.log(this.name); // 报错:Cannot read properties of undefined (reading 'name')
    }
    
    const obj = {
      name: "小S",
      myFunction: globalFunction // 将全局函数作为对象的方法
    };
    
    obj.myFunction(); // 小S
    
    globalFunction.call(obj); // 不推荐,会修改全局函数
  2. 事件处理函数: 在浏览器中,事件处理函数通常会将 this 指向触发事件的 DOM 元素。但在严格模式下,如果没有显式地指定 this 的指向,this 仍然可能是 undefined

    解决方法:可以使用 addEventListener 方法,并使用 bind 方法来显式地指定 this 的指向。

    <!DOCTYPE html>
    <html>
    <head>
      <title>Strict Mode and this</title>
    </head>
    <body>
      <button id="myButton">Click me</button>
    
      <script>
        "use strict";
    
        const button = document.getElementById("myButton");
    
        function handleClick() {
          console.log(this); // <button id="myButton">Click me</button>
          console.log("Button clicked!");
        }
    
        button.addEventListener("click", handleClick);
    
        // 或者使用 bind 显式绑定 this
        // button.addEventListener("click", handleClick.bind(button));
      </script>
    </body>
    </html>
  3. 箭头函数: 箭头函数没有自己的 this,它会继承外层作用域的 this。在严格模式下,如果外层作用域的 thisundefined,箭头函数中的 this 也会是 undefined

    解决方法:确保箭头函数的外层作用域的 this 有明确的指向。

    "use strict";
    
    const obj = {
      name: "小T",
      sayHello: function() {
        const arrowFunction = () => {
          console.log(this.name); // 小T
        };
        arrowFunction();
      }
    };
    
    obj.sayHello();

第五幕:最佳实践:拥抱严格模式!

虽然严格模式下的 this 更加“冷酷”,但它也更加安全、可控。因此,我强烈建议大家在开发过程中,尽量开启严格模式。

  • 代码规范: 制定统一的代码规范,明确 this 的使用方式,避免混淆。
  • 单元测试: 编写充分的单元测试,确保 this 的指向符合预期。
  • 代码审查: 进行代码审查,及时发现潜在的 this 问题。

结尾:this,不再是你的噩梦!

通过今天的学习,相信大家对严格模式下的 this 已经有了更深入的了解。它不再是你的噩梦,而是你手中的一把利剑,可以帮助你写出更加健壮、可靠的代码。

记住,this 就像一只小鸟,你要了解它的习性,才能让它在你手中自由飞翔。🕊️

好了,今天的“this 的奇幻漂流记”就到这里了。感谢大家的收看,我们下期再见!拜拜!👋

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注