onclick = xxx這種賦值寫法綁定事件的原理是什麼?
剛入門不久,能力有限,這個問題我描述起來有點困難,只有勞煩各位大神細看了
我之前一直以為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為什麼要這麼做呢?
合理猜測:給onclick賦值的內部操作時,remove掉原來的,add上新的。
路過
不同瀏覽器不一定是這個結果底層代碼肯定不是JS僅趴了機器上幾年前最老的blink代碼看了下
EventListenerMap 里靠的是 EventListenerVector這玩意就是個 Vector
typedef Vector&onclick setting 時候是 vector-&>find 後沒有對應 handle
再 append 進去的
再次 setting 時是 find 有就先 remove 老的再 append沒見 Vector 有用到(定義過) replace 方法所以(在這麼實現的瀏覽器上)才有這種現象
最終還是輪子哥猜對了。訂閱者模式,內部應該是通過一個列表來維護事件響應的,所以每次為OnClick賦值的時候會替換原來的事件委託。
這個ff和chrome/safari行為是不一致的(edge未測試)。按照現在的規範(https://html.spec.whatwg.org/multipage/webappapis.html#event-handler-attributes:event-handlers-12),blink/webkit的行為是錯誤的。
嗯,恭喜輪子猜對了一個錯誤的實現。js就是猜的人多,而不去看源碼或規範,所以有一堆誤導大眾的文章
你這是毛病得改,對未在需求文檔中定義的行為不要妄加猜測,因為說不定哪天就改了呢。
這個可能是listener和onclick一個是列表,一個是屬性,屬性賦值自然覆蓋。先執行屬性,再執行監聽器列表。
當然也可以有其它和實現,那表現就不一樣了,你依賴這種調用順序是錯誤的,我完全可以所有listener並發,符合需求,卻讓你的程序出bug,你這就是作死,不要學習那些上古遺留的糟粕屬性,setter方法,去掉舊的,加上新的……你懂了吧,我猜的
跟所謂的主線程隊列裡面加入子線程是不是一個道理(疑惑
輪子哥猜中了。就是隊列,出了重新進,就從隊尾到隊頭了
推薦閱讀:
※有哪些常用軟體是用WEB前端技術寫的?底層使用瀏覽器殼?
※我可以只用flex布局嗎?
※網站的 logo 圖片用 img 標籤還是背景圖片合適?
※以下 CSS 柵格布局除了用 table 以外,有什麼其他的方法嗎?
※到底 CSS 還有必要語義么?若沒有必要,類名要怎樣寫?
TAG:前端開發 | JavaScript | HTML5 |