前端相关面试题
前言
JS
ES6
事件
事件事件是用来实现js和html与之相关的交互,可以用处理程序开预定事件,方便事件处理响应的代码。这种在传统软件工程中被称为观察者模式的模型,支持页面的行为js和页面的外观html和css的与之渲染。
事件流
事件流是从页面中接收事件的顺序,IE的事件流是事件冒泡;然而,Netscape Communicator 的事件流是事件捕获流。
事件冒泡
IE的事件流就成为事件冒泡就是事件执行顺序从下往上的顺序执行的。
如图所示:
事件捕获
事件捕获是事件到达预定目标之前捕获它,与事件冒泡原理刚好是相反的思维,执行顺序是从外往内。话不多说,点击链接即可:
DOM事件流
“DOM2级事件”给i顶的事件流包含了三个阶段:
- 事件捕获阶段
- 目标阶段
- 事件冒泡阶段
该阶段执行的触发事件顺序为:
如图所示:
请注意:IE8及更早版本不支持DOM事件流,IE9、Opera、Firefox、Chrome和Safari都支持DOM事件流;。
事件处理程序
响应某个事件的函数就称之为事件处理程序或者称为事件侦听器。那么事件处理程序的名字是以on开头的,例:点击事件的事件处理程序就是onclick
- HTML 事件处理程序:
在HTML中定义的事件处理程序包含要执行的具体动作,也可以调用在页面其他地方定义的脚本。
<input type="button" onclick="add()">
在HTML中指定的事件处理程序其实是有三个缺点:
- 存在一个时差问题。因为用户可能会在HTML元素一出现在页面上就触发相应的事件,但当时的事件处理程序有可能尚不具备执行条件。为此,很多HTML事件处理程序都会被封装在一个try-catch块中,以便错误不会浮出水面
- 这样扩展事件处理程序的作用域在不同浏览器中会导致不同结果。不同js引擎遵循的标识符解析规则略有差异,很可能会在访问非限定对象成员时出错.
- html与js代码紧密耦合,更换事件处理程序改动较大,产生性能消耗。
- DOM 0级事件处理程序
通过 JavaScript 指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。
其实每个元素都有自己的事件处理程序属性,比如onclick等。可以通过js将一个函数赋值给元素的事件处理程序属性。然而在DOM 0级事件处理程序中,事件处理程序里的this指向了当前的元素。
//拿到id属性值,并且声明。
var obj=document.getElementById("app");
//点击触发事件
obj.οnclick=function(){
alert(this.innerHTML);
}
如果删除DOM 0级事件,只需将事件处理程序的值赋值为null即可。
obj.onclick = null;
- DOM 2级事件处理程序
它定义了两个方法:
addEventListener() 和removeEventListener(),两者都接受了三个参数: 要处理的事件、作为事件处理程序的函数、useCaptrue(布尔值)。假如:布尔值为true,表示捕获阶段调用事件处理程序,反之,表示为在冒泡阶段调用事件处理程序。
addEventListener() 和removeEventListener()两者的区别:addEventListener()可以为元素添加多个事件处理程序,触发时会按照添加的顺序执行;removeEventListener() 不能移除匿名添加的函数。
var btn = document.getElementById("btn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);
var handler = function(){
console.log("北京欢迎您")
};
btn.addEventListener("click", handler, false);
// 这里省略了其他代码
btn.removeEventListener("click", handler, false); // 有效
大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段。从而,更大范围的做兼容和维护各种浏览器。IE9、Opera、Firefox、Chrome和Safari都支持DOM2级事件处理程序
IE事件处理程序
- IE 实现了与DOM中类似的两个方法:attachEvent() 和 detachEvent()。这两个方法接受相同的两个参数:事件处理程序名称事件处理程序函数。由于IE只支持事件冒泡,所以通过 attachEvent() 添加的事件处理程序都会被添加到冒泡阶段。
- 在使用DOM0级方法的情况下,事件处理程序会在其所属元素的作用域内运行;在使用 attachEvent() 方法的情况下,事件处理程序会在全局作用域中运行,因此 this 等于 window 。并且,与DOM 方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发
var btn = document.getElementById("btn");
var handler = function(){
document.write("clickAble")
};
btn.attachEvent("onclick", handler);
···
btn.detachEvent("onclick", handler);
注意:1=>事件名前面有on前缀;2=>在事件处理程序的函数中,this不再指向当前元素,而是指向window对象。
跨浏览器的事件处理程序
第一个要创建的方法是 addHandler(),它的职责是视情况分别使用DOM0级方法、DOM2级方法或IE方法来添加事件,它属于一个名叫 EventUtil 的对象。addHandler()方法接受3个参数:要操作的元素、事件名称和事件处理程序函数。EventUtil的用法如下所示:
var EventDev = {
//element==>当前元素 type==>事件名称 hanlder事件处理程序函数
addHandler: function(element, type, handler){//添加事件处理函数
if (element.addEventListener){//当前元素存在事件,就执行冒泡阶段的处理程序函数
element.addEventListener(type, handler, false);
} else if(element.attachEvent) {//元素注册事件存在
element.attachEvent("on" + type, handler);
} else {//当以上事件都为没执行,就让当前元素添加一个事件函数赋值为当前的事件 handler;
element["on" + type] = handler;
}
},
//删除事件处理程序函数
removeHandler: function(element, type, handler){
if (element.removeEventListener){//存在
element.removeEventListener(type, handler, false); //执行冒泡阶段的处理函数
} else if(element.detachEvent){//移除事件存在时 ,就删除当前元素的事件
element.detachEvent("on" + type, handler);
} else {//反之,直接为空。
element["on" + type] = null;
}
}
}
以下是触发 EventDev 对象的例子:
var btn = document.getElementById("btn");
var handler = function(){
alert("Clicked");
};
EventDev.addHandler(btn, "click", handler);
···
EventDev.removeHandler(btn, "click", handler);