this这个JavaScript的关键字通常使该语言的初学者感到困惑。这种混乱的部分原因是, this与其他语言(例如Java或Python中的self)相比, JavaScript中的JavaScript区别对待。
理解this为了理解JavaScript中的更高级概念或阅读和编写JavaScript代码, 这绝对是必要的, 这就是为什么我们将在本文中尝试阐明这在JavaScript中的真正含义。
我们将花费大量的文章来学习this参考JavaScript中的函数, 这就是为什么我们首先要看一个有关JavaScript函数的事实, 它将帮助我们更好地做到这一点。
JavaScript中的函数本质上是对象。像对象一样, 它们可以分配给变量, 传递给其他函数并从函数返回。与对象非常相似, 它们具有自己的属性。这些属性之一是this.
this的值store是JavaScript程序的当前执行上下文。因此, 在函数内部使用时this值的变化取决于函数的定义方式, 调用方式以及默认的执行上下文。
注意 :
this
始终持有对
单
对象, 用于定义当前代码执行上下文行。
在我们进一步研究如何
this
在函数中的行为, 让我们看一下它们在函数外部的行为:
全局背景:
编写在函数外部的代码行属于
全球背景
和的价值
this
在此全局上下文中与全局对象相同。
例如, 如果你打开浏览器控制台并在其中输入以下几行, 然后按回车/确认键:
console.log(this)
你会看到Window对象正在登录到控制台。这是因为在浏览器运行时(例如Chrome运行时)中, 全局对象是Window对象。
但是, 在函数内部, 全局上下文可能不再存在, 并且函数可能具有自己定义的上下文, 因此,
this
。为了理解这一点, 让我们把注意力转移到函数上:
JavaScript中的函数可以通过多种方式调用:
1, 函数调用
2.方法调用
3, 构造函数调用
这与功能调用:
函数调用是指使用函数名称或表达式求值到函数对象并后跟一组前后的第一个方括号(包括方括号表示我们要JavaScript引擎立即执行该函数)来调用该函数的过程)。
例如:
<!DOCTYPE html>
<html>
<body>
<script>
function doSomething() {
// do something here
}
// function invocation
doSomething();
</script>
</body>
</html>
this如果在doSomething函数内部通过上述函数调用来调用, 则它具有全局对象的值, 即窗口浏览器环境中的对象:
<!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
然而, 这并非总是如此。如果做点什么()功能正在运行严格模式, 它将记录未定义而不是全局窗口对象。这是因为, 在严格模式下(由line表示:"使用严格";), 此值的默认值(对于任何函数对象)均设置为undefined, 而不是全局对象。
例如 :
<!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
这与方法调用:
函数定义为对象的字段或属性时, 称为方法。
<!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.logInfo()), 然后再加上一组开括号。
必须了解如何
函数调用
和
方法调用
不同。
反过来, 这将有助于我们了解
this
上下文可能在任何给定的函数中, 因为在这些调用的每一个中,
this
是不同的。
在使用属性访问器调用的方法内部, this将具有调用对象的值, 即this将指向与属性访问器结合使用以进行调用的对象。
例如 :
<!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()
是一种方法
加
对象, 因此使用第9和10行中的方法调用规则进行调用。
我们知道, 当使用方法调用模式时,
this
设置为调用对象。
在this里面
calc()
方法, 此值设置为调用对象, 在本例中为
加
。这样我们就可以成功访问
加
‘s
数
属性。
但是, 让我们知道一个主要的混淆点:
发生什么事this在嵌套在对象方法内部的函数中?
<!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
让我们尝试了解发生了什么。
当我们打电话
calc()
在第14和15行中, 我们使用的是方法调用
this
to
加
in
calc()
。可以使用第4行中的log语句来验证这一点。
然而, innerfunc()从内部调用calc()使用简单函数调用的方法(第11行)。这意味着, 在里面innerfunc() this 设置为全局对象, 该对象没有数性质, 因此获得NaN输出。
我们该如何解决这个问题?this从嵌套函数的外部方法?
一种解决方案是分配this从外部函数到要在嵌套函数中使用的变量的值, 如下所示:
<!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(), 我们将尽快进行调查。
这与构造函数调用:
构造函数调用在以下情况下执行新关键字后跟一个函数名称, 以及一组右括号和右括号(带或不带参数)。
例如:let person1 = new People('John', 21);
这里,
人1
是新创建的对象, 并且
人
是用于创建此对象的构造函数。
构造函数调用是使用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))。
然后, 它将构造函数的原型(人员)链接到新创建的对象, 从而确保该对象可以继承构造函数的所有属性和方法。
然后, 在这个新创建的对象上调用构造函数, 如果我们调用方法调用, 将会看到类似的结果, 因此, 在构造函数内部, 这将获得调用中使用的新创建对象的值。
最后, 将创建的对象及其所有属性和方法均设置为person1
一个人应该记住新关键字对于正确设置构造函数内部的上下文至关重要。新我们将有一个正常的函数调用, 因此这个即使在构造函数内部, 也可能会错误地将其设置为全局对象。
我们将涵盖更多主题, 例如箭头功能, 分离的方法等。这个在Set-2中的JavaScript中。