JavaScript 中的 this

JavaScript 中的this关键字通常是该语言初学者的困惑之源。这种混淆部分源于这样一个事实,即JavaScript 中的this与其他语言(如 Java 或 Python 中的 self)的处理方式不同。为了理解 JavaScript 中更高级的概念或读写 JavaScript 代码,
理解这一点是绝对必要的,这就是为什么我们将在本文中试图阐明这在 JavaScript 中的真正含义。
我们将在本文的大部分时间里参考 JavaScript 中的函数来学习方面的知识,这就是为什么我们首先要了解一个关于 JavaScript 函数的事实,它可以帮助我们更好地做到这一点。
 

this 和函数

JavaScript 中的函数本质上是对象。像对象一样,它们可以分配给变量,传递给其他函数并从函数返回。就像对象一样,它们也有自己的属性。这些属性之一是thisthis
存储的值是 JavaScript 程序的当前执行上下文。因此,当在函数内部使用时,this的值将根据该函数的定义方式、调用方式和默认执行上下文而改变。注意:始终包含对单个对象的引用,该对象定义了当前代码行的执行上下文。 

在我们深入研究 this 在函数中的行为之前,让我们看看它在函数之外的行为:
全局上下文: 
在函数外部编写的一行代码被称为属于全局上下文,并且在这个全局上下文中 this 的值是与全局对象相同。
例如,如果您打开浏览器控制台并在其中输入以下行,然后按回车/回车键: 
console.log(this)
您会看到 Window 对象正在登录到控制台。这是因为全局对象在浏览器运行时(例如 Chrome 的运行时)是 Window 对象。 
然而,在函数内部,全局上下文可能不再存在,函数可能有自己定义的上下文,因此 this 的值不同。为了理解这一点,让我们把注意力转向函数:
函数,在 JavaScript 中可以通过多种方式调用:

1.函数调用 

2.方法调用

3. 构造函数调用
 

this与函数调用:

函数调用是指使用函数名称或表达式调用函数的过程,该表达式计算为函数对象,后跟一组打开和关闭的第一个括号(包含括号表示我们正在要求 JavaScript 引擎立即执行该函数)。
例如: 
 

  • JavaScript

<!DOCTYPE html>
<html>
<body>
<script>
    function doSomething() {
        // do something here
    }
  
// function invocation
doSomething(); 
</script>                    
</body>
</html>

doSomething函数里面的this,如果是通过上面的函数调用来调用的话,它的值就是全局对象,也就是浏览器环境中的window对象:
 

  • JavaScript

<!DOCTYPE html>
<html>
<body>
<script>
    function doSomething(a, b) {
  
       // adds a propone property to the Window object
        this.propone = "test value"
    }
  
// function invocation
doSomething(); 
document.write(window.propone);
</script>                    
</body>
</html>                        

输出:  

test value

然而,这并非总是如此。如果 doSomething() 函数在严格模式下运行,它将记录undefined而不是全局窗口对象。这是因为,在严格模式下(由行 : 'use strict';表示), this 的默认值,对于任何函数对象都设置为未定义而不是全局对象。 
例如 :  

  • JavaScript

