我希望找到一个“this”关键字的明确解释,以及如何正确使用它。
它的行为似乎很奇怪,我不完全明白为什么。
这是如何工作的,何时使用?
我希望找到一个“this”关键字的明确解释,以及如何正确使用它。
它的行为似乎很奇怪,我不完全明白为什么。
这是如何工作的,何时使用?
当前回答
这是我见过的最好的解释:清晰地理解JavaScripts
此引用总是指(并保持)object-一个单独的对象,通常用于函数或方法,尽管它可以在全局范围请注意,当我们使用strict模式时在全局函数和匿名函数中未定义绑定到任何对象。
有四种情况可能会令人困惑:
当我们传递一个方法(使用此方法)作为参数用作回调函数时。当我们使用内部函数(闭包)时。需要注意的是,闭包不能通过使用this关键字访问外部函数的this变量,因为this变量只能由函数本身访问,而不能由内部函数访问。当依赖于此的方法被分配给跨上下文的变量时,在这种情况下,它引用了另一个对象,而不是最初预期的对象。与bind、apply和call方法一起使用时。
他给出了代码示例、解释和解决方案,我认为这很有帮助。
其他回答
与其他语言相比,this关键字在JavaScript中的行为有所不同。在面向对象语言中,this关键字指的是类的当前实例。在JavaScript中,这个值由函数的调用上下文(context.function())及其调用位置决定。
1.在全局上下文中使用时
当您在全局上下文中使用它时,它将绑定到全局对象(浏览器中的窗口)
document.write(this); //[object Window]
当您在全局上下文中定义的函数中使用此函数时,它仍然绑定到全局对象,因为该函数实际上是全局上下文的方法。
function f1()
{
return this;
}
document.write(f1()); //[object Window]
f1以上是全局对象的方法。因此,我们也可以在window对象上调用它,如下所示:
function f()
{
return this;
}
document.write(window.f()); //[object Window]
2.在对象方法内部使用时
当您在对象方法中使用此关键字时,它将绑定到“立即”封闭对象。
var obj = {
name: "obj",
f: function () {
return this + ":" + this.name;
}
};
document.write(obj.f()); //[object Object]:obj
上面我把单词immediate用双引号括起来。这是为了指出,如果您将对象嵌套在另一个对象中,那么这将绑定到直接父对象。
var obj = {
name: "obj1",
nestedobj: {
name:"nestedobj",
f: function () {
return this + ":" + this.name;
}
}
}
document.write(obj.nestedobj.f()); //[object Object]:nestedobj
即使您将函数作为方法显式添加到对象中,它仍然遵循上述规则,即这仍然指向直接父对象。
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.调用无上下文函数时
当您使用这个在没有任何上下文的情况下调用的内部函数(即,不在任何对象上)时,它将绑定到全局对象(浏览器中的窗口)(即使函数是在对象内部定义的)。
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
使用函数尝试所有功能
我们也可以用函数来尝试以上几点。然而,存在一些差异。
上面我们使用对象文字表示法向对象添加了成员。我们可以通过使用这个向函数添加成员。以指定它们。对象文字表示法创建了一个我们可以立即使用的对象实例。对于函数,我们可能需要首先使用新运算符创建其实例。同样,在对象文字方法中,我们可以使用点运算符将成员显式添加到已定义的对象中。这将仅添加到特定实例。然而,我已经向函数原型添加了变量,以便它在函数的所有实例中得到反映。
下面,我尝试了我们使用Object和上面所做的所有事情,但首先创建了函数,而不是直接编写对象。
/*********************************************************************
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关键字调用时),此内部函数体指向正在构造的新对象。
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.在原型链上定义的函数内部使用时
如果该方法位于对象的原型链上,则此类方法中的这个引用该方法所调用的对象,就像该方法是在对象上定义的一样。
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()内部的值,并调用fun(()传递argsArray元素作为其参数。fun.call(obj1[,arg1[,arg2[,arg3[,…]]])-将obj1设置为fun()内部的值,并调用fun(,传递arg1,arg2,arg3,…)。。。作为其论点。fun.bind(obj1[,arg1[,arg2[,arg3[,…]]])-返回对函数fun的引用,此函数内部fun绑定到obj1,fun的参数绑定到指定的参数arg1,arg2,arg3,。。。。到目前为止,apply、call和bind之间的区别肯定已经很明显了。apply允许将参数指定为类似数组的对象,即具有数字长度属性和相应的非负整数财产的对象。而调用允许直接指定函数的参数。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.此内部事件处理程序
当您将函数直接分配给元素的事件处理程序时,直接在事件处理函数内部使用该函数将引用相应的元素。这种直接函数分配可以使用addeventListener方法或通过传统的事件注册方法(如onclick)完成。类似地,当您在元素的事件属性(如<button onclick=“…this…”>)中直接使用它时,它引用的是元素。但是,通过在事件处理函数或事件属性内调用的其他函数间接地使用该函数将解析为全局对象窗口。当我们使用Microsoft的event Registration模型方法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.这在ES6箭头函数中
在箭头函数中,它的行为类似于公共变量:它将从其词法范围继承。函数的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
这里有一个很好的JavaScript源代码。
以下是总结:
全局this在浏览器中,在全局范围内,这是windowobject<script type=“text/javascript”>console.log(此==窗口);//真的var foo=“bar”;console.log(this.foo);//“条形图”console.log(window.foo);//“条形图”在使用repl的节点中,这是顶级命名空间。您可以将其称为全局。>这个{ArrayBuffer:[Function:ArrayBuffer],Int8Array:{[Function:Int8Array]BYTES_PER_ELEMENT:1},Uint8Array:{[Function:Uint8Array]BYTES_PER_ELEMENT:1},...>全局==此真的在从脚本执行的节点中,全局范围中的这个对象以空对象开始。它与全球不同\\测试.jsconsole.log(此);\\{}console.log(this==全局);\\时尚函数this
除了在DOM事件处理程序的情况下,或者当提供了thisArg时(请参见下文),在节点和浏览器中都会在不使用新引用调用全局范围的函数中使用此函数…
<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;,在这种情况下,这将是未定义的
<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。
<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>
原型
您创建的函数将成为函数对象。它们会自动获得一个特殊的原型属性,这是您可以为其赋值的属性。当您使用new调用函数来创建实例时,您可以访问分配给原型属性的值。您可以使用此访问这些值。
function Thing() {
console.log(this.foo);
}
Thing.prototype.foo = "bar";
var thing = new Thing(); //logs "bar"
console.log(thing.foo); //logs "bar"
在原型上分配数组或对象通常是错误的。如果希望每个实例都有自己的数组,请在函数中创建它们,而不是在原型中创建它们。
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 []
反对这个
您可以在对象的任何函数中使用它来引用该对象的其他财产。这与使用new创建的实例不同。
var obj = {
foo: "bar",
logFoo: function () {
console.log(this.foo);
}
};
obj.logFoo(); //logs "bar"
DOM事件this
在HTML DOM事件处理程序中,这始终是对事件附加到的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();
除非您绑定上下文
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();
HTML此
在可以放入JavaScript的HTML属性中,这是对元素的引用。
<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
评估此
您可以使用eval访问此。
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
eval("console.log(this.foo)"); //logs "bar"
}
var thing = new Thing();
thing.logFoo();
用这个
您可以使用with将其添加到当前范围中,以读取和写入其值,而无需显式引用它。
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
jQuery在很多地方都会引用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>
丹尼尔,太棒了!在事件处理程序的情况下,这里有几个单词,以及这个执行上下文指针的良好列表。
换句话说,JavaScript中的这一点指向运行当前函数的对象(或其执行上下文),并且它始终是只读的,无论如何都不能设置它(这样的尝试将以“赋值中的左侧无效”消息结束)。
对于事件处理程序:内联事件处理程序,例如<elementonclick=“foo”>,会覆盖之前附加的任何其他处理程序,因此要小心,最好不要进行内联事件委派。感谢Zara Alaverdyan,他通过一场不同意见的辩论激发了我的灵感:)
el.onclick=foo;//在foo-obj中el.onclick=函数(){this.style.color=“#fff”;}//objel.onclick=function(){doSomething();}//在doSometing中-窗el.addEventListener('click',foo,false)//在foo-obj中el.attachEvent('包含,函数(){//this}')//窗口,所有符合IE:)<button onclick=“this.style.color='#fff';”>//obj<button onclick=“foo”>//在foo窗口中,但您可以<buttononclick=“foo(this)”>
JavaScript中的this总是指正在执行的函数的“所有者”。
如果未定义显式所有者,则引用最顶层的所有者窗口对象。
所以如果我做了
function someKindOfFunction() {
this.style = 'foo';
}
element.onclick=someKindOfFunction;
这将引用元素对象。但是要小心,很多人都会犯这个错误。
<element onclick=“someKindOfFunction()”>
在后一种情况下,您只是引用函数,而不是将其交给元素。因此,这将引用窗口对象。
JavaScript中的“this”这是执行上下文的财产之一。
每次执行函数时都会创建此属性,而不是在此之前。它的价值不是静态的,而是取决于它的使用方式。获取一个指向其所在函数所有者的值习惯于
“this”关键字有不同的使用方式,下面是它的示例(方法、正则函数、箭头函数、事件监听器、显式函数绑定)。
1.方法内部。
this==(对调用方法的对象)。
在上面的示例中,方法“fullName()”由对象“person”调用,因此方法“fullName()”中的值将等于对象“person”。
2.函数内部。
i) 函数声明/表达式
在松散模式下,此==窗口(对象)
在严格模式下,this==未定义
注意:使用函数声明或函数表达式方法定义函数时,此属性的工作原理相同。
ii)箭头功能:
箭头函数没有自己的此属性,它们将此属性的值作为其周围的函数。如果周围函数不存在,即如果它们是在全局级别定义的,则此==窗口(对象)
3.事件侦听器this==附加处理程序的对象。单击事件绑定到Document对象
在上面的示例中,由于单击处理程序附加到“document”对象,因此它将等于“document“对象
4.显式函数绑定(调用、应用、绑定)
call()和apply()方法是预定义的JavaScript方法。
它们都可以用来调用另一个对象作为参数的对象方法。
在上面的示例中,“printFullDetails()”中的这一点通过传递作为调用方法的第一个参数显式设置为personObj1和personObj2。
您可以在这里探索有关调用、应用和绑定方法的更多信息。