本文轉自知乎貘吃饃香的回答
提問:剛入門不久,能力有限,這個問題我描述起來有點困難,只有勞煩各位大神細看了
我之前一直以為js底層存在類似下面這樣的代碼:
//給所有dom對象定義好onclick值為一個空函數 HTMLElement.prototype.onclick = function(){}; //給所有dom對象綁定默認點擊回調函數:點擊時都執行一次自己的onclick方法 [].map.call(document.all,function(item){ item.addEventListener('click',function(){ this.onclick(); }); });
然后我認為給同一個元素多次添加事件函數,會形成一個待執行的函數隊列,那么onclick以后無論怎么賦值,執行順序會相對固定。
然而有如下可運行的代碼我又無法解釋(請展開全部之后再閱讀代碼,避免混亂):
//改變onclick的函數。此時body['click']的事件隊列第一個函數為alert(1); document.body.onclick = function(){alert(1)} //body['click']事件隊列里增加了alert(2);點擊時依次執行alert(1)、alert(2) document.body.addEventListener('click',function(){alert(2)}); //再改變onclick的函數。此時body['click']的事件隊列第一個函數換為alert(3); document.body.onclick = function(){alert(3)}
然后這時候點擊body,先后順序本應該是alert(3)、alert(2),實際卻是alert(3)在后面?
為什么僅僅憑一個賦值操作改變了onclick的值就能導致事件執行的順序變了呢?
是“隊列”的思想錯誤了,還是onclick=xxx,不是我想的那么簡單?
補充后續思考:
如果onclick賦值時有內部操作改變了執行函數的隊列,那js為什么要這么做呢?
貘吃饃香:
路過
不同瀏覽器不一定是這個結果
底層代碼肯定不是JS
僅趴了機器上幾年前最老的blink代碼看了下
EventListenerMap 里靠的是 EventListenerVector
這玩意就是個 Vector
typedef Vector<RegisteredEventListener, 1>
這么搞的
onclick setting 時候是 vector->find 后沒有對應 handle
再 append 進去的
再次 setting 時是 find 有
就先 remove 老的再 append
沒見 Vector 有用到(定義過) replace 方法
所以(在這么實現的瀏覽器上)才有這種現象
最終還是輪子哥猜對了。vczh:
合理猜測:給onclick賦值的內部操作時,remove掉原來的,add上新的。