前端面试week2
1.html5有哪些新特性?如何处理HTML5新标签的浏览器兼容问题?如何区分 HTML 和 HTML5?
转自:
https://www.cnblogs.com/wuqilang/p/11366962.html
h5新特性:
语义化标签:
<hrader></header>
<footer></footer>
<nav></nav>
<section></section>
<article></article>
<aside></aside>
<video></video>
<audio></audio>
新增表单元素:
email、month、number、range、search、tel、url、week、time、date、datatime、datetime-local
新增表单属性:
placeholder、required、autofocus、autocomplete、maxlength、novalidate、max、min、step、multipe、disabled、checked
新增的视频和音频标签:
<video></video>、<audio></audio>
canvas绘图
SVG绘图
拖拽
WebWorker
WebStorage
WebSocket
h5新标签的兼容问题:
(1)IE8/IE7/IE6支持通过 document.createElement
(2)将html5shiv.js引入到head中(IE9及以下)
载入后,初始化新标签的CSS:
/*html5*/
article,aside,dialog,footer,header,section,footer,nav,figure,menu{display:block}
如何区分html和html5:
(1)在文档类型声明上,h5为,之前版本比较长
(2)h5有语义化标签,如<header></header>
2.浏览器的渲染过程
转载:
https://www.cnblogs.com/slly/p/6640761.html
Firefox、Chrome和Safari是基于两种渲染引擎构建的,Firefox使用Geoko——Mozilla自主研发的渲染引擎,Safari和Chrome都使用webkit。
渲染主流程
渲染引擎首先通过网络获得所请求文档的内容,通常以8K分块的方式完成。下面是渲染引擎在取得内容之后的基本流程:
解析html以构建dom树 -> 构建render树 -> 布局render树 -> 绘制render树
DOM Tree:浏览器将HTML解析成树形的数据结构。
CSS Rule Tree:浏览器将CSS解析成树形的数据结构。
Render Tree: DOM和CSSOM合并后生成Render Tree。
layout: 有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系,从而去计算出每个节点在屏幕中的位置。
painting: 按照算出来的规则,通过显卡,把内容画到屏幕上。
reflow(回流):当浏览器发现某个部分发生了点变化影响了布局,需要倒回去重新渲染,内行称这个回退的过程叫 reflow。reflow 会从 这个 root frame 开始递归往下,依次计算所有的结点几何尺寸和位置。reflow 几乎是无法避免的。现在界面上流行的一些效果,比如树状目录的折叠、展开(实质上是元素的显 示与隐藏)等,都将引起浏览器的 reflow。鼠标滑过、点击……只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起它内部、周围甚至整个页面的重新渲 染。通常我们都无法预估浏览器到底会 reflow 哪一部分的代码,它们都彼此相互影响着。
repaint(重绘):改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸没有变。
注意:(1)display:none 的节点不会被加入Render Tree,而visibility: hidden 则会,所以,如果某个节点最开始是不显示的,设为display:none是更优的。
(2)display:none 会触发 reflow,而 visibility:hidden 只会触发 repaint,因为没有发现位置变化。
(3)有些情况下,比如修改了元素的样式,浏览器并不会立刻reflow 或 repaint 一次,而是会把这样的操作积攒一批,然后做一次 reflow,这又叫异步 reflow 或增量异步 reflow。但是在有些情况下,比如resize 窗口,改变了页面默认的字体等。对于这些操作,浏览器会马上进行 reflow。
webkit的主要流程
Geoko的主要流程:
Gecko 里把格式化好的可视元素称做“帧树”(Frame tree)。每个元素就是一个帧(frame)。 webkit 则使用”渲染树”这个术语,渲染树由”渲染对象”组成。webkit 里使用”layout”表示元素的布局,Gecko则称为”reflow”。Webkit使用”Attachment”来连接DOM节点与可视化信息以构建渲染树。一个非语义上的小差别是Gecko在HTML与DOM树之间有一个附加的层 ,称作”content sink”,是创建DOM对象的工厂。
尽管Webkit与Gecko使用略微不同的术语,这个过程还是基本相同的,如下:
1. 浏览器会将HTML解析成一个DOM树,DOM 树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。
2. 将CSS解析成 CSS Rule Tree 。
3. 根据DOM树和CSSOM来构造 Rendering Tree。注意:Rendering Tree 渲染树并不等同于 DOM 树,因为一些像Header或display:none的东西就没必要放在渲染树中了。
4. 有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系。下一步操作称之为layout,顾名思义就是计算出每个节点在屏幕中的位置。
5. 再下一步就是绘制,即遍历render树,并使用UI后端层绘制每个节点。
注意:上述这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。
3.DOM怎样添加、移除、移动、复制、创建和查找节点
转载:
http://blog.sina.com.cn/s/blog_49fa034d0101gg7m.html
1)创建新节点
createDocumentFragment() //创建一个DOM片段
createElement_x_x() //创建一个具体的元素
createTextNode() //创建一个文本节点
(2)添加、移除、替换、插入
appendChild()
removeChild()
replaceChild()
insertBefore()
(3)查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性
1.创建元素节点
document.createElement_x_x() 方法 用于创建元素,接受一个参数,即要创建元素的标签名,返回创建的元素节点
1 var div = document.createElement_x_x(“div”); //创建一个div元素
2 div.id = “myDiv”; //设置div的id
3 div.className = “box”; //设置div的class
创建元素后还要把元素添加到文档树中
2.添加元素节点
appendChild() 方法 用于向childNodes列表的末尾添加一个节点,返回要添加的元素节点
1 var ul = document.getElementByIdx_xx_x(“myList”); //获得ul
2 var li = document.createElement_x_x(“li”); //创建li
3 li.innerHTML = “项目四”; //向li内添加文本
4 ul.appendChild(li); //把li 添加到ul子节点的末尾
appendChild() 方法还可以添加已经存在的元素,会将元素从原来的位置移到新的位置
1 var ul = document.getElementByIdx_xx_x(“myList”); //获得ul
2 ul.appendChild(ul.firstChild); //把ul的第一个元素节点移到ul子节点的末尾
insertBefore() 方法,如果不是在末尾插入节点,而是想放在特定的位置上,用这个方法,该方法接受2个参数,第一个是要插入的节点,第二个是参照节点,返回要添加的元素节点
1 var ul = document.getElementByIdx_xx_x(“myList”); //获得ul
2 var li = document.createElement_x_x(“li”); //创建li
3 li.innerHTML= “项目四”; //向li内添加文本
4 ul.insertBefore(li,ul.firstChild); //把li添加到ul的第一个子节点前
1 var ul = document.getElementByIdx_xx_x(“myList”); //获得ul
2 var li = document.createElement_x_x(“li”); //创建li
3 li.innerHTML= “项目四”; //向li内添加文本
4 ul.insertBefore(li,ul.lastChild); //把li添加到ul的子节点末尾
1 var ul = document.getElementByIdx_xx_x(“myList”); //获得ul
2 var li = document.createElement_x_x(“li”); //创建li
3 li.innerHTML= “项目四”; //向li内添加文本
4 var lis = ul.getElementsByTagName_r(“li”) //获取ul中所有li的集合
5 ul.insertBefore(li,lis[1]); //把li添加到ul中的第二个li节点前
添加后:
3.移除元素节点
removeChild() 方法,用于移除节点,接受一个参数,即要移除的节点,返回被移除的节点,注意被移除的节点仍然在文档中,不过文档中已没有其位置了
1 var ul = document.getElementByIdx_xx_x(“myList”); //获得ul
2 var fromFirstChild = ul.removeChild(ul.firstChild); //移除ul第一个子节点
1 var ul = document.getElementByIdx_xx_x(“myList”); //获得ul
2 var lis = ul.getElementsByTagName_r(“li”) //获取ul中所有li的集合
3 ul.removeChild(lis[0]); //移除第一个li,与上面不同,要考虑浏览器之间的差异
4.替换元素节点
replaceChild() 方法,用于替换节点,接受两个参数,第一参数是要插入的节点,第二个是要替换的节点,返回被替换的节点
1 var ul = document.getElementByIdx_xx_x(“myList”); //获得ul
2 var fromFirstChild = ul.replaceChild(ul.firstChild); //替换ul第一个子节点
1 var ul = document.getElementByIdx_xx_x(“myList”); //获得ul;
2 var li = document.createElement_x_x(“li”); //创建li
3 li.innerHTML= “项目四”; //向li内添加文本
4 var lis = ul.getElementsByTagName_r(“li”) //获取ul中所有li的集合
5 var returnNode = ul.replaceChild(li,lis[1]); //用创建的li替换原来的第二个li
5.复制节点
cloneNode() 方法,用于复制节点, 接受一个布尔值参数, true 表示深复制(复制节点及其所有子节点), false 表示浅复制(复制节点本身,不复制子节点)
1 var ul = document.getElementByIdx_xx_x(“myList”); //获得ul
2 var deepList = ul.cloneNode(true); //深复制
3 var shallowList = ul.cloneNode(false); //浅复制
4. 解释盒模型宽高值得计算方式,边界塌陷,负值作用,box-sizing概念
转载:
https://blog.csdn.net/webbeizi/article/details/107079560
- 盒模型:IE 678 下(不添加doctype) 使用ie盒模型,宽度 = 边框 + padding + 内容宽度;
chrom、IE9+、(添加doctype) 使用标准盒模型, 宽度 = 内容宽度。 - box-sizing :
为了解决标准黑子和IE盒子的不同,CSS3增添了盒模型属性box-sizing,content-box(默认),border-box
让元素维持IE传统盒子模型, inherit 继承 父盒子模型; - 边界塌陷:块元素的 top 与 bottom 外边距有时会合并(塌陷)为单个外边距(合并后最大的外边距),这样的现象称之为 外边距塌陷。
- 负值作用:负margin会改变浮动元素的显示位置,即使我的元素写在DOM的后面,我也能让它显示在最前面。
5.this对象的理解
转载:
https://www.cnblogs.com/ktddcn/p/12099099.htm
一、方法中的this
var isObject = {
a: 'inner object',
innerFunction: function() {
return this.a;
}
}
console.log('方法里的this指向:', isObject.innerFunction());
//输出结果:方法里的this指向: inner object
由上面代码可以看出,因为对象调用了其内部方法innerFunction(),所以此时this指向使用它时所在的对象,即isObject对象。
如果我们此时在innerFunction()函数里return this,此时控制台打印出Object {a: “inner object”, innerFunction: },表示this正好指向isObject对象。
二、单独使用this
var x = this;
console.log("this指向:", x);
//输出结果:this指向: Window {postMessage: , blur: , focus: , close: , parent: Window, …}
可以看出,当单独使用this时,this指向window对象
三、函数中使用this
var variable = 'test';
function outerFunction() {
var variable = 0;
return this.variable;
}
console.log('函数中this指向:', outerFunction());
//输出结果:函数中this指向:test
从上面代码看出,函数中的this指向window对象,所以打印出的结果是test而不是0。
如果我们此时在outerFunction()函数里return this,此时控制台打印出Window {postMessage: , blur: , focus: , close: , parent: Window, …},表示this指向window对象。
值的注意的一点是在严格模式中,函数并不能绑定到this上,所以这时候的this是undefined。
再来看一个例子:
var a = 21;
var isObject = {
a: 'inner object',
innerFunction: function() {
return this.a;
}
}
var useObject = isObject.innerFunction;
console.log('结果:', useObject());
//输出结果:结果:21
可能有人会问,为什么输出的不是inner object,而是21,注意,this指向的是使用它时所在的对象,因为isObject.innerFunction将自身赋给全局变量useObject,所以此时useObject保存的是innerFunction()方法,this指向全局。
四、事件中的this
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<button onclick="this.style.display='none'">点我我就消失</button>
</body>
</html>
很显然,在HTML事件句柄中,this指向了接收事件的HTML元素。
五、箭头函数中的this
需要注意的是,箭头函数内部并没有绑定this的机制,所以this的指向是固定的,即指向当前定义时所在的对象(注意,一般情况下,上下文环境不做变化,this为全局对象,即this定义在顶层环境)。也可以说,内部的this就是外层代码块的this。
var isObject = {
a: 'hhh',
functions: () => {
console.log("对象:",this);
}
}
isObject.functions();
//输出结果:对象:Window {postMessage: , blur: , focus: , close: , parent: Window, …}
可以看到,同样是对象方法,箭头函数里的this指向的是window对象。
再来看一个例子:
var isObject = {
a: 'hhh',
functions: () => {
this.a = 0
console.log("结果:",this.a);
}
}
isObject.functions();
//输出结果:结果:0
此时,在isObject对象functions方法内部定义了一个属性a,它属于this全局对象,所以输出结果为0。
难道this只能指向window了吗?答案是否定的,再来看一个例子:
function myFunction() {
var innerfunction = () => {
console.log('x:', this.x);
}
return innerfunction;
}
var test = myFunction.call({x: 1});
test();
//输出结果:1
从上面代码可以看出,this此时指向myFunction里的对象{x:1},所以打印出的结果为1。注意,因为箭头函数本身并不能绑定this,所以它不能使用apply,call,bind方法来改变上下文环境。
6.JavaScript事件模型
转载:
https://blog.csdn.net/chenmoquan/article/details/10162477
什么是事件?
事件(Event)是JavaScript应用跳动的心脏 ,也是把所有东西粘在一起的胶水。当我们与浏览器中 Web 页面进行某些类型的交互时,事件就发生了。事件可能是用户在某些内容上的点击、鼠标经过某个特定元素或按下键盘上的某些按键。事件还可能是 Web 浏览器中发生的事情,比如说某个 Web 页面加载完成,或者是用户滚动窗口或改变窗口大小。
通过使用 JavaScript ,你可以监听特定事件的发生,并规定让某些事件发生以对这些事件做出响应。
今天的事件
在漫长的演变史,我们已经告别了内嵌式的事件处理方式(直接将事件处理器放在 HTML 元素之内来使用)。今天的事件,它已是DOM的重要组成部分,遗憾的是, IE继续保留它最早在IE4.0中实现的事件模型,以后的IE版本中也没有做太大的改变,这也就是说IE还是使用的是一种专有的事件模型(冒泡型),而其它的主流浏览器直到DOM 级别 3 规定定案后,才陆陆续续支持DOM标准的事件处理模型 — 捕获型与冒泡型。
历史原因是:W3C 规范 在DOM 级别 1中并没有定义任何的事件,直到发布于 2000 年 11 月 的DOM 级别 2 才定义了一小部分子集,DOM 级别 2中已经提供了提供了一种更详细的更细致的方式以控制 Web 页面中的事件,最后,完整的事件是在2004年 DOM 级别 3的规定中才最终定案。因为IE4是1995推出的并已实现了自己的事件模型(冒泡型),当时根本就没有DOM标准,不过在以后的DOM标准规范过程中已经把IE的事件模型吸收到了其中。
目前除IE浏览器外,其它主流的Firefox, Opera,
Safari都支持标准的DOM事件处理模型。IE仍然使用自己专有的事件模型,即冒泡型,它事件模型的一部份被DOM标准采用,这点对于开发者来说也是有好处的,只有使用
DOM标准,IE都共有的事件处理方式才能有效的跨浏览器。
DOM事件流
DOM(文档对象模型)结构是一个树型结构,当一个HTML元素产生一个事件时,该事件会在元素结点与根节点之间按特定的顺序传播,路径所经过的节点都会收到该事件,这个传播过程可称为DOM事件流。
事件顺序有两种类型:事件捕捉和事件冒泡。
冒泡型事件(Event Bubbling)
这是IE浏览器对事件模型的实现,也是最容易理解的,至少笔者觉得比较符合实际的。冒泡,顾名思义,事件像个水中的气泡一样一直往上冒,直到顶端。从
DOM树型结构上理解,就是事件由叶子节点沿祖先结点一直向上传递直到根节点;从浏览器界面视图HTML元素排列层次上理解就是事件由具有从属关系的最确定的目标元素一直传递到最不确定的目标元素.冒泡技术.冒泡型事件的基本思想,事件按照从特定的事件目标开始到最不确定的事件目标.
捕获型事件(Event Capturing)
Netscape 的实现,它与冒泡型刚好相反,由DOM树最顶层元素一直到最精确的元素,这个事件模型对于开发者来说(至少是我…)有点费解,因为直观上的理解应该如同冒泡型,事件传递应该由最确定的元素,即事件产生元素开始。
DOM标准的事件模型
DOM标准同时支持两种事件模型,即捕获型事件与冒泡型事件,但是,捕获型事件先发生。两种事件流都会触发DOM中的所有对象,从document对象开始,也在document对象结束(大部分兼容标准的浏览器会继续将事件是捕捉/冒泡延续到window对象)。
如果一个处理函数既注册了捕获型事件的监听,又注册冒泡型事件监听,那么在DOM事件模型中它就会被调用两次。
DOM标准的事件模型最独特的性质是,文本节点也会触发事件(在IE不会)。
事件传送
为了更好的说明DOM标准中的事件流原理,我们把它放在“事件传送”小结里来更具体的解释。
显然,如果为一个超链接添加了click事件监听器,那么当该链接被点击时该事件监听器就会被执行。但如果把该事件监听器指派给了包含该链接的p元素或者位于DOM树顶端的document节点,那么点击该链接也同样会触发该事件监听器。这是因为事件不仅仅对触发的目标元素产生影响,它们还会对沿着DOM结构的所有元素产生影响。这就是大家所熟悉的事件转送。
W3C事件模型中明确地指出了事件转送的原理。事件传送可以分为3个阶段。
(1)在事件捕捉(Capturing)阶段,事件将沿着DOM树向下转送,目标节点的每一个祖先节点,直至目标节点。例如,若用户单击了一个超链接,则该单击事件将从document节点转送到html元素,body元素以及包含该链接的p元素。
在此过程中,浏览器都会检测针对该事件的捕捉事件监听器,并且运行这件事件监听器。
(2)在目标(target)阶段,浏览器在查找到已经指定给目标事件的事件监听器之后,就会运行 该事件监听器。目标节点就是触发事件的DOM节点。例如,如果用户单击一个超链接,那么该链接就是目标节点(此时的目标节点实际上是超链接内的文本节点)。
(3)在冒泡(Bubbling)阶段,事件将沿着DOM树向上转送,再次逐个访问目标元素的祖先节点到document节点。该过程中的每一步。浏览器都将检测那些不是捕捉事件监听器的事件监听器,并执行它们。
并非所有的事件都会经过冒泡阶段的
所有的事件都要经过捕捉阶段和目标阶段,但是有些事件会跳过冒泡阶段。例如,让元素获得输入焦点的focus事件以及失去输入焦点的blur事件就都不会冒泡。
事件句柄和事件接听器
事件句柄
事件句柄(又称事件处理函数,DOM称之为事件监听函数),用于响应某个事件而调用的函数称为事件处理函数
。每一个事件均对应一个事件句柄,在程序执行时,将相应的函数或语句指定给事件句柄,则在该事件发生时,浏览器便执行指定的函数或语句,从而实现网页内容与用户操作的交互。当浏览器检测到某事件发生时,便查找该事件对应的事件句柄有没有被赋值,如果有,则执行该事件句柄。
我们认为响应点击事件的函数是onclick事件处理函数。以前,事件处理函数有两种分配方式:在JavaScript中或者在HTML中。
如果在JavaScript 中分配事件处理函数, 则需要首先获得要处理的对象的一引用,然后将函数赋值给对应的事件处理函数属性,请看一个简单的例子:
1 var link = document.getElementById( " mylink " );
2 link.onclick = function (){
3 alert( " I was clicked ! " );
4 };
从我们看到的例子中,我们发现使用事件句柄很容易,
不过事件处理函数名称必须是小写的,还有就是只有在
元素载入完成之后才能将事件句柄赋给元素,不然会有异常。
关于文档载入技术,请看《window.onload加载的多种解决方案》 的文章。
如果在HTML中分配事件句柄的话,则直接通过HTML属性来设置事件处理函数就行了,并在其中包含合适的脚本作为特性值就可以了,例如:
<a href="/" onclick="JavaScript code here">......</a>
这种JavaScript 代码和通过HTML的style属性直接将CSS属性赋给元素类似。这样会代码看起来一团糟,也违背了将实现动态行为的代码与显示文档静态内容的代码相分离的原则。从1998年开始,这种写法就过时了。
这种传统的事件绑定技术,优缺点是显然的:
*简单方便,在HTML中直接书写处理函数的代码块,在JS中给元素对应事件属性赋值即可。
*IE与DOM标准都支持的一种方法,它在IE与DOM标准中都是在事件冒泡过程中被调用的。
*可以在处理函数块内直接用this引用注册事件的元素,this引用的是当前元素。
*要给元素注册多个监听器,就不能用这方法了。
事件接听器
除了前面已经介绍的简单事件句柄之外,现在大多数浏览器都内置了一些更高级的事件处理方式,即,事件监听器,这种处理方式就不受一个元素只能绑定一个事件句柄的限制。
我们已经知道了事件句柄与事件监听器的最大不同之处是使用事件句柄时一次只能插接一个事件句柄,但对于事件监听器,一次可以插接多个。
IE下的事件监听器:
IE提供的却是一种自有的,完全不同的甚至存在BUG的事件监听器,因此如果要让脚本在本浏览器中正常运行的话,就必须使用IE所支持的事件监听器。另外,Safari 浏览器中的事件监听器有时也存在一点不同。
在IE中,每个元素和window对象都有两个方法:attachEvent方法和detachEvent方法。
1 element.attachEvent( " onevent " ,eventListener);
此方法的意思是在IE中要想给一个元素的事件附加事件处理函数,必须调用attachEvent方法才能创建一个事件监听器。attachEvent方法允许外界注册该元素多个事件监听器。
attachEvent接受两个参数。第一个参数是事件类型名,第二个参数eventListener是回调处理函数。这里得说明一下,有个经常会出错的地方,IE下
利用attachEvent注册的处理函数调用时this指向不再是先前注册事件的元素,这时的this为window对象。还有一点是此方法的事件类型名称必须加上一个”on”的前缀(如onclick)。
element.attachEvent( " onevent " ,eventListener);
要想移除先前元素注册的事件监听器,可以使用detachEvent方法进行删除,参数相同。
DOM标准下的事件监听器:
在支持W3C标准事件监听器的浏览器中,对每个支持事件的对象都可以使用addEventListener方法。该方法既支持注册冒泡型事件处理,又支持捕获型事件处理。所以与IE浏览器中注册元素事件监听器方式有所不同的。
1 // 标准语法
2 element.addEventListener( ' event ' , eventListener, useCapture);
3 // 默认
4 element.addEventListener( ' event ' , eventListener, false );
addEventListener方法接受三个参数。第一个参数是事件类型名,值得注意的是,这里事件类型名称与IE的不同,事件类型名是没’on’开头的;第二个参数eventListener是回调处理函数(即监听器函数);第三个参数注明该处理回调函数是在事件传递过程中的捕获阶段被调用还是冒泡阶段被调用 ,通常此参数通常会设置为false(为false时是冒泡),那么,如果将其值设置为true,那就创建一个捕捉事件监听器。
移除已注册的事件监听器调用element的removeEventListener方法即可,参数相同。
1 // 标准语法
2 element.removeEventListener( ' event ' , eventListener, useCapture);
3 // 默认
4 element.removeEventListener( ' event ' , eventListener, false );
通过addEventListener方法添加的事件处理函数,必须使用removeEventListener方法才能删除,而且要求参数与添加事件处理函数时addEventListener方法的参数完全一致(包括useCapture参数),否则将不能成功删除事件处理函数。
跨浏览器的注册与移除元素事件监听器方案
我们现在已经知道,对于支持addEventListener方法的浏览器,只要需要事件监听器脚本就都需要调用addEventListener方法;而对于不支持该方法的IE浏览器,使用事件监听器时则需要调用attachEvent方法。要确保浏览器使用正确的方法其实并不困难,只需要通过一个if-else语句来检测当前浏览器中是否存在addEventListener方法或attachEvent方法即可。
这样的方式就可以实现一个跨浏览器的注册与移除元素事件监听器方案:
1 var EventUtil = {
2 // 注册
3 addHandler: function (element, type, handler){
4 if (element.addEventListener){
5 element.addEventListener(type, handler, false );
6 } else if (element.attachEvent){
7 element.attachEvent( " on " + type, handler);
8 } else {
9 element[ " on " + type] = handler;
10 }
11 },
12 // 移除注册
13 removeHandler: function (element, type, handler){
14 if (element.removeEventListener){
15 element.removeEventListener(type, handler, false );
16 } else if (element.detachEvent){
17 element.detachEvent( " on " + type, handler);
18 } else {
19 element[ " on " + type] = null ;
20 }
21 }
22 };
事件对象引用
为了更好的处理事件,你可以根据所发生的事件的特定属性来采取不同的操作。
如事件模型一样,IE 和其他浏览器处理方法不同:IE 使用一个叫做 event 的全局事件对象来处理对象(它可以在全局变量window.event中找到),而其它所有浏览器采用的 W3C 推荐的方式,则使用独立的包含事件对象的参数传递。
跨浏览器实现这样的功能时,最常见的问题就是获取事件本身的引用及获取该事件的目标元素的引用。
下面这段代码就为你解决了这个问题:
1 var EventUtil = {
2 getEvent: function (event){
3 return event ? event : window.event;
4 },
5 getTarget: function (event){
6 return event.target || event.srcElement;
7 }
8 };
停止事件冒泡和阻止事件的默认行为
“停止事件冒泡“和”阻止浏览器的默认行为“,这两个概念非常重要,它们对复杂的应用程序处理非常有用。
1.停止事件冒泡
停止事件冒泡是指,停止冒泡型事件的进一步传递(取消事件传递,不只是停止IE和DOM标准共有的冒泡型事件,我们还可以停止支持DOM标准浏览器的捕捉型事件,用topPropagation()方法)。例如上图中的冒泡型事件传递中,在body处理停止事件传递后,位于上层的document的事件监听器就不再收到通知,不再被处理。
2.阻止事件的默认行为
停止事件的默认行为是指,通常浏览器在事件传递并处理完后会执行与该事件关联的默认动作(如果存在这样的动作)。例如,如果表单中input type 属性是 “submit”,点击后在事件传播完浏览器就自动提交表单。又例如,input 元素的 keydown 事件发生并处理后,浏览器默认会将用户键入的字符自动追加到 input 元素的值中。
停止事件冒泡的处理方法:
在IE下,通过设置event对象的cancelBubble为true即可。
1 function someHandle() {
2 window.event.cancelBubble = true ;
3 }
DOM标准通过调用event对象的stopPropagation()方法即可。
1 function someHandle(event) {
2 event.stopPropagation();
3 }
因些,跨浏览器的停止事件传递的方法是:
1 function someHandle(event) {
2 event = event || window.event;
3 if (event.stopPropagation){
4 event.stopPropagation();
5 } else {
6 event.cancelBubble = true ;
7 }
8 }
阻止事件的默认行为的处理方法
就像事件模型和事件对象差异一样,在IE和其它所有浏览器中阻止事件的默认行为的方法也不同。
在IE下,通过设置event对象的returnValue为false即可。
1 function someHandle() {
2 window.event.returnValue = false ;
3 }
DOM标准通过调用event对象的preventDefault()方法即可。
1 function someHandle(event) {
2 event.preventDefault();
3 }
因些,跨浏览器的取消事件传递后的默认处理方法是:
1 function someHandle(event) {
2 event = event || window.event;
3 if (event.preventDefault){
4 event.preventDefault();
5 } else {
6 event.returnValue = false ;
7 }
8 }
完整的事件处理兼容性函数
1 var EventUtil = {
2 addHandler: function (element, type, handler){
3 if (element.addEventListener){
4 element.addEventListener(type, handler, false );
5 } else if (element.attachEvent){
6 element.attachEvent( " on " + type, handler);
7 } else {
8 element[ " on " + type] = handler;
9 }
10 },
11 removeHandler: function (element, type, handler){
12 if (element.removeEventListener){
13 element.removeEventListener(type, handler, false );
14 } else if (element.detachEvent){
15 element.detachEvent( " on " + type, handler);
16 } else {
17 element[ " on " + type] = null ;
18 }
19 },
20 getEvent: function (event){
21 return event ? event : window.event;
22 },
23 getTarget: function (event){
24 return event.target || event.srcElement;
25 },
26 preventDefault: function (event){
27 if (event.preventDefault){
28 event.preventDefault();
29 } else {
30 event.returnValue = false ;
31 }
32 },
33 stopPropagation: function (event){
34 if (event.stopPropagation){
35 event.stopPropagation();
36 } else {
37 event.cancelBubble = true ;
38 }
39 };
捕获型事件模型与冒泡型事件模型的应用场合
标准事件模型为我们提供了两种方案,可能很多朋友分不清这两种不同模型有啥好处,为什么不只采取一种模型。
这里抛开IE浏览器讨论(IE只有一种,没法选择)什么情况下适合哪种事件模型。
- 捕获型应用场合
捕获型事件传递由最不精确的祖先元素一直到最精确的事件源元素,传递方式与操作系统中的全局快捷键与应用程序快捷键相似。当一个系统组合键发生时,如果注
册了系统全局快捷键监听器,该事件就先被操作系统层捕获,全局监听器就先于应用程序快捷键监听器得到通知,也就是全局的先获得控制权,它有权阻止事件的进
一步传递。所以捕获型事件模型适用于作全局范围内的监听,这里的全局是相对的全局,相对于某个顶层结点与该结点所有子孙结点形成的集合范围。
例如你想作全局的点击事件监听,相对于document结点与document下所有的子结点,在某个条件下要求所有的子结点点击无效,这种情况下冒泡模型就解决不了了,而捕获型却非常适合,可以在最顶层结点添加捕获型事件监听器,伪码如下:
1 function globalClickListener(event) {
2 if (canEventPass == false ) {
3 // 取消事件进一步向子结点传递和冒泡传递
4 event.stopPropagation();
5 // 取消浏览器事件后的默认执行
6 event.preventDefault();
7 }
8 }
这样一来,当canEventPass条件为假时,document下所有的子结点click注册事件都不会被浏览器处理。
- 冒泡型的应用场合
可以说我们平时用的都是冒泡事件模型,因为IE只支持这模型。这里还是说说,在恰当利用该模型可以提高脚本性能。在元素一些频繁触发的事件中,如
onmousemove,
onmouseover,onmouseout,如果明确事件处理后没必要进一步传递,那么就可以大胆的取消它。此外,对于子结点事件监听器的处理会对父
层监听器处理造成负面影响的,也应该在子结点监听器中禁止事件进一步向上传递以消除影响。
综合案例分析
最后结合下面HTML代码作分析:
1 < body onclick ="alert('current is body');" >
2 < div id ="div0" onclick ="alert('current is '+this.id)" >
3 < div id ="div1" onclick ="alert('current is '+this.id)" >
4 < div id ="div2" onclick ="alert('current is '+this.id)" >
5 < div id ="event_source" onclick ="alert('current is '+this.id)" style ="height:200px;width:200px;background-color:red;" ></ div >
6 </ div >
7 </ div >
8 </ div >
9 </ body >
HTML运行后点击红色区域,这是最里层的DIV,根据上面说明,无论是DOM标准还是IE,直接写在html里的监听处理函数是事件冒泡传递时调用的,由最里层一直往上传递,所以会先后出现
current is event_source
current is div2
current is div1
current is div0
current is body
添加以下片段:
1 var div2 = document.getElementById( ' div2 ' );
2 EventUtil.addHandler(div2, ' click ' , function (event){
3 event = EventUtil.getEvent(event);
4 EventUtil.stopPropagation(event);
5 }, false );
current is event_sourcecurrent is div2
当点击红色区域后,根据上面说明,在泡冒泡处理期间,事件传递到div2后被停止传递了,所以div2上层的元素收不到通知,所以会先后出现:
在支持DOM标准的浏览器中,添加以下代码:
1 document.body.addEventListener( ' click ' , function (event){
2 event.stopPropagation();
3 }, true );
以上代码中的监听函数由于是捕获型传递时被调用的,所以点击红色区域后,虽然事件源是ID为event_source的元素,但捕获型选传递,从最顶层开始,body结点监听函数先被调用,并且取消了事件进一步向下传递,所以只会出现 current is body .
7.Doctype作用? 严格模式与混杂模式-如何触发这两种模式,区分它们有何意义?
转载:
https://blog.csdn.net/JsRoccketq/article/details/101222773
doctype是一种标准通用标记语言的文档声明类型,目的是告知要有什么来解析文档。
<!DOCTYPE>
声明是用来指示web浏览器关于页面使用哪个htnl版本进行编写的指令。声明必须是在文档的第一行,在html标签之前。
浏览器本身就分为两种模式,一种是严格模式(标准模式),一种是混杂模式(怪异模式),浏览器就是通过doctype来区分这两种模式的, doctype在html中的作用就是触发浏览器的严格模式,如果省略doctype,浏览器就会进入到混乱模式。
严格模式的排版和要求都是以js运作模式是以该浏览器支持的最高的标准来运行程序的。
混乱模式中,页面以宽松的渐进增强的方式来兼容显示,先以老旧的浏览器的行为来渲染页面。在这种模式下,有些样式会和标准模式存在差异,而在不同的浏览器下,界面的显示也会不同,所以一定要在开头使用doctype。
8.CSS3有哪些新特性?
转载:
https://blog.csdn.net/xiaoxueqiu1987/article/details/77320096?utm_medium=distribute.pc_relevant.none-task-blog-title-1&spm=1001.2101.3001.4242
-
CSS3实现圆角(border-radius),阴影(box-shadow),边框图片border-image
-
对文字加特效(text-shadow、),强制文本换行(word-wrap),线性渐变(linear-gradient)
3.旋转,缩放,定位,倾斜:transform:rotate(90deg) scale(0.85,0.90) translate(0px,-30px) skew(-9deg,0deg);
-
增加了更多的CSS选择器、多背景、rgba();
-
在CSS3中唯一引入的伪元素是 ::selection ;
-
媒体查询(@media),多栏布局(flex)
9.介绍一下你对浏览器内核的理解?
转载:
https://wallhaven.cc/toplist
主要分成两个部分:
渲染引擎(Render Engine)
和JS引擎。
渲染引擎:负责取得网页的内容(html,xml和图像等),整理讯息(例如假如css),以及计算网页的显示方式,然后输出到显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不同。所有网页浏览器、电子邮件客户端以及它需要编辑、显示网络内容的应用程序都需要内核。
JS引擎:解析和执行JavaScript来实现网页的动态效果。
最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向与只指渲染引擎
10.JavaScript的作用域和作用域链
转载:
https://blog.csdn.net/howgod/article/details/88565793
11.浏览器的垃圾回收机制
转载:
https://blog.csdn.net/qq_21428081/article/details/82465801?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param
(1)垃圾回收概述
垃圾回收机制(GC:Garbage Collection),执行环境负责管理代码执行过程中使用的内存。垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。
(2)垃圾回收策略:
2种最为常用:标记清除和引用计数,其中标记清除更为常用。
标记清除(mark-and-sweep):是对于脱离作用域的变量进行回收,当进入作用域时,进行标记,离开作用域时,标记并回收这些变量。到目前为止,IE、Firefox、Opera、Chrome、Safari的js实现使用的都是标记清除的垃圾回收策略或类似的策略,只不过垃圾收集的时间间隔互不相同。
当变量进入环境(例如,在函数中声明一个变量)时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占的内存,因为只要执行流进入相应的环境,就可能用到它们。而当变量离开环境时,这将其 标记为“离开环境”。
引用计数:引用计数是跟踪记录每个值被引用的次数。就是变量的引用次数,被引用一次则加1,当这个引用计数为0时,被视为准备回收的对象,每当过一段时间开始垃圾回收的时候,就把被引用数为0的变量回收。引用计数方法可能导致循环引用,类似死锁,导致内存泄露。
在这个例子中,objA和objB通过各自的属性相互引用;也就是说这两个对象的引用次数都是2。在采用引用计数的策略中,由于函数执行之后,这两个对象都离开了作用域,函数执行完成之后,objA和objB还将会继续存在,因为他们的引用次数永远不会是0。这样的相互引用如果说很大量的存在就会导致大量的内存泄露。
(3)常见内存泄露的原因
全局变量引起的内存泄露
闭包引起的内存泄露:慎用闭包
dom清空或删除时,事件未清除导致的内存泄漏
循环引用带来的内存泄露
(4)如何减少垃圾回收开销
由于每次的垃圾回收开销都相对较大,并且由于机制的一些不完善的地方,可能会导致内存泄露,我们可以利用一些方法减少垃圾回收,并且尽量避免循环引用。
在对象结束使用后 ,令obj = null。这样利于解除循环引用,使得无用变量及时被回收;
js中开辟空间的操作有new(), [ ], { }, function (){…}。最大限度的实现对象的重用;
慎用闭包。闭包容易引起内存泄露。本来在函数返回之后,之前的空间都会被回收。但是由于闭包可能保存着函数内部变量的引用,且闭包在外部环境,就会导致函数内部的变量不能够销毁。
(5)垃圾回收的缺陷
和其他语言一样,javascript的GC策略也无法避免一个问题:GC时,停止响应其他操作,这是为了安全考虑。而Javascript的GC在100ms甚至以上,对一般的应用还好,但对于JS游戏,动画对连贯性要求比较高的应用,就麻烦了。这就是新引擎需要优化的点:避免GC造成的长时间停止响应。
(6)优化GC
分代回收(Generation GC):与Java回收策略思想是一致的。目的是通过区分“临时”与“持久”对象;多回收“临时对象”区(young generation),少回收“持久对象”区(tenured generation),减少每次需遍历的对象,从而减少每次GC的耗时。
增量GC:这个方案的思想很简单,就是“每次处理一点,下次再处理一点,如此类推。
12.vue生命周期
转载:
https://www.cnblogs.com/laohange/p/12825225.html
beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,activated,deactivated,beforeDestory,destoryed
beforeCreate: function() {
console.log('1-beforeCreate 初始化之前');
},
created: function() {
console.log('2-created 创建完成');
},
beforeMount: function() {
console.log('3-beforeMount 挂载之前');
},
mounted: function() {
console.log('4-mounted 被挂载后');
},
beforeUpdate: function() {
console.log('5-beforeUpdate 数据更新前');
},
updated: function() {
console.log('6-updated 被更新后');
},
activated: function() {
console.log('7-activated');
},
deactivated: function() {
console.log('8-deactivated');
},
beforeDestroy: function() {
console.log('9-beforeDestroy 销毁之前');
},
destroyed: function() {
console.log('10-destroyed 销毁之后')
}
13.js数组主要有哪些方法?主要参数有哪些?
转载:
http://www.shouhuola.com/q-25371.html
/数组的方法
toString(),join(),pop(),push(),shift(),unshift(),splice(),concat(),slice()
//1.toString()与join()一样都是把数组转成以逗号分割的字符串
var fruits=['Banana','Orange','Apple']; var foods=['rice']
console.log(fruits.toString()) // Banana,Orange,Apple
console.log(fruits.join()) // Banana,Orange,Apple
//2.pop() 删除数组的最后一项
var fruits=['Banana','Orange','Apple']; var str=fruits.pop(); //str=Apple
console.log(fruits) //['Banana','Orange']
//3.push() 往数组最后添加新数据
var fruits=['Banana','Orange','Apple']; var str=fruits.push('kkk') // str=4 返回的数组的长度
console.log(fruits) //['Banana','Orange','Apple','kkk'];
//4.shift() 删除数组最前面的一项
var fruits = ["Banana", "Orange", "Apple", "Mango"]; var str=fruits.shift(); //str=Banana
console.log(fruits) //["Orange", "Apple", "Mango"];
//5. unshift() 往数组开头添加新数据
var fruits = ["Banana", "Orange", "Apple", "Mango"]; var str=fruits.unshift('ll'); //str=ll
console.log(fruits) //["ll", "Banana", "Orange", "Apple", "Mango"]
//6. splice() 方法可用于向数组添加新项或者删除数组
//新增
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(2, 0, "Lemon", "Kiwi");
console.log( fruits)// ["Banana", "Orange", "Lemon", "Kiwi", "Apple", "Mango"]
//删除
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(2, 1);
console.log(fruits)// ["Banana", "Orange", "Mango"]
//7.concat()连接两个数组生成一个新数组
var fruits= ["Banana", "Orange", "Mango"]; var fruits1=['222'];
console.log(fruits.concat(fruits1)) //["Banana", "Orange", "Mango", "222"]
//8.slice()
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"]; var citrus = fruits.slice(1);
console.log(citrus) // (4) ["Orange", "Lemon", "Apple", "Mango"]
14.null和undefined的区别?
转载:
https://www.cnblogs.com/web-record/p/11151069.html
null表示"没有对象",即该处不应该有值。典型用法是:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
Object.getPrototypeOf(Object.prototype)
// null
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
var i;
i // undefined
function f(x){console.log(x)}
f() // undefined
var o = new Object();
o.p // undefined
var x = f();
x // undefined
上一篇: “逻辑异或”进行数值交换的过程分析
下一篇: 把雨涮都给骂启动了