likes
comments
collection
share

this:我究竟属于谁?

作者站长头像
站长
· 阅读数 12

前言

在JavaScript编程中,this关键字是一个核心概念,它在函数执行的上下文中扮演着至关重要的角色,决定着函数内部如何访问和操作外部数据。正确理解和运用this的指向规则,对于编写高质量、易于维护的代码至关重要。本文将深入探讨this的工作原理,包括其在不同场景下的指向规则,并特别介绍箭头函数对this处理的不同之处。

一、this的作用与基本使用场景

this的主要作用在于提供一种机制,让函数能够访问和操作定义它的上下文环境中的数据。具体来说,this可以在全局作用域和函数体内被使用。在全局作用域下,this默认指向全局对象,在浏览器环境中即为Window对象;而在函数体内部,this的值则依赖于函数的调用方式和执行环境。

二、this的指向规则

1. 默认绑定

首先,我们先解释一下什么是默认绑定,当一个函数不作为任何对象的方法直接被调用时,我们称其为默认绑定,其this指向全局对象(在非严格模式下)或undefined(在严格模式下)。例如:

var a = 1
function foo(){
    var a = 2 
    function bar(){
        var a = 3
        function baz(){
            console.log(this.a);
        }
        baz() 
    }
    bar()
}
foo()

当你看完这段代码,你认为这里的this指向哪呢? 没错,这里的this指向全局,最后输出1

我们来解释一下为什么,首先我们找到this,它现在在baz()中,baz企图打印出this指向的abaz函数是一个普通函数调用,并没有被某个对象所拥有,所以我们继续往上找,发现baz()的“老大”bar()也是一个默认绑定,那我们继续往上找,发现“老大的老大”foo()也是默认绑定,所以我们继续找,找到全局作用域,发现全局作用域里面有一个全局变量a并调用全局里面的a

2. 隐式绑定

当函数作为某个对象的属性(方法)被调用时,this会被绑定到该对象上。这是最常见的this使用场景之一:

const person = {
    name: "Alice",
    greet: function() {
        console.log(`Hello, my name is ${this.name}`);
    }
};

person.greet(); // 输出 "Hello, my name is Alice"

这个代码应该大家都见多了,就不多解释了

3. 隐式丢失

在链式调用或函数作为参数传递给其他函数时,如果中间某个环节改变了调用方式,可能会导致this的隐式丢失。不过,这通常被视为一种错误用法,应避免或通过显示绑定来修正。

4. 显示绑定

JavaScript提供了call(), apply()bind()方法来显式地设置函数执行时this的值,从而“掰弯”this的指向:

var obj = {
    a:1
}

function foo(x,y){
    console.log(this.a,x+y);
}
foo.call(obj,1,2) //call会把foo中的this掰弯到obj中
foo.apply(obj,[2,3])
const bar = foo.bind(obj,1)
bar(2)

5. new绑定

当使用new关键字创建一个对象实例时,构造函数内部的this会自动绑定到新创建的对象上:

function Person(name) {
    this.name = name;
    this.sayName = function() {
        console.log(this.name);
    };
}

const alice = new Person("Alice");
alice.sayName(); // 输出 "Alice"

三、箭头函数与this

箭头函数是ES6引入的一种新的函数表达式,它在处理this时有所不同。箭头函数不会创建自己的this上下文,而是继承自其所在的词法环境。这意味着箭头函数内部的this就是其定义时所在上下文的this

const person = {
    name: "Dave",
    greet: () => {
        console.log(`Hello, I'm ${this.name}`); // 注意这里的this并不指向person
    }
};

person.greet(); // 输出 "Hello, I'm undefined" 或者可能的全局变量名,取决于环境

在这个例子中,尽管greetperson对象的一个方法,但因为使用了箭头函数,其内部的this并没有绑定到person上,而是继承了外层(全局或最近的非箭头函数)的this值。

四、优先级

在JavaScript中,this的绑定规则遵循一定的优先级顺序,这有助于确定在特定情境下this的指向。以下是this绑定的五种类型及其优先级,从高到低排列:

1.new绑定:当函数作为构造函数通过new关键字被调用时,this会被绑定到新创建的对象实例上。这是最高优先级的绑定。

2.显示绑定:通过.call(), .apply(), 或 .bind()方法明确指定函数的this值。这种方式可以覆盖默认的绑定规则。

3.隐式绑定:当函数作为某个对象的属性或方法被调用时,this会被绑定到该对象上。这是最常见的绑定情况之一。

4.默认绑定:如果以上三种情况都不适用,this会按照以下规则默认绑定:

5.箭头函数中的绑定:箭头函数不遵循上述规则,它没有自己的this。箭头函数中的this是由其定义时的上下文决定的,即外层(非箭头)函数的this值,或者全局作用域的this值(如果是顶级作用域)。

总结起来this的绑定遵循一个确定的优先级顺序,其中new绑定优先级最高,箭头函数中的特殊处理虽然不在这四类传统绑定规则之内,但其行为类似于一种特殊的默认绑定,且在实践中非常有用。理解这些优先级有助于准确预测和控制函数内部this的指向,避免潜在的错误。

总结

正确理解和应用this的规则,是JavaScript进阶之路上的重要一步。通过合理利用默认绑定、隐式绑定、显示绑定以及new绑定等机制,可以使代码更加灵活和高效。而箭头函数作为一种特殊的函数形式,以其简洁的语法和固定的this行为,为解决某些场景下的问题提供了新的选择。掌握这些知识,将帮助你编写出更健壮、更易于维护的JavaScript代码。

好的,这次的内容就分享到这了,如果小友觉得整的还不错的,可以留下一个小小的赞帮助俺找回自己的脑子,谢谢啦!!!

转载自:https://juejin.cn/post/7377051427887628342
评论
请登录