我注意到,对于 Stack Overflow 网站上的 JavaScript, this
关键字是什么以及如何正确(以及错误地)使用this
关键字似乎没有明确的解释。
我目睹了它的一些非常奇怪的行为,并且未能理解为什么会发生它。
怎么this
时候它应该被用来工作?
我建议先阅读Mike West的文章Scope in JavaScript ( 镜像 )。这是一个很好的,友好的介绍的概念, this
在 JavaScript 和范围链。
一旦你开始习惯this
的规则实际上是相当简单的。 ECMAScript 5.1 标准 this
定义:
§11.1.1的
this
关键字
this
关键字的值为当前执行上下文的 ThisBinding 的值
JavaScript 解释器在评估 JavaScript 代码时会维护 ThisBinding,例如特殊的 CPU 寄存器,其中包含对对象的引用。每当仅在以下三种情况之一中建立执行上下文时,解释器就会更新 ThisBinding:
在顶级代码中评估的 JavaScript 代码就是这种情况,例如,直接在<script>
内部时:
<script>
alert("I'm evaluated in the initial global execution context!");
setTimeout(function () {
alert("I'm NOT evaluated in the initial global execution context.");
}, 1);
</script>
在初始的全局执行上下文中评估代码时,ThisBinding 设置为全局对象window
(第10.0.4.1.1 节 )。
… 直接调用eval()
Binding 保持不变;它与调用执行上下文的ThisBinding (第10.4.2 (2)(a)节)的值相同。
… 如果不是通过直接调用eval()
将这个 Binding 设置为全局对象,就像在初始全局执行上下文中执行一样(第10.4.2 (1)节)。
§15.1.2.1.1 定义了对eval()
的直接调用。基本上, eval(...)
是直接调用,而类似(0, eval)(...)
或var indirectEval = eval; indirectEval(...);
是对eval()
的间接调用。看到chuckj 对 JavaScript 中的 (1,eval)('this')vs eval('this') 的回答 吗?和Dmitry Soshnikov 的 ECMA-262-5 详细信息。第 2 章严格模式。当您可能使用间接eval()
调用时。
调用函数时会发生这种情况。如果在对象上调用了函数,例如obj.myMethod()
或等效的obj["myMethod"]()
,则 ThisBinding 设置为对象(示例中为obj
;第13.2.1 节 )。在大多数其他情况下,ThisBinding 设置为全局对象(第10.4.3 节 )。
之所以写 “在大多数情况下”,是因为有八个 ECMAScript 5 内置函数可以在参数列表中指定 ThisBinding。这些特殊功能采用了一个所谓的thisArg
,当调用该函数时,它会成为 ThisBinding(第10.4.3 节 )。
这些特殊的内置函数是:
Function.prototype.apply( thisArg, argArray )
Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )
Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )
Array.prototype.every( callbackfn [ , thisArg ] )
Array.prototype.some( callbackfn [ , thisArg ] )
Array.prototype.forEach( callbackfn [ , thisArg ] )
Array.prototype.map( callbackfn [ , thisArg ] )
Array.prototype.filter( callbackfn [ , thisArg ] )
对于Function.prototype
函数,它们是在函数对象上调用的,而不是将 ThisBinding 设置为函数对象,而是将 ThisBinding 设置为thisArg
。
对于Array.prototype
函数,将在执行上下文中调用给定的callbackfn
,其中,如果提供,则将 ThisBinding 设置为thisArg
。否则,转到全局对象。
这些是纯 JavaScript 的规则。当您开始使用 JavaScript 库(例如 jQuery)时,您可能会发现某些库函数会操纵this
的值。这些 JavaScript 库的开发人员之所以这样做是因为它倾向于支持最常见的用例,并且该库的用户通常会发现此行为更加方便。将引用this
回调函数传递给库函数时,应确保参考该文档,以确保有关在调用函数时this
的值的任何保证。
如果您想知道 JavaScript 库如何处理this
的值,则该库仅使用接受thisArg
的内置 JavaScript 函数thisArg
。您也可以使用回调函数和thisArg
编写自己的函数:
function doWork(callbackfn, thisArg) {
//...
if (callbackfn != null) callbackfn.call(thisArg);
}
我还没有提到一个特殊情况。通过new
运算符构造新对象时,JavaScript 解释器会创建一个新的空对象,设置一些内部属性,然后在新对象上调用构造函数。因此,当一个函数被调用在构造方面,的值this
是解释创建的新对象:
function MyType() {
this.someData = "a string";
}
var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);
箭头功能 (在 ECMA6 引入)改变的范围this
。参见现有规范问题, 箭头函数与函数声明 / 表达式:它们是否等效 / 可互换?了解更多信息。简而言之:
箭自己的职能没有
this
.... 结合。相反,这些标识符像任何其他变量一样在词法范围内解析。这意味着,一个箭头函数内部,this
... 参照(一个或多个),以的值this
在箭头函数是在定义的环境。
要显示答案,请将鼠标悬停在浅黄色框上。
什么是值this
在标线?为什么?
window
—在初始全局执行上下文中评估标记的行。
if (true) {
// What is `this` here?
}
什么是价值this
当标线obj.staticFunction()
执行?为什么?
obj
—在对象上调用函数时,ThisBinding 设置为该对象。
var obj = {
someData: "a string"
};
function myFun() {
return this // What is `this` here?
}
obj.staticFunction = myFun;
console.log("this is window:", obj.staticFunction() == window);
console.log("this is obj:", obj.staticFunction() == obj);
什么是值this
在标线?为什么?
window
在此示例中,JavaScript 解释器输入函数代码,但是由于未在对象上调用
myFun
/obj.myMethod
,因此 ThisBinding 设置为window
。这与 Python 不同,在 Python 中,访问方法(
obj.myMethod
)创建绑定的方法对象 。
var obj = {
myMethod: function () {
return this; // What is `this` here?
}
};
var myFun = obj.myMethod;
console.log("this is window:", myFun() == window);
console.log("this is obj:", myFun() == obj);
什么是值this
在标线?为什么?
window
这个很棘手。在评估评估代码时,
this
是obj
。然而,在 EVAL 代码,myFun
不是在对象上调用,所以 ThisBinding 设置为window
的呼叫。
function myFun() {
return this; // What is `this` here?
}
var obj = {
myMethod: function () {
eval("myFun()");
}
};
什么是值this
在标线?为什么?
obj
行
myFun.call(obj);
正在调用特殊的内置函数Function.prototype.call()
,该Function.prototype.call()
接受thisArg
作为第一个参数。
function myFun() {
return this; // What is `this` here?
}
var obj = {
someData: "a string"
};
console.log("this is window:", myFun.call(obj) == window);
console.log("this is obj:", myFun.call(obj) == obj);
与其他语言相比, this
关键字在 JavaScript 中的行为有所不同。在面向对象的语言中, this
关键字引用该类的当前实例。在 JavaScript 中, this
值取决于函数的调用上下文( context.function()
)及其调用位置。
1. 在全球范围内使用
在全局上下文中使用this
时,它将绑定到全局对象(浏览器中的window
)
document.write(this); //[object Window]
当您在全局上下文中定义的函数中使用this
函数时,由于该函数实际上已成为全局上下文的方法, this
它仍然绑定到全局对象。
function f1()
{
return this;
}
document.write(f1()); //[object Window]
在f1
之上是全局对象的方法。因此,我们还可以在window
对象上调用它,如下所示:
function f()
{
return this;
}
document.write(window.f()); //[object Window]
2. 当在内部对象方法中使用时
当您使用this
关键字的对象方法中, this
势必会 “立即” 包围对象。
var obj = {
name: "obj",
f: function () {
return this + ":" + this.name;
}
};
document.write(obj.f()); //[object Object]:obj
在上面,我已经将单词立即用双引号引起来。要指出的是,如果将对象嵌套在另一个对象中,则this
对象将绑定到直接父对象。
var obj = {
name: "obj1",
nestedobj: {
name:"nestedobj",
f: function () {
return this + ":" + this.name;
}
}
}
document.write(obj.nestedobj.f()); //[object Object]:nestedobj
即使你明确的对象添加功能的方法,但它仍然遵循上述规则,那就是this
仍然指向直接父对象。
var obj1 = {
name: "obj1",
}
function returnName() {
return this + ":" + this.name;
}
obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1
3. 调用无上下文功能时
当您使用this
是没有任何上下文中调用(即没有任何物体上)里面的功能,它被绑定到全局对象( window
浏览器)(即使该函数的对象中定义)。
var context = "global";
var obj = {
context: "object",
method: function () {
function f() {
var context = "function";
return this + ":" +this.context;
};
return f(); //invoked without context
}
};
document.write(obj.method()); //[object Window]:global
尝试所有功能
我们也可以使用功能尝试上述几点。但是有一些区别。
this
将成员添加到函数中。指定它们。 new
运算符创建其实例。 下面我尝试了所有的事情,我们做了与对象与this
之上,但首先创建功能,而不是直接书写的对象。
/*********************************************************************
1. When you add variable to the function using this keyword, it
gets added to the function prototype, thus allowing all function
instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
this.name = "ObjDefinition";
this.getName = function(){
return this+":"+this.name;
}
}
obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition
/*********************************************************************
2. Members explicitly added to the function protorype also behave
as above: all function instances have their own copy of the
variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
return "v"+this.version; //see how this.version refers to the
//version variable added through
//prototype
}
document.write(obj1.getVersion() + "<br />"); //v1
/*********************************************************************
3. Illustrating that the function variables added by both above
ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1
obj2.incrementVersion(); //incrementing version in obj2
//does not affect obj1 version
document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1
/*********************************************************************
4. `this` keyword refers to the immediate parent object. If you
nest the object through function prototype, then `this` inside
object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj',
getName1 : function(){
return this+":"+this.name;
}
};
document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj
/*********************************************************************
5. If the method is on an object's prototype chain, `this` refers
to the object the method was called on, as if the method was on
the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
//as its prototype
obj3.a = 999; //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
//calling obj3.fun() makes
//ProtoObj.fun() to access obj3.a as
//if fun() is defined on obj3
4. 在构造函数内部使用时 。
当将该函数用作构造函数时(即使用new
关键字调用它时), this
内部函数主体指向正在构造的新对象。
var myname = "global context";
function SimpleFun()
{
this.myname = "simple function";
}
var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
// object being constructed thus adding any member
// created inside SimipleFun() using this.membername to the
// object being constructed
//2. And by default `new` makes function to return newly
// constructed object if no explicit return value is specified
document.write(obj1.myname); //simple function
5. 在原型链上定义的内部函数中使用时
如果该方法在对象的原型链上,则this
方法内部的对象将引用该方法在其上调用的对象,就好像该方法是在对象上定义的一样。
var ProtoObj = {
fun: function () {
return this.a;
}
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun()
//to be the method on its prototype chain
var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999
//Notice that fun() is defined on obj3's prototype but
//`this.a` inside fun() retrieves obj3.a
6. 在 call(),apply()和 bind()函数内部
Function.prototype
上定义。 this
同时被执行的功能是将被使用。它们还可以在调用原始函数时采用任何要传递给原始函数的参数。 fun.apply(obj1 [, argsArray])
obj1
设置为fun()
内部的this
值,并调用传递给argsArray
元素的fun()
作为其参数。 fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- 将obj1
设置this
fun()
的值,并通过arg1, arg2, arg3, ...
调用fun()
arg1, arg2, arg3, ...
作为它的参数。 fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- 返回对该函数fun
的引用,其中this
内部 fun 绑定到obj1
,将fun
参数绑定到指定的参数arg1, arg2, arg3,...
apply
, call
和bind
之间的区别必须已经很明显。 apply
允许指定参数以充当类似数组的对象,即具有数字length
属性和相应的非负整数属性的对象。而call
允许直接指定函数的参数。 apply
和call
立即在指定的上下文中使用指定的参数调用该函数。另一方面, bind
仅返回绑定到指定的this
值和参数的函数。我们可以通过将其分配给变量来捕获对该返回函数的引用,以后我们可以随时调用它。 function add(inc1, inc2)
{
return this.a + inc1 + inc2;
}
var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
//above add.call(o,5,6) sets `this` inside
//add() to `o` and calls add() resulting:
// this.a + inc1 + inc2 =
// `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
// `o.a` i.e. 4 + 5 + 6 = 15
var g = add.bind(o, 5, 6); //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />"); //15
var h = add.bind(o, 5); //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
// 4 + 5 + 6 = 15
document.write(h() + "<br />"); //NaN
//no parameter is passed to h()
//thus inc2 inside add() is `undefined`
//4 + 5 + undefined = NaN</code>
7. this
内部事件处理程序
this
函数将引用相应的元素。可以使用addeventListener
方法或通过传统的事件注册方法(如onclick
来完成此类直接功能分配。 this
直接事件属性内(如<button onclick="...this..." >
的元素,它是指该元素。 this
函数将解析为全局对象window
。 attachEvent
将函数附加到事件处理程序时,可以实现上述相同的行为。它没有将功能分配给事件处理程序(因而没有将其分配为元素的功能方法),而是在事件上调用了功能(在全局上下文中有效地调用了该功能)。 我建议最好在JSFiddle 中尝试一下 。
<script>
function clickedMe() {
alert(this + " : " + this.tagName + " : " + this.id);
}
document.getElementById("button1").addEventListener("click", clickedMe, false);
document.getElementById("button2").onclick = clickedMe;
document.getElementById("button5").attachEvent('onclick', clickedMe);
</script>
<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>
<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />
<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />
IE only: <button id="button5">click() "attached" using attachEvent() </button>
8. this
在 ES6 箭头功能
在箭头函数中, this
行为类似于普通变量:它将从其词法范围继承。函数的this
,其中定义了 arrow 函数,将是 arrow 函数的this
。
因此,这与以下行为相同:
(function(){}).bind(this)
请参见以下代码:
const globalArrowFunction = () => {
return this;
};
console.log(globalArrowFunction()); //window
const contextObject = {
method1: () => {return this},
method2: function(){
return () => {return this};
}
};
console.log(contextObject.method1()); //window
const contextLessFunction = contextObject.method1;
console.log(contextLessFunction()); //window
console.log(contextObject.method2()()) //contextObject
const innerArrowFunction = contextObject.method2();
console.log(innerArrowFunction()); //contextObject
this
考虑以下功能:
function foo() {
console.log("bar");
console.log(this);
}
foo(); // calling the function
请注意,我们在正常模式下运行此程序,即未使用严格模式。
当在浏览器中运行,值this
将被记录为window
。这是因为window
是 Web 浏览器范围内的全局变量。
如果你像 node.js 中的环境中运行该同一段代码, this
将涉及到全局变量在你的应用程序。
现在,如果我们在严格模式下通过添加语句"use strict";
到函数声明的开头, this
将不再引用这两种环境中的全局变量。这样做是为了避免在严格模式下造成混淆。 this
会,在这种情况下,只要登录undefined
,因为那是它是什么,没有定义它。
在以下情况下,我们将看到如何操纵this
的值。
有不同的方法可以做到这一点。如果您已经使用诸如forEach
和slice
类的 Javascript 调用了本机方法,那么您应该已经知道,在this
情况下, this
变量引用了您在其上调用了该函数的Object
(请注意,在 javascript 中,几乎所有东西都是Object
,包括Array
和Function
)。以下面的代码为例。
var myObj = {key: "Obj"};
myObj.logThis = function () {
// I am a method
console.log(this);
}
myObj.logThis(); // myObj is logged
如果Object
包含一个包含Function
的属性,则该属性称为方法。调用此方法时,将始终this
变量设置为与之关联的Object
。对于严格和非严格模式都是如此。
注意,如果一个方法被存储(或更确切地说,复制)在另一变量中,参照this
不再保留在新的变量。例如:
// continuing with the previous code snippet
var myVar = myObj.thisMethod;
myVar();
// logs either of window/global/undefined based on mode of operation
考虑一个更常见的实际情况:
var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself
new
关键字考虑一下 Javascript 中的构造函数:
function Person (name) {
this.name = name;
this.sayHello = function () {
console.log ("Hello", this);
}
}
var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`
这是如何运作的?好吧,让我们看看使用new
关键字时会发生什么。
new
关键字调用该函数将立即初始化Person
类型的Object
。 Object
的构造函数将其构造函数设置为Person
。另外,请注意typeof awal
将仅返回Object
。 Object
分配Person.prototype
的原型。这意味着Person
原型中的任何方法或属性都可用于Person
所有实例,包括awal
。 Person
本身被调用; this
是对新建物体awal
。 很简单,是吗?
请注意,官方 ECMAScript 规范无处声明此类函数是实际的constructor
函数。它们只是正常功能,而new
可以在任何功能上使用。只是我们原样使用它们,因此我们仅如此称呼它们。
call
并apply
是的,因为function
也是Objects
(实际上是 Javascript 中的第一类变量),所以即使函数也具有本身就是函数的方法。
所有的功能从全球继承Function
,及其两个多方法call
和apply
,都可以用来操纵的值this
在它们所调用的函数。
function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);
这是使用call
的典型示例。它基本上采用第一个参数,并在函数foo
this
参数设置为对thisArg
的引用。传递给call
所有其他参数作为参数传递给foo
函数。
因此,上面的代码将在控制台中记录{myObj: "is cool"}, [1, 2, 3]
。相当不错的方法来改变的值this
在任何功能。
apply
几乎与call
accept 相同,它只接受两个参数: thisArg
和一个包含要传递给函数的参数的数组。因此,上述call
可以转换为如下apply
:
foo.apply(thisArg, [1,2,3])
注意, call
和apply
可以通过我们在第二个项目符号中讨论的点方法调用来覆盖this
设置的值。很简单:)
bind
! bind
是call
和apply
的兄弟。它也是所有函数从 Javascript 的全局Function
构造函数继承的方法。 bind
和call
/ apply
之间的区别是call
和apply
都将实际调用该函数。另一方面, bind
返回一个带有thisArg
和arguments
预设的新函数。让我们举个例子来更好地理解这一点:
function foo (a, b) {
console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */
bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`
看到两者之间的区别了吗?它很微妙,但是用法不同。像call
和apply
一样, bind
也将通过点方法调用来覆盖this
设置的值。
另请注意,这三个功能均未对原始功能进行任何更改。 call
和apply
将从新构造的函数返回值,而bind
将返回新构造的函数本身,随时可以调用。
有时候,你不喜欢的事实, this
改变与范围,尤其是嵌套的范围。看下面的例子。
var myObj = {
hello: function () {
return "world"
},
myMethod: function () {
// copy this, variable names are case-sensitive
var that = this;
// callbacks ftw \o/
foo.bar("args", function () {
// I want to call `hello` here
this.hello(); // error
// but `this` references to `foo` damn!
// oh wait we have a backup \o/
that.hello(); // "world"
});
}
};
在上面的代码中,我们看到的价值this
与嵌套的范围内改变,但我们想要的值, this
从原来的范围。因此,我们 “复制” this
到that
和所使用的副本,而不是this
。聪明吧?
指数:
this
是什么? new
关键字怎么办? call
和apply
操作this
? bind
。 this
可解决嵌套范围问题。 “这” 是关于范围的。每个函数都有自己的作用域,并且由于 JS 中的所有对象都是对象,所以即使一个函数也可以使用 “此” 将一些值存储到自身中。 OOP 101 教导 “此” 仅适用于对象的实例 。因此,每次执行一个功能时,该功能的新 “实例” 具有新的含义 “this”。
大多数人在匿名闭包函数中尝试使用 “this” 时会感到困惑:
(function(value) { this.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = this.value; // uh oh!! possibly undefined }); })(2);
所以在这里,在 each()中,“this” 不包含您期望它(从
this.value = value;它上面)。因此,要解决此问题(无双关语),开发人员可以:
(function(value) { var self = this; // small change self.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = self.value; // phew!! == 2 }); })(2);
试试看; 您将开始喜欢这种编程模式
JavaScript 中的this
始终是指所执行函数的 “所有者”。
如果未定义任何显式所有者,则引用最高的所有者,即窗口对象。
所以如果我做到了
function someKindOfFunction() {
this.style = 'foo';
}
element.onclick = someKindOfFunction;
this
将引用元素对象。但是要小心,很多人都会犯这个错误。
<element onclick="someKindOfFunction()">
在后一种情况下,您仅引用函数,而不将其移交给元素。因此, this
将引用窗口对象。
由于该主题的发展,我为刚接触this
主题的读者提供了几点建议。
this
决定的? 我们使用这种方式类似于在自然语言(如英语)中使用代词的方式:“约翰之所以跑得快,是因为他正试图赶上火车。” 相反,我们可以写成 “…… 约翰正试图赶上火车”。
var person = {
firstName: "Penelope",
lastName: "Barrymore",
fullName: function () {
// We use "this" just as in the sentence above:
console.log(this.firstName + " " + this.lastName);
// We could have also written:
console.log(person.firstName + " " + person.lastName);
}
}
this
直到对象调用定义它的功能不被分配的值 。在全局范围内,所有全局变量和函数都在window
对象上定义。因此,全局函数中的this
引用全局window
对象(并具有其值)。
use strict
,在未绑定到任何对象的全局函数和匿名函数中, this
函数的值均为undefined
。
在this
关键字是最容易被误解时:1)我们借用一个使用方法this
,2)我们分配方法,该方法使用this
到一个变量,3)的函数,它使用this
作为一个回调函数传递,和 4) this
是在闭包内部使用 - 内部函数。 (2)
在ECMA 脚本 6 中定义,箭头功能从封闭的(功能或全局)范围采用this
绑定。
function foo() {
// return an arrow function
return (a) => {
// `this` here is lexically inherited from `foo()`
console.log(this.a);
};
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };
var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!
尽管箭头函数提供了使用bind()
的替代方法,但需要注意的是,它们实际上是在禁用传统的this
机制,而希望使用更广泛理解的词法作用域。 (1)
参考文献:
javascript 中的每个函数 执行上下文都有一个范围 上下文, 此 范围由以下参数设置:
无论范围上下文是什么,均由 “this” 引用。
您可以使用func.call
, func.apply
或func.bind
更改设置此 范围 上下文值的值。
默认情况下,什么迷惑大多数初学者,当事件被一个 DOM 元素上引发后回调监听器被调用, 范围方面功能的这个值是的 DOM 元素。
jQuery 使用 jQuery.proxy 可以轻松地进行更改。
这里是一个很好的来源this
中JavaScript
。
这是摘要:
全球这个
在浏览器中,在全局范围内, this
是window
对象
<script type="text/javascript">
console.log(this === window); // true
var foo = "bar";
console.log(this.foo); // "bar"
console.log(window.foo); // "bar"
在使用 repl 的node
, this
是顶级名称空间。您可以将其称为global
。
>this
{ ArrayBuffer: [Function: ArrayBuffer],
Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
...
>global === this
true
在通过脚本执行的node
, this
在全局范围内从一个空对象开始。它与global
\\test.js
console.log(this); \\ {}
console.log(this === global); \\ fasle
发挥这个作用
除了在 DOM 事件处理程序中或在提供thisArg
时(参见下文),在节点和浏览器中都使用this
函数,而该函数未使用new
引用调用全局范围…
<script type="text/javascript">
foo = "bar";
function testThis() {
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
testThis();
console.log(this.foo); //logs "foo"
</script>
如果使用use strict;
,在这种情况下this
将是undefined
<script type="text/javascript">
foo = "bar";
function testThis() {
"use strict";
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
testThis(); //Uncaught TypeError: Cannot set property 'foo' of undefined
</script>
如果使用new
调用函数this
将是一个新的上下文,它将不会引用全局this
。
<script type="text/javascript">
foo = "bar";
function testThis() {
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
new testThis();
console.log(this.foo); //logs "bar"
console.log(new testThis().foo); //logs "foo"
</script>
您创建的函数成为函数对象。它们会自动获得一个特殊的prototype
属性,您可以为其分配值。通过用new
调用函数来创建实例时,您可以访问分配给prototype
属性的值。您可以使用this
访问这些值。
function Thing() {
console.log(this.foo);
}
Thing.prototype.foo = "bar";
var thing = new Thing(); //logs "bar"
console.log(thing.foo); //logs "bar"
在prototype
上分配数组或对象通常是一个错误。如果您希望实例各自具有自己的数组,请在函数(而不是原型)中创建它们。
function Thing() {
this.things = [];
}
var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []
您可以在对象的任何函数中使用this
来引用该对象的其他属性。这与使用new
创建的实例不同。
var obj = {
foo: "bar",
logFoo: function () {
console.log(this.foo);
}
};
obj.logFoo(); //logs "bar"
在 HTML DOM 事件处理程序中, this
始终是对事件附加到的 DOM 元素的引用
function Listener() {
document.getElementById("foo").addEventListener("click",
this.handleClick);
}
Listener.prototype.handleClick = function (event) {
console.log(this); //logs "<div id="foo"></div>"
}
var listener = new Listener();
document.getElementById("foo").click();
除非您bind
上下文
function Listener() {
document.getElementById("foo").addEventListener("click",
this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
console.log(this); //logs Listener {handleClick: function}
}
var listener = new Listener();
document.getElementById("foo").click();
在可以放置 JavaScript 的 HTML 属性内, this
是对该元素的引用。
<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
您可以使用eval
来访问this
。
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
eval("console.log(this.foo)"); //logs "bar"
}
var thing = new Thing();
thing.logFoo();
您可以使用with
添加this
到目前的范围,读取和写入值在this
没有提到this
明确。
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
with (this) {
console.log(foo);
foo = "foo";
}
}
var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
jQuery 在许多地方都this
引用 DOM 元素。
<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
this.click();
});
</script>
丹尼尔,很棒的解释!在事件处理程序的情况下,在this
上下文上下文指针以及this
列表中列出了几个单词。
在两个词, this
在 JavaScript 中指出,与人(或将从其执行上下文)当前函数运行对象和它的始终是只读的,你不能设置也无妨(这种尝试将结束 “左无效手在作业中的讯息。
对于事件处理程序:内联事件处理程序(例如<element onclick="foo">
)会覆盖之前和之前附加的所有其他处理程序,因此请当心,最好不要使用内联事件委托。还要感谢 Zara Alaverdyan,他通过一次持异议的辩论启发了我列举了以下示例:)
el.onclick = foo; // in the foo - obj
el.onclick = function () {this.style.color = '#fff';} // obj
el.onclick = function() {doSomething();} // In the doSomething - Window
el.addEventListener('click',foo,false) // in the foo - obj
el.attachEvent('onclick, function () { // this }') // window, all the compliance to IE :)
<button onclick="this.style.color = '#fff';"> // obj
<button onclick="foo"> // In the foo - window, but you can <button onclick="foo(this)">
可能有关this
内容的最详细,最全面的文章如下:
在 JavaScript 中对 “this” 关键字的温和解释
背后的想法this
是了解函数调用类型对设置显著重视this
值。
在遇到问题时识别this
, 不问自己:
this
是从哪里来的 ?
但不要问自己:
该函数如何调用 ?
对于箭头功能(上下文透明的特殊情况),请问自己:
在定义箭头功能的情况下,
this
值有什么值?
在处理this
问题时, this
心态是正确的,可以使您免于头痛。