1. they do not bind their own values of
this
2. Arrow functions are always anonymous. 即function
3. Arrow functions are part of the ECMAscript 6 specification, but not part of "normal" JavaScript in use in most browsers today.
in place of expressions like
function (foo) {...}
, you can see below:例1
var a = [
"We're up all night 'til the sun",
"We're up all night to get some",
"We're up all night for good fun",
"We're up all night to get lucky"
];
// These two assignments are equivalent:
// Old-school:
var a2 = a.map(function(s){ return s.length });
// ECMAscript 6 using arrow functions
var a3 = a.map( s => s.length );
// both a2 and a3 will be equal to [31, 30, 31, 31]
例2
function Foo() {
this.name = name;
this.count = 0;
this.startCounting();
}
Foo.prototype.startCounting = function() {
var self = this;
setInterval(function () {
// this is the Window, not Foo {}, as you might expect
console.log(this); // [object Window]
// that's why we reassign this to self before setInterval()
console.log(self.count);
self.count++;
},1000)
}
new Foo();
可寫成function Foo() {
this.name = name;
this.count = 0;
this.startCounting();
}
Foo.prototype.startCounting = function() {
setInterval(() => {
console.log(this); // [object Object]
console.log(this.count); // 1, 2, 3
this.count++;
},1000)
}
new Foo();
https://blog.techbridge.cc/2017/07/15/javascript-event-propagation/
1. 關於這些事件的傳遞順序,只要記住兩個原則就好:
先捕獲,再冒泡
當事件傳到 target 本身,沒有分捕獲跟冒泡
2.eventPhase,是一個數字,表示這個事件在哪一個 Phase 觸發。
html:
// PhaseTypeconst unsigned short CAPTURING_PHASE = 1;const unsigned short AT_TARGET = 2;const unsigned short BUBBLING_PHASE = 3;
3.實例說明
js:<html><body><ul id="list"><li id="list_item"><a id="list_item_link" target="_blank" href="http://google.com"></a></li></ul></body></html>
const get = (id) => document.getElementById(id);const $list = get('list');const $list_item = get('list_item');const $list_item_link = get('list_item_link');// list 的冒泡$list.addEventListener('click', (e) => {console.log('list bubbling', e.eventPhase);}, false)// list 的捕獲$list.addEventListener('click', (e) => {console.log('list capturing', e.eventPhase);}, true)// list_item 的冒泡$list_item.addEventListener('click', (e) => {console.log('list_item bubbling', e.eventPhase);}, false)// list_item 的捕獲$list_item.addEventListener('click', (e) => {console.log('list_item capturing', e.eventPhase);}, true)// list_item_link 的冒泡$list_item_link.addEventListener('click', (e) => {console.log('list_item_link bubbling', e.eventPhase);}, false)// list_item_link 的捕獲$list_item_link.addEventListener('click', (e) => {console.log('list_item_link capturing', e.eventPhase);}, true)
一樣點擊超連結,輸出的結果是:
list capturing 1list_item capturing 1list_item_link bubbling 2list_item_link capturing 2list_item bubbling 3list bubbling 3
4. 事件鏈這麼長,一定有方法可以中斷這一條鏈,讓事件的傳遞不再繼續,就是:e.stopPropagation (取消事件傳遞),但對於同一個層級,其他的 listener 還是會被執行到。
若是你想要讓其他同一層級的 listener 也不要被執行,可以改用e.stopImmediatePropagation();
5. e.preventDefault (取消預設行為) ,preventDefault跟 JavaScript 的事件傳遞「一點關係都沒有」,你加上這一行之後,事件還是會繼續往下傳遞。
Once preventDefault has been called it will remain in effect throughout the remainder of the event’s propagation. 意思就是說一旦 call 了preventDefault,在之後傳遞下去的事件裡面也會有效果。
以上面的例子,$list改寫成下方這樣,則不會跳出google.com新頁面,但所有console.log內容都會和原本所呈現的結果一樣
// list 的捕獲$list.addEventListener('click', (e) => {console.log('list capturing', e.eventPhase);e.preventDefault();}, true)
應用 做數據統計及分析
|
|
cancelable動作:檢測事件是否為 preventDefault() 方法可以取消与事件关联的默认动作 ,結果會回傳true, 或false。所有 Cancelable 为 true 的事件类型理论上都是可以有 {passive: true} 优化的。
passive: addEventListener() 的第三个参数之一,出現這個參數的理由是 浏览器无法预先知道一个监听器会不会调用 preventDefault(),它能做的只有等监听器执行完后再去执行默认行为,而监听器执行是要耗时的,有些甚至耗时很明显,这样就会导致页面卡顿
passive 的意思是“顺从的”,表示它不会对事件的默认行为说 no,也就是 preventDefault() 无效。
鉴于这个新特性本来就是为解决滚动和触摸事件的卡顿而发明的,目前 Chrome 和 Firefox 支持优化的事件类型也仅限这类事件,比如 touchstart,touchmove,wheel 等事件。
即便为下面这些类型的事件添加 passive 的监听器,目前浏览器们也不会优化:
- click 事件: 左键点击这个链接,等待 3 秒后才会打开新页面(可能被浏览器识别成弹窗)
- contextmenu 事件:右键点击这句文本,等待 3 秒后才会打开右键菜单
- beforeinput 事件(只有 Chrome 52 及以上支持):在右侧输入时会有 300 毫秒的卡顿
总结一下就是 {passive: true} 不能保证浏览器对所有事件类型的默认行为进行优化
http://www.cnblogs.com/ziyunfei/p/5545439.html
event.defaultPrevented:
回傳一個布林值,表示事件的預設行為是否被取消,也就是事件物件是否曾執行 preventDefault() 方法event.stopPropagation():
stops the move upwards, but on the current element all other handlers will run.event.stopImmediatePropagation():stop the bubbling and prevent handlers on the current element from running.
dispatchEvent:是「建立→初始化→觸發」的最後一步驟。而事件有多種建立方式,例如用
document.createEvent
並用 initEvent 或其他特殊 methods ,像是 initMouseEvent 或 initUIEvent 來初始化。或是用new Event建立,再用addEventListener監聽,最後再用dispatchEvent觸發。
也就是說,欲使用dispatchEvent必須要有一定的前置作業!
綜合上述各個新詞彙,應用如下
let event = new Event("foo", { // 创建一个 type 为 foo 的事件对象,可以被阻止默认行为。這是創建了一個叫foo的「動作」! "cancelable": true }) document.addEventListener("foo", function(event) { // 在 document 上绑定 foo 事件的监听函数。為了更熟悉,可以想像foo替換成click,這樣就是監聽click動作 console.log(event.defaultPrevented) // false event.preventDefault() console.log(event.defaultPrevented) // 还是 false,preventDefault() 无效 }, { passive: true }) document.dispatchEvent(event) // 觸發自定义事件
輸出結果會有 Unable to preventDefault inside passive event listener invocation.警告
另外,我們要注意:
event.currentTarget (=
this) v.s. event.target(触发事件的元素,觀念為caturing→target→bubbling)
currentTarget有可能會比較大,為parent element。
而target會是特定element,不會是parent element。
在 removeEventListener 的时候永远不需写 passive 和 once,但 capture 可能要!理由显而易见,一个监听器同时是 passive 和非 passive(以及同时是 once 和非 once)是说不通的,如果你添加了两者,那么后添加的不算,浏览器会认为添加过了
沒有留言:
張貼留言