The this in the anonymous callback function points to

an anonymous callback function

is passed in the usual use of setTimeout addEventListener .

such as:

1.
window.setTimeout(function() {
    console.log(this)
}, 1000) 


2.
var el = document.getElementById("wrapper")
el.addEventListener("click", function() {
    console.log(this)
}, false)

in case 1, this points to the caller-> window object of the setTimeout function
, while in case 2, this also points to the caller-> wrapper of the addEventListener function

.

but I myself am similar to window.setTimeout , which creates an object

var a = {
    b: "b in a",
    c: function (callback) {
        callback()
    }
}

//ac
a.c(function() {
    //thisa"b in a"thiswindow
    console.log(this.b) 
})

I thought it would be similar to window.setTimeout el.addEventListener , where this points to the object before . (dot).

then I changed the object a

var a = {
    b: "b in a",
    c: function (callback) {
        callback.bind(this)()
    }
}

this is the time when this points to a.

then here comes the problem:
1. Like this use of anonymous function passing parameters , why is it that using my own defined object is not the same as the api provided by the browser? How should the direction of this type of this be better understood ?
2. Is it true that the internal implementation of system api, such as setTimeout and addEventListener helps us to give this bind to the object calling this method, such as callback.bind (window) and addEventListener in setTimeout ? callback.bind (el) ?

are there any great gods who can answer this question? thank you very much.

Mar.02,2021

you can think of this as a hidden parameter of function, which is equivalent to

.
function(_this, otherArgs){

}

in fact, almost all languages are handled in the same way. So when this is wrong, you can explicitly pass this parameter with bind.

check whether a function is bound to this. This parameter can be used in the following method:

// ES5
function isBindable(func) {
  return func.hasOwnProperty('prototype');
}

// ES6
const isBindable = func => func.hasOwnProperty('prototype');

event monitoring may have done special handling there. After all, JS is a poorly designed language (ha)


MDN bind


the this of anonymous functions all point to window by default. It is a special case that this points to the element itself in a function that listens for element events.


priority of this pointing

  1. new Foo () bind a new object
  2. bind/call/apply bind the specified object
  3. binding context

    var a = {
        b: function () {
            //this -> a
        }
    }
  4. default global
var a = {
    b: 'b in a',
    c: function c2(callback) {
        callback()
    }
}

//ac
a.c(function c1() {
    //c1this1,2c23
    console.log(this.b) 
})

then the code of the landlord, I named it in order to describe it.

< H2 > instructions for supplementing addEventListener < / H2 >

the following is a polyfill code
provided for browser compatibility. This code, combined with the above rules, clearly illustrates this

of addEventListener .
(function() {
  if (!Event.prototype.preventDefault) {
    Event.prototype.preventDefault=function() {
      this.returnValue=false;
    };
  }
  if (!Event.prototype.stopPropagation) {
    Event.prototype.stopPropagation=function() {
      this.cancelBubble=true;
    };
  }
  if (!Element.prototype.addEventListener) {
    var eventListeners=[];
    
    var addEventListener=function(type,listener /*, useCapture (will be ignored) */) {
      var self=this;
      var wrapper=function(e) {
        e.target=e.srcElement;
        e.currentTarget=self;
        if (typeof listener.handleEvent != 'undefined') {
          listener.handleEvent(e);
        } else {
          listener.call(self,e);
        }
      };
      if (type=="DOMContentLoaded") {
        var wrapper2=function(e) {
          if (document.readyState=="complete") {
            wrapper(e);
          }
        };
        document.attachEvent("onreadystatechange",wrapper2);
        eventListeners.push({object:this,type:type,listener:listener,wrapper:wrapper2});
        
        if (document.readyState=="complete") {
          var e=new Event();
          e.srcElement=window;
          wrapper2(e);
        }
      } else {
        this.attachEvent("on"+type,wrapper);
        eventListeners.push({object:this,type:type,listener:listener,wrapper:wrapper});
      }
    };
    var removeEventListener=function(type,listener /*, useCapture (will be ignored) */) {
      var counter=0;
      while (counter<eventListeners.length) {
        var eventListener=eventListeners[counter];
        if (eventListener.object==this && eventListener.type==type && eventListener.listener==listener) {
          if (type=="DOMContentLoaded") {
            this.detachEvent("onreadystatechange",eventListener.wrapper);
          } else {
            this.detachEvent("on"+type,eventListener.wrapper);
          }
          eventListeners.splice(counter, 1);
          break;
        }
        PPcounter;
      }
    };
    Element.prototype.addEventListener=addEventListener;
    Element.prototype.removeEventListener=removeEventListener;
    if (HTMLDocument) {
      HTMLDocument.prototype.addEventListener=addEventListener;
      HTMLDocument.prototype.removeEventListener=removeEventListener;
    }
    if (Window) {
      Window.prototype.addEventListener=addEventListener;
      Window.prototype.removeEventListener=removeEventListener;
    }
  }
})()

addEventListener polyfill link

Menu