<!DOCTYPE html>
<html>
<body>
<script>
    function doSomething() {
        // enable the strict mode
        'use strict'
  
       // logs undefined
        document.write(this + '<br>'
            function innerFunction() {
              // Also logs undefined, indicating that 
              // strict mode permeates to inner function scopes
                document.write(this
            }
        innerFunction();
    }
  
// function invocation
doSomething(); 
</script>                    
</body>
</html>                                           

输出:  

undefined
undefined 

 

this与方法调用:

函数,当定义为对象的字段或属性时,称为方法。 

  • JavaScript

<!DOCTYPE html>
<html>
<body>
<script>
    let person = {
        name : "John",
        age : 31,
        logInfo : function() {
            document.write(this.name + " is " + this.age + " years old ");
        }
    }
       // logs John is 31 years old
       person.logInfo() 
                 </script>                    
</body>
</html>                                        

输出:  

John is 31 years old 

在上面的代码示例中,logInfo()person 对象的一个​​方法,我们使用对象调用模式来调用它。 
也就是说,我们使用属性访问器来访问作为对象一部分的方法。
这样的调用需要使用一个表达式来计算我们的方法所属的对象,以及一个属性访问器(例如:person.logInfo()),后跟一组左括号和右括号。
了解函数调用和方法调用的不同之处至关重要。 
这反过来将帮助我们理解this上下文在任何给定函数中可能是什么,因为在每个调用中,this是不同的。
在使用属性访问器调用的此类方法中,this将具有调用对象的值,即this将指向与属性访问器一起使用以进行调用的对象。
例如 :  

  • JavaScript

<!DOCTYPE html>
<html>
<body>
<script>
    let add = {
        num : 0,
        calc : function() {
  
            // logs the add object
            document.write(this + ' '
                this.num
                += 1;
            return this.num;
        }
    };
  
// logs 1
document.write(add.calc() + '<br>'); 
// logs 2
document.write(add.calc()); 
</script>                    
</body>
</html>

输出:  

[object Object] 1
[object Object] 2 

在上面的例子中, calc() 是 add 对象的一个​​方法,因此使用第 9 行和第 10 行的方法调用规则来调用。 
我们知道,当使用方法调用模式时,this的值被设置为调用目的。
在这个 calc() 方法中,this 的值被设置为调用对象,在我们的例子中是 add。因此我们可以成功访问 add 的 num 属性。 
然而,让我们看看一个主要的混淆点:在嵌套在对象方法中的函数中 
会发生什么

  • JavaScript

<!DOCTYPE html>
<html>
<body>
<script>
    let add = {
        num : 0,
        calc : function() {
  
        // logs the add object
        document.write(this + ' '
  
        function innerfunc() {
            this.num += 1;
  
        // logs the window object
        document.write(this + ' '); 
  
        return this.num
  
    } return innerfunc();
     }
};
  
// logs NaN
document.write(add.calc() + '<br>'); 
  
// logs NaN
document.write(add.calc());
</script>                 
</body>
</html>                               

输出:  

[object Object] [object Window] NaN
[object Object] [object Window] NaN 

让我们试着理解刚刚发生的事情。 
当我们在第 14 行和第 15 行调用 calc() 时,我们正在使用方法调用,它将this设置为添加到 calc() 中。这可以使用第 4 行中的 log 语句来验证。
但是,使用简单的函数调用(第 11 行)从 calc() 方法中调用 innerfunc()。这意味着,在 innerfunc() 内部,this 被设置为没有 num 属性的全局对象,因此获得了 NaN 输出。
我们如何解决这个问题?我们如何从嵌套函数内部的外部方法中保留 this 的值?
一种解决方案是将外部函数的this值分配给要在嵌套函数中使用的变量,如下所示: 

  • JavaScript

<!DOCTYPE html>
<html>
<body>
<script>
    let add = {
        num : 0,
        calc : function() {
  
            // logs the add object
            document.write(this + ' '
  
           // using thisreference variable to 
           // store the value of this
           thisreference = this
  
            function innerfunc()
            {
  
             // using the variable to access the
             // context of the outer function
                thisreference.num += 1; 
  
               // logs the add object
                document.write(thisreference + ' ');
                return thisreference.num;
            }
            return innerfunc();
        }
    };
  
// logs 1
document.write(add.calc() + '<br>'); 
  
// logs 2
document.write(add.calc()); 
</script>                    
</body>
</html>                                                

输出:  

[object Object] [object Object] 1
[object Object] [object Object] 2 

此问题的其他解决方案包括使用 bind()、call() 或 apply(),我们将很快研究这些方法。
 

this 与构造函数调用:

当 new 关键字后跟一个函数名和一组左括号和右括号(带或不带参数)时,将执行构造函数调用。
例如: let person1= new People('John', 21); 
这里,person1 是新创建的对象,People 是用于创建该对象的构造函数。
构造函数调用是在 JavaScript 中创建对象的几种方法之一。 
当我们将 new 关键字与函数名结合使用时,究竟会发生什么? 
通过这种方法创建对象基本上涉及五个步骤。让我们用下面的例子来研究它们: 

  • JavaScript

<!DOCTYPE html>
<html>
<body>
<script>
let people = function(name, age) {
         this.name = name;
         this.age = age;
  
    this.displayInfo = function() {
       document.write(this.name + " is " + this.age + " years old");
      }
    }
  
let person1
    = new people('John', 21);
  
// logs John is 21 years old
person1.displayInfo();
</script>         
</body>
</html>                                                                                   

输出:  

John is 21 years old 
  • 首先,创建一个空对象,它是与 new 一起使用的函数名称的实例(即:people(name, age))。换句话说,它将对象的构造函数属性设置为调用中使用的函数(people(name, age))。
     
  • 然后,它将构造函数(people)的原型链接到新创建的对象,从而保证这个对象可以继承构造函数的所有属性和方法 
     
  • 然后,在这个新创建的对象上调用构造函数。如果我们回想方法调用,我们会看到类似。因此,在构造函数内部,this获取调用中使用的新创建对象的值。 
     
  • 最后,将创建的对象及其所有属性和方法集返回给 person1 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值