我注意到,对于this
Stack Overflow网站上的JavaScript,关键字是什么以及如何正确(以及错误地)使用关键字似乎没有明确的解释。
我目睹了它的一些非常奇怪的行为,并且未能理解为什么会发生它。
如何this
工作以及何时使用?
this
peter.michaux.ca/articles/javascript-widgets-without-this
我注意到,对于this
Stack Overflow网站上的JavaScript,关键字是什么以及如何正确(以及错误地)使用关键字似乎没有明确的解释。
我目睹了它的一些非常奇怪的行为,并且未能理解为什么会发生它。
如何this
工作以及何时使用?
this
peter.michaux.ca/articles/javascript-widgets-without-this
Answers:
我建议先阅读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()
ThisBinding保持不变;它与调用执行上下文的ThisBinding(第10.4.2(2)(a)节)的值相同。
…如果不是通过直接调用eval()
ThisBinding ,则将其设置为全局对象,就像在初始全局执行上下文中执行一样(第10.4.2(1)节)。
§15.1.2.1.1定义了直接调用eval()
是什么。基本上eval(...)
是直接调用,而(0, eval)(...)
或var indirectEval = eval; indirectEval(...);
则是的间接调用eval()
。见chuckj的回答到(1,EVAL)( '本')与在JavaScript中的eval( '本')?和Dmitry Soshnikov的ECMA-262-5详细信息。第2章严格模式。有关何时可以使用间接eval()
调用的信息。
调用函数时会发生这种情况。如果在某个对象(例如in obj.myMethod()
或等效对象)中调用了函数obj["myMethod"]()
,则ThisBinding设置为该对象(obj
在示例中;第13.2.1节)。在大多数其他情况下,ThisBinding设置为全局对象(第10.4.3节)。
之所以写“在大多数情况下”,是因为有八个ECMAScript 5内置函数可以在参数列表中指定ThisBinding。这些特殊功能带有一个所谓的thisArg
,当调用该功能时(第10.4.3节),它成为ThisBinding。
这些特殊的内置函数是:
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
在执行上下文中调用给定,thisArg
如果提供,则将ThisBinding设置为;否则,转到全局对象。
这些是纯JavaScript的规则。当您开始使用JavaScript库(例如jQuery)时,您可能会发现某些库函数会操纵的值this
。这些JavaScript库的开发人员之所以这样做是因为它倾向于支持最常见的用例,并且该库的用户通常会发现此行为更加方便。当传递引用this
库函数的回调函数时,您应参考文档以获取有关this
调用该函数时值的任何保证。
如果您想知道JavaScript库如何处理的值this
,则该库只是使用接受的内置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中,访问method(
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()
,该函数接受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
operator 创建其实例。在下面,我尝试了使用Object以及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
为this
inside 的值,fun()
并将fun()
传递argsArray
其的元素作为其参数。fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
-设置obj1
为this
inside 的值,fun()
并将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
。它没有将功能分配给事件处理程序(因而没有将其分配为元素的功能方法),而是对事件进行了调用(在全局上下文中有效地对其进行了调用)。<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
,其中箭头函数定义,将箭头功能的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
this
:在这种情况下,调用未设置的值。由于代码不是处于严格模式下,因此值必须始终是一个对象,因此它默认为全局对象。实际上,这就是为什么我认为我们可以直接进行call window.f1()
,所以意味着在调用之前,该意思f1()
已经附加到window
对象上了。我搞错了吗?
window.fn
,它不是。此默认为全局对象,因为在呼叫中使用的函数被定义,其中的不因为没有基准参照,(所以这仍然是由功能如何被调用设置)。如果你明确地把它用window.fn
,那么你设置这给窗口。结果相同,处理方式不同。:-)
this
考虑以下功能:
function foo() {
console.log("bar");
console.log(this);
}
foo(); // calling the function
请注意,我们在正常模式下运行此程序,即未使用严格模式。
在浏览器中运行时,的值this
将记录为window
。这是因为它window
是Web浏览器范围内的全局变量。
如果您在诸如node.js之类的环境中运行同一段代码,this
则将引用您应用程序中的全局变量。
现在,如果我们通过"use strict";
在函数声明的开头添加语句以严格模式运行此命令,则this
在任何一个环境中都将不再引用全局变量。这样做是为了避免在严格模式下造成混淆。this
在这种情况下,只需log undefined
,因为它就是它,所以未定义。
在以下情况下,我们将看到如何操纵的值this
。
有不同的方法可以做到这一点。如果您已经在Javascript中像forEach
和一样调用了本机方法slice
,则应该已经知道该this
情况下的变量是指Object
您在其上调用了该函数的变量(请注意,在javascript中,几乎所有内容都是一个Object
,包括Array
s和Function
s)。以下面的代码为例。
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.logThis;
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
关键字调用该函数将立即初始化Object
type Person
。Object
构造函数设置为Person
。另外,请注意,这typeof awal
只会返回Object
。Object
将分配给的原型Person.prototype
。这意味着Person
原型中的任何方法或属性都可用于的所有实例Person
,包括awal
。Person
现在,该函数本身被调用;this
是对新建对象的引用awal
。很简单,是吗?
请注意,官方ECMAScript规范无处声明此类功能是实际constructor
功能。它们只是正常功能,new
可以在任何功能上使用。只是我们原样使用它们,因此我们仅如此称呼它们。
call
和apply
是的,因为function
s也是Objects
(实际上是Javascript中的第一类变量),所以即使函数也具有本身就是函数的方法。
所有函数都从global继承Function
,其许多方法中的两个是call
和apply
,并且这两个方法均可用于操纵this
调用它们的函数中的value 。
function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);
这是使用的典型示例call
。它基本上采用第一个参数,并this
在函数中设置对的foo
引用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
。它也是所有函数从Function
Java脚本的全局构造函数继承的方法。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
嵌套范围更改了value ,但是我们希望this
从原始范围更改。因此,我们“复制” this
到that
了副本并使用了副本this
。聪明吧?
指数:
this
默认情况下保留什么?new
关键字怎么办?this
使用call
和操作apply
?bind
。this
以解决嵌套范围问题。“这”是关于范围的。每个函数都有自己的作用域,并且由于JS中的所有对象都是对象,所以即使一个函数也可以使用“此”将一些值存储到自身中。OOP 101教导“此”仅适用于对象的实例。因此,每次执行一个函数时,该函数的新“实例”就具有“ this”的新含义。
大多数人在匿名闭包函数中尝试使用“ this”时会感到困惑:
(函数(值){ this.value =值; $('。some-elements')。each(function(elt){ elt.innerHTML = this.value; //哦哦!可能未定义 }); })(2);
所以在这里,在each()中,“ this”不包含您期望它(从
this.value =值;它上面)。因此,要解决此问题(无双关语),开发人员可以:
(函数(值){ var self = this; // 小变化 self.value =值; $('。some-elements')。each(function(elt){ elt.innerHTML = self.value; //!== 2 }); })(2);
试试看; 您将开始喜欢这种编程模式
this
关键字无关的范围。同样,它在不是对象属性的函数中也具有意义。
this
范围不是全部。这完全取决于执行上下文,这与作用域不同。JavaScript具有词法范围(意思是范围由代码的位置确定),但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参数,该参数由以下参数设置:
eval
您可以设置的值此使用func.call
,func.apply
或func.bind
。
默认情况下,令大多数初学者感到困惑的是,在DOM元素上引发事件后调用侦听器时,此,该函数值为DOM元素。
jQuery使用jQuery.proxy可以轻松地进行更改。
this
JavaScript 令人困惑的是它不是函数本身的固有属性,而是函数调用方式的产物。
func.call
,func.bind
等等-苏希尔
this
并没有引用函数的作用域。this
将引用一个特定的对象(或可能undefined
),正如您所说的,可以使用.call()
或对其进行更改.apply()
。函数的作用域(基本上是简化时)是它可以访问的变量,而这完全取决于函数在何处声明且不能更改。
this
范围与ES5及之前的版本(例如,写此答案的时间)之间没有任何关系。在ES2015(又名ES6)中,this
作用域与wrt箭头功能(箭头功能是从其封闭的作用域继承而来)以一种相当最小的方式相关this
,但this
从未引用作用域。
这是this
in的一个好来源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"
在node
使用repl时,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
提供a的情况下(请参阅下一节),在节点和浏览器中都使用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
在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)">
关于如何在JavaScript中解释“ this”关键字存在很多困惑。希望本文能使所有这些东西一劳永逸。还有更多。请仔细阅读整篇文章。请注意,本文篇幅较长。
无论使用哪种上下文,“ this”始终引用Javascript中的“当前对象”。但是,“当前对象”的含义根据上下文而有所不同。所述上下文可以是恰好1 6的以下情况:
下面逐一描述每种情况:
全局上下文(即在所有功能之外):
在所有函数之外(即,在全局上下文中),“当前对象”(因此是“ this”的值)始终是浏览器的 “窗口”对象。
内部直接“无界函数”调用:
在直接的“非绑定函数”调用中,调用该函数调用的对象将成为“当前对象”(并因此成为“ this”的值)。如果在没有显式当前对象的情况下调用函数,则当前对象是“窗口”对象(对于非严格模式)或未定义(对于严格模式)。全局上下文中定义的任何函数(或变量)都会 自动成为“窗口”对象的属性。例如,假设函数在全局上下文中定义为
function UserDefinedFunction(){
alert(this)
}
它成为窗口对象的属性,就像您已将其定义为
window.UserDefinedFunction=function(){
alert(this)
}
在“非严格模式”下,直接通过“ UserDefinedFunction()”调用/调用此函数 会自动将其作为“ window.UserDefinedFunction()”进行调用/调用,从而使“ window”成为 “当前对象”(因此,“ “”在“ UserDefinedFunction ”中)。在“非严格模式”下调用此函数将导致以下情况
UserDefinedFunction() // displays [object Window] as it automatically gets invoked as window.UserDefinedFunction()
在“严格模式”下,直接通过“ UserDefinedFunction()”调用/调用该函数 将“不”自动将其作为“ window.UserDefinedFunction()”调用/调用。因此,“当前对象”(以及“ this”的值)) “ UserDefinedFunction”中的)应为undefined。在“严格模式”下调用此功能将导致以下情况
UserDefinedFunction() // displays undefined
但是,使用window对象显式调用它会导致以下结果
window.UserDefinedFunction() // "always displays [object Window] irrespective of mode."
让我们看另一个例子。请看下面的代码
function UserDefinedFunction()
{
alert(this.a + "," + this.b + "," + this.c + "," + this.d)
}
var o1={
a:1,
b:2,
f:UserDefinedFunction
}
var o2={
c:3,
d:4,
f:UserDefinedFunction
}
o1.f() // Shall display 1,2,undefined,undefined
o2.f() // Shall display undefined,undefined,3,4
在上面的示例中,我们看到当通过o1调用“ UserDefinedFunction”时,“ this”的值为o1,并且显示其属性“ a”和“ b”的值。的值“C”和“d”被示出为未定义为O1没有定义这些属性
类似地,当通过o2调用“ UserDefinedFunction”时, “ this”取值为o2并显示其属性“ c”和“ d”的值。与o2一样,“ a”和“ b”的值显示为未定义没有定义这些属性。
内部间接“非绑定函数”通过functionName.call和functionName.apply调用:
当一个“非绑定函数”是通过称为 functionName.call或functionName.apply中,“当前对象”(以及因此的值“这种”)被设置为的值 “这种”传递给参数(第一参数)呼叫/应用。以下代码演示了相同的内容。
function UserDefinedFunction()
{
alert(this.a + "," + this.b + "," + this.c + "," + this.d)
}
var o1={
a:1,
b:2,
f:UserDefinedFunction
}
var o2={
c:3,
d:4,
f:UserDefinedFunction
}
UserDefinedFunction.call(o1) // Shall display 1,2,undefined,undefined
UserDefinedFunction.apply(o1) // Shall display 1,2,undefined,undefined
UserDefinedFunction.call(o2) // Shall display undefined,undefined,3,4
UserDefinedFunction.apply(o2) // Shall display undefined,undefined,3,4
o1.f.call(o2) // Shall display undefined,undefined,3,4
o1.f.apply(o2) // Shall display undefined,undefined,3,4
o2.f.call(o1) // Shall display 1,2,undefined,undefined
o2.f.apply(o1) // Shall display 1,2,undefined,undefined
上面的代码清楚地表明,可以通过call / apply更改任何“ NON Bound Function”的“ this”值。另外,如果未将 “ this”参数显式传递给call / apply,则在“非严格”模式下,“当前对象”(因此,“ this”的值)将设置为“窗口”,在严格模式下将设置为“未定义”。
在“绑定函数”内部调用(即,已通过调用functionName.bind绑定的函数):
绑定函数是其“ this”值已固定的函数。以下代码演示了在绑定函数的情况下“ this”如何工作
function UserDefinedFunction()
{
alert(this.a + "," + this.b + "," + this.c + "," + this.d)
}
var o1={
a:1,
b:2,
f:UserDefinedFunction,
bf:null
}
var o2={
c:3,
d:4,
f:UserDefinedFunction,
bf:null
}
var bound1=UserDefinedFunction.bind(o1); // permanantly fixes "this" value of function "bound1" to Object o1
bound1() // Shall display 1,2,undefined,undefined
var bound2=UserDefinedFunction.bind(o2); // permanantly fixes "this" value of function "bound2" to Object o2
bound2() // Shall display undefined,undefined,3,4
var bound3=o1.f.bind(o2); // permanantly fixes "this" value of function "bound3" to Object o2
bound3() // Shall display undefined,undefined,3,4
var bound4=o2.f.bind(o1); // permanantly fixes "this" value of function "bound4" to Object o1
bound4() // Shall display 1,2,undefined,undefined
o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes "this" value of function "o1.bf" to Object o2
o1.bf() // Shall display undefined,undefined,3,4
o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes "this" value of function "o2.bf" to Object o1
o2.bf() // Shall display 1,2,undefined,undefined
bound1.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
bound1.apply(o2) // Shall still display 1,2,undefined,undefined. "apply" cannot alter the value of "this" for bound function
o2.bf.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of "this" for bound function
如以上代码中所给,任何“绑定函数”的“ this”值都不能通过call / apply进行更改。另外,如果 未明确传递“ this”参数进行绑定,则在“非严格”模式下将“当前对象” (因此将“ this”的值)设置为“ window”,在严格模式下将设置为“ undefined”。还有一件事。绑定已经绑定的函数不会更改“ this”的值。它仍然设置为第一个绑定函数设置的值。
通过“ new”创建对象时:
在构造函数中,“当前对象”(因此是“ this”的值 )引用当前通过“ new”创建的对象,而与函数的绑定状态无关。但是,如果构造函数是绑定函数,则应使用为绑定函数设置的预定义参数集来调用它。
内部内联DOM事件处理程序:
请查看以下HTML代码段
<button onclick='this.style.color=white'>Hello World</button>
<div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div>
上面示例中的“ this”分别表示“ button”元素和“ div”元素。
在第一个示例中,单击按钮时,其字体颜色应设置为白色。
在第二个示例中,当单击“ div”元素时,它将使用其第二个参数引用被单击的div元素来调用OnDivClick函数。但是, OnDivClick中的“ this”值不应引用所单击的div 元素。应分别在非严格模式和严格模式下将其设置为“窗口对象”或 “未定义”(如果OnDivClick是未绑定函数),或者设置为预定义的Bound值(如果OnDivClick是绑定函数)
以下总结了整篇文章
在全局上下文中,“ this”始终引用“ window”对象
每当调用函数时,都会在对象(“当前对象”)的上下文中调用该函数。如果当前对象没有明确规定,在当前的对象 是“窗口对象”在非严格模式和“未定义”在默认情况下,严格模式。
Non Bound函数中的“ this”的值是对调用该函数的对象的引用(“当前对象”)
Non Bound函数中的“ this”值可以通过调用和应用函数的方法来覆盖 。
对于绑定函数,“ this”的值是固定的,不能被该函数的调用和应用方法覆盖。
绑定和已经绑定的函数不会更改“ this”的值。它仍然设置为第一个绑定函数设置的值。
构造函数中“ this”的值是正在创建和初始化的对象
内联DOM事件处理程序中的“ this”的值引用为其提供事件处理程序的元素。
关于this
以下内容的最详细,最全面的文章可能是:
背后的想法this
是要了解函数调用类型对于设置this
值具有重要意义。
在确定问题时this
,不要问自己:
从哪里
this
带走的?
但不要问自己:
该函数如何调用?
对于箭头功能(上下文透明的特殊情况),请问自己:
this
在定义箭头功能的地方有什么值?
这种心态在与人打交道时是正确的this
,它将使您免于头痛。
this
关键字?
这是我见过的最好的解释:了解JavaScript的这种清晰
在此引用总是指(并保持的值)的物体的单一对象,而且它通常是一个函数或方法内使用,虽然它可以在函数外,在全球范围内使用。请注意,当我们使用严格模式时,它在全局函数和未绑定到任何对象的匿名函数中都具有未定义的值。
有四个场景中这可能会造成混淆:
他提供了代码示例,解释和解决方案,我认为这非常有帮助。
用伪古典术语来说,许多课程讲授“ this”关键字的方式是作为由类或对象构造函数实例化的对象。每次从类构造一个新对象时,请想象在幕后创建并返回“ this”对象的本地实例。我记得它的教导是这样的:
function Car(make, model, year) {
var this = {}; // under the hood, so to speak
this.make = make;
this.model = model;
this.year = year;
return this; // under the hood
}
var mycar = new Car('Eagle', 'Talon TSi', 1993);
// ========= under the hood
var this = {};
this.make = 'Eagle';
this.model = 'Talon TSi';
this.year = 1993;
return this;
this
是JavaScript中一个被误解的概念之一,因为它的行为因地而异。简单来说,this
是指我们当前正在执行的函数的“所有者”。
this
帮助获取我们正在使用的当前对象(又名执行上下文)。如果你了解这是越来越当前执行的函数对象,你可以很容易地了解当前this
IS
var val = "window.val"
var obj = {
val: "obj.val",
innerMethod: function () {
var val = "obj.val.inner",
func = function () {
var self = this;
return self.val;
};
return func;
},
outerMethod: function(){
return this.val;
}
};
//This actually gets executed inside window object
console.log(obj.innerMethod()()); //returns window.val
//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val
console.log(obj.outerMethod()); //returns obj.val
在上方,我们创建了3个具有相同名称“ val”的变量。一个在全局上下文中,一个在obj内部,另一个在obj的innerMethod内部。JavaScript通过将范围链从本地扩展到全局来解析特定上下文中的标识符。
很少this
可以区分的地方
var status = 1;
var helper = {
status : 2,
getStatus: function () {
return this.status;
}
};
var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2
var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1
执行line1时,JavaScript会为函数调用建立执行上下文(EC),将其设置this
为最后一个“”之前的内容所引用的对象。。因此,在最后一行中,您可以了解它a()
是在全局上下文中执行的window
。
this
可用于引用正在创建的对象
function Person(name){
this.personName = name;
this.sayHello = function(){
return "Hello " + this.personName;
}
}
var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott
var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined
Person()
执行new时,将创建一个全新的对象。Person
被调用,它this
被设置为引用该新对象。
function testFunc() {
this.name = "Name";
this.myCustomAttribute = "Custom Attribute";
return this;
}
var whatIsThis = testFunc();
console.log(whatIsThis); //window
var whatIsThis2 = new testFunc();
console.log(whatIsThis2); //testFunc() / object
console.log(window.myCustomAttribute); //Custom Attribute
如果我们错过了new
关键字,则whatIsThis
指向它可以找到的最全局的上下文(window
)
如果事件处理程序为内联,则this
引用全局对象
<script type="application/javascript">
function click_handler() {
alert(this); // alerts the window object
}
</script>
<button id='thebutton' onclick='click_handler()'>Click me!</button>
通过JavaScript添加事件处理程序时,this
是指生成事件的DOM元素。
.apply()
.call()
和操作上下文.bind()
var that = this
JavaScript代表什么有关此的一点信息关键字的
让我们this
在全局范围内将关键字记录到控制台中,无需任何其他代码,但
console.log(this)
在Client / Browser中, this
关键字是一个全局对象,它是window
console.log(this === window) // true
和
在Server / Node / Javascript中,runtime this
关键字也是一个全局对象,它是module.exports
console.log(this === module.exports) // true
console.log(this === exports) // true
记住exports
只是对module.exports
像这样用于Scope
<script type="text/javascript" language="javascript">
$('#tbleName tbody tr').each(function{
var txt='';
txt += $(this).find("td").eq(0).text();
\\same as above but synatx different
var txt1='';
txt1+=$('#tbleName tbody tr').eq(0).text();
alert(txt1)
});
</script>
上例中txt1和txt的值相同$(this)= $('#tbleName tbody tr')是相同的
我有不同的看法 this
对其他答案,希望对您有所帮助。
查看JavaScript的一种方法是看到只有一种方法可以调用函数1。它是
functionObject.call(objectForThis, arg0, arg1, arg2, ...);
始终提供一些值objectForThis
。
其他一切都是语法糖 functionObject.call
因此,其他所有内容都可以通过翻译成来描述functionObject.call
。
如果只调用一个函数,则this
是“全局对象”,在浏览器中是窗口
function foo() {
console.log(this);
}
foo(); // this is the window object
换一种说法,
foo();
被有效地翻译成
foo.call(window);
请注意,如果您使用严格模式,this
则将undefined
'use strict';
function foo() {
console.log(this);
}
foo(); // this is the window object
意思是
换一种说法,
foo();
被有效地翻译成
foo.call(undefined);
在JavaScript中有像运营商+
和-
和*
。还有一个点运算符是.
在.
与右侧的功能和在左边的对象使用时,操作者实际上意味着“通过对象作为this
到功能。
例
const bar = {
name: 'bar',
foo() {
console.log(this);
},
};
bar.foo(); // this is bar
换句话说,bar.foo()
翻译成const temp = bar.foo; temp.call(bar);
请注意,函数的创建方式无关紧要(主要是...)。所有这些都会产生相同的结果
const bar = {
name: 'bar',
fn1() { console.log(this); },
fn2: function() { console.log(this); },
fn3: otherFunction,
};
function otherFunction() { console.log(this) };
bar.fn1(); // this is bar
bar.fn2(); // this is bar
bar.fn3(); // this is bar
同样,这些都是语法糖
{ const temp = bar.fn1; temp.call(bar); }
{ const temp = bar.fn2; temp.call(bar); }
{ const temp = bar.fn3; temp.call(bar); }
原型链是另一个难题。当您使用a.b
JavaScript时,首先会查找a
属性直接为所引用的对象b
。如果b
未在对象上找到JavaScript,则JavaScript将在对象的原型中查找find b
。
有多种定义对象原型的方法,2019年最常见的是class
关键字。出于目的,this
这无关紧要。重要的是,因为它看起来在对象a
的属性b
,如果它发现性能b
上的对象或它的原型链是否b
结束是一个函数,则相同的规则,上述申请。函数b
引用将使用call
方法调用,并a
作为objectForThis 传递,如答案顶部所示。
现在。假设我们创建了一个this
在调用另一个函数之前已显式设置的函数,然后使用.
(点)运算符对其进行调用
function foo() {
console.log(this);
}
function bar() {
const objectForThis = {name: 'moo'}
foo.call(objectForThis); // explicitly passing objectForThis
}
const obj = {
bar,
};
obj.bar();
经过翻译使用call
,obj.bar()
成为const temp = obj.bar; temp.call(obj);
。当我们进入bar
函数时,我们会调用,foo
但是我们为objectForThis显式传递了另一个对象,因此当我们到达foo时this
就是该内部对象。
这bind
和=>
功能都是有效的。它们是语法更多的糖。他们有效地构建了一个新的不可见函数,就像bar
上面的函数一样,它this
在调用指定的函数之前先进行了显式设置。如果bind this
设置为您要传递的值bind
。
function foo() {
console.log(this);
}
const bar = foo.bind({name: 'moo'});
// bind created a new invisible function that calls foo with the bound object.
bar();
// the objectForThis we are passing to bar here is ignored because
// the invisible function that bind created will call foo with with
// the object we bound above
bar.call({name: 'other'});
请注意,如果functionObject.bind
不存在,我们可以像这样制作自己的
function bind(fn, objectForThis) {
return function(...args) {
return fn.call(objectForthis, ...args);
};
}
然后我们可以这样称呼它
function foo() {
console.log(this);
}
const bar = bind(foo, {name:'abc'});
箭头功能,=>
运算符是绑定的语法糖
const a = () => {console.log(this)};
是相同的
const tempFn = function() {console.log(this)};
const a = tempFn.bind(this);
就像一样bind
,会创建一个新的不可见函数,该函数用的绑定值调用给定函数,objectForThis
但与bind
要绑定的对象不同的是隐式的。使用运算符this
时会发生任何事情=>
。
所以,就像上面的规则
const a = () => { console.log(this); } // this is the global object
'use strict';
const a = () => { console.log(this); } // this is undefined
function foo() {
return () => { console.log(this); }
}
const obj = {
foo,
};
const b = obj.foo();
b();
obj.foo()
转换为const temp = obj.foo; temp.call(obj);
表示内部的箭头运算符foo
将绑定obj
到新的不可见函数并返回分配给的新不可见函数b
。b()
将像往常一样工作b.call(window)
或b.call(undefined)
调用foo
创建的新的不可见函数。该不可见函数将忽略this
传递给它的内容,并将其obj
作为objectForThis` 传递给arrow函数。
上面的代码转换为
function foo() {
function tempFn() {
console.log(this);
}
return tempFn.bind(this);
}
const obj = {
foo,
};
const b = obj.foo();
b.call(window or undefined if strict mode);
1apply
是类似于call
functionName.apply(objectForThis, arrayOfArgs);
但从ES6概念上讲,您甚至可以将其转换为
functionName.call(objectForThis, ...arrayOfArgs);
this
Javascript:this
取决于函数的调用方式(在何处创建)!this
由点左侧的对象确定。(window
在全球范围内)this
引用在其上调用事件的DOM元素。new
关键字调用in函数时,的值this
引用新创建的对象this
与功能:call
,apply
,bind
let object = {
prop1: function () {console.log(this);}
}
object.prop1(); // object is left of the dot, thus this is object
const myFunction = object.prop1 // We store the function in the variable myFunction
myFunction(); // Here we are in the global space
// myFunction is a property on the global object
// Therefore it logs the window object
document.querySelector('.foo').addEventListener('click', function () {
console.log(this); // This refers to the DOM element the eventListener was invoked from
})
document.querySelector('.foo').addEventListener('click', () => {
console.log(this); // Tip, es6 arrow function don't have their own binding to the this v
}) // Therefore this will log the global object
.foo:hover {
color: red;
cursor: pointer;
}
<div class="foo">click me</div>
function Person (name) {
this.name = name;
}
const me = new Person('Willem');
// When using the new keyword the this in the constructor function will refer to the newly created object
console.log(me.name);
// Therefore, the name property was placed on the object created with new keyword.
要正确理解“此”,必须了解上下文,范围以及它们之间的区别。
范围:在javascript中,范围与变量的可见性有关,范围通过使用函数来实现。(了解有关范围的更多信息)
上下文:上下文与对象有关。它是指功能所属的对象。当您使用JavaScript“ this”关键字时,它指向函数所属的对象。例如,在函数内部,当您说:“ this.accoutNumber”时,您所指的是属性“ accoutNumber”,该属性属于该函数所属的对象。
如果对象“ myObj”具有名为“ getMyName”的方法,则当在“ getMyName”内部使用JavaScript关键字“ this”时,它称为“ myObj”。如果函数“ getMyName”是在全局范围内执行的,则“ this”是指窗口对象(严格模式下除外)。
现在让我们看一些例子:
<script>
console.log('What is this: '+this);
console.log(this);
</script>
根据输出,您在窗口对象的上下文内部,也可以看到窗口原型引用该对象。
现在让我们尝试一个函数内部:
<script>
function myFunc(){
console.log('What is this: '+this);
console.log(this);
}
myFunc();
</script>
输出:
输出是相同的,因为我们在全局范围中记录了“ this”变量,而在功能范围中记录了该变量,所以我们没有更改上下文。在这两种情况下,上下文都是相同的,都与寡妇对象有关。
现在让我们创建自己的对象。在javascript中,您可以通过多种方式创建对象。
<script>
var firstName = "Nora";
var lastName = "Zaman";
var myObj = {
firstName:"Lord",
lastName:'Baron',
printNameGetContext:function(){
console.log(firstName + " "+lastName);
console.log(this.firstName +" "+this.lastName);
return this;
}
}
var context = myObj.printNameGetContext();
console.log(context);
</script>
因此,从上面的示例中,我们发现'this'关键字是指与myObj相关的新上下文,并且myObject也具有指向Object的原型链。
让我们再举一个例子:
<body>
<button class="btn">Click Me</button>
<script>
function printMe(){
//Terminal2: this function declared inside window context so this function belongs to the window object.
console.log(this);
}
document.querySelector('.btn').addEventListener('click', function(){
//Terminal1: button context, this callback function belongs to DOM element
console.log(this);
printMe();
})
</script>
</body>
如果您无法理解上述示例,请尝试使用我们自己的回调;
<script>
var myObj = {
firstName:"Lord",
lastName:'Baron',
printName:function(callback1, callback2){
//Attaching callback1 with this myObj context
this.callback1 = callback1;
this.callback1(this.firstName +" "+this.lastName)
//We did not attached callback2 with myObj so, it's reamin with window context by default
callback2();
/*
//test bellow codes
this.callback2 = callback2;
this.callback2();
*/
}
}
var callback2 = function (){
console.log(this);
}
myObj.printName(function(data){
console.log(data);
console.log(this);
}, callback2);
</script>
现在让我们了解一下范围,自我,IIFE和这是如何表现的
var color = 'red'; // property of window
var obj = {
color:'blue', // property of window
printColor: function(){ // property of obj, attached with obj
var self = this;
console.log('In printColor -- this.color: '+this.color);
console.log('In printColor -- self.color: '+self.color);
(function(){ // decleard inside of printColor but not property of object, it will executed on window context.
console.log(this)
console.log('In IIFE -- this.color: '+this.color);
console.log('In IIFE -- self.color: '+self.color);
})();
function nestedFunc(){// decleard inside of printColor but not property of object, it will executed on window context.
console.log('nested fun -- this.color: '+this.color);
console.log('nested fun -- self.color: '+self.color);
}
nestedFunc(); // executed on window context
return nestedFunc;
}
};
obj.printColor()(); // returned function executed on window context
</script>
简单答案:
“ this”关键字始终取决于调用的上下文。它们在下面提到。
使用新关键字调用功能
如果使用NEW关键字调用该函数,则THIS将绑定到新创建的对象。
function Car(){
this.name="BMW";
}
const myCar=new Car();
myCar.name; // output "BMW"
在上面,这将绑定到“ myCar”对象
使用呼叫和应用方法明确调用功能。
在这种情况下,THIS将绑定到显式传递给函数的对象。
var obj1={"name":"bond"};
function printMessage(msg){
return msg+" "+this.name;
}
const message=printMessage.call(obj1,"my name is ");
console.log(message); //HERE THIS WILL BE BOUND TO obj1 WHICH WE PASSED EXPLICITLY. SAME FOR APPLY METHOD ALSO.
如果隐式调用了功能,则将其绑定到该对象
var obj1={
"name":"bond",
getName: function () {
return this.name;
}
};
const newname=obj1.getName();
console.log(newname); //HERE THIS WILL BE BOUND TO obj1(WHITCHEVER OBJECT IS MENTIONED BEFORE THE DOT THIS WILL BE BOUND TO THAT)
在没有任何上下文的情况下调用功能时,它将被绑定到全局对象中
const util = {
name: 'Utility',
getName: function () {
return this.name;
};
const getName=util.getName;
const newName=getName();
console.log(newName); // IF THIS EXECUTED IN BROWSER THIS WILL BE BOUND TO WINDOW OBJECT. IF THIS EXECUTED IN SERVER THIS WILL BE BOUND TO GLOBAL OBJECT
在严格模式下,这将是不确定的
function setName(name){
"use strict"
return this.name;
}
setName(); //WILL BE ERROR SAYING name IS UNDEFINED.