The this
object binding is volatile in JavaScript...that is, it doesn't always point to the same object and its binding can change from one line of code to the very next. How you invoke the code that contains the word this
determines what object it will bind to.
Had you cached your this
object reference prior to the setTimeout
like this:
var self = this;
you could then refer to self
in the setTimeout
and it would have worked.
Here's a checklist that you can follow to know what this
will bind
to (your scenario is #3 and you can read more about it here
under the "The "this" problem" section)...
If the code that contains this
is invoked:
As a method or property of an object instance (through an instance variable):
var o = new Object();
// "this" will be bound to the "o" object instance
// while "someProperty" and "someMethod" code executes
o.someProperty = someValue;
o.someMethod();
Via a .call()
, .apply()
, .bind()
or Array.prototype.fn
invocation:
// "this" will be bound to the object suppled as the "thisObjectBinding"
someFunction.call(thisObjectBinding, arg, arg);
someFunction.apply(thisObjectBinding, [arg, arg]);
var newFunc = someFunction.bind(thisObjectBinding, arg, arg);
Note: When a callback function is invoked (i.e. event handler), there is an implicit call to the handler when the event is triggered. In these cases, the object responsible for triggering the event becomes the object bound to this
.
Additionally, several Array.prototype
methods allow for a thisObject
to be passed which will alter the binding for the duration of the method call:
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 ] )
If none of the other scenarios apply, Default binding occurs.
3a. With "use strict"
in effect: this
is undefined
3b. Without "use strict"
in effect: this
binds to the Global object
** NOTE: this
binding can also be affected by using eval()
, but as a general best practice, the use of eval()
should be avoided.
Having said all that, I'm not sure why you need a setTimeout
at all (if I understood your scenario correctly):
var divs = document.querySelectorAll("div:not(#parent)");
divs.forEach(function(div){
div.addEventListener("click", function(){
var self = this;
// get other two divs, not this one
var $otherDivs = $(divs).not(this);
// Fade them out:
$otherDivs.fadeOut(function(){
// JQuery animations accept a callback function to run when the animation is complete
$(self).addClass("clickedDiv");
});
});
});
#parent { width:350px; border: 0; background:inherit;}
div {
width:100px;
height:100px;
background:#ff0;
text-align:center;
float:left;
border:1px solid black;
}
.clickedDiv {
background:#f99;
width:100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent">
<div>I'm DIV 1</div>
<div>I'm DIV 2</div>
<div>I'm DIV 3</div>
</div>
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…