面试
几个很实用的BOM属性对象方法?
Bom是浏览器对象。
(1)location对象
location.href– 返回或设置当前文档的URL
location.search – 返回URL中的查询字符串部分。例 如http://www.dreamdu.com/dreamdu.php?id=5&name=dreamdu
返回包括(?)后面的内容?id=5&name=dreamdu
location.hash – 返回URL#后面的内容,如果没有#,返回空
location.host – 返回URL中的域名部分,例如[www.dreamdu.com](http://www.dreamdu.com)
location.hostname – 返回URL中的主域名部分,例如dreamdu.com
location.pathname – 返回URL的域名后的部分。例如 http://www.dreamdu.com/xhtml/
返回/xhtml/
location.port – 返回URL中的端口部分。例如 http://www.dreamdu.com:8080/xhtml/
返回8080
location.protocol – 返回URL中的协议部分。例如 http://www.dreamdu.com:8080/xhtml/
返回(//)前面的内容http:
location.assign – 设置当前文档的URL
location.replace() – 设置当前文档的URL,并且在history对象的地址列表中移除这个URL
location.replace(url);
location.reload() – 重载当前页面
(2)history对象
history.go() – 前进或后退指定的页面数 history.go(num);
history.back() – 后退一页
history.forward() – 前进一页
(3)Navigator对象
navigator.userAgent – 返回用户代理头的字符串表示(就是包括浏览器版本信息等的字符串)
navigator.cookieEnabled – 返回浏览器是否支持(启用)cookie
Doctype作用?严格模式与混杂模式如何区分?它们有何意义?
Doctype声明于文档最前面,告诉浏览器以何种方式来渲染页面,这里有两种模式,严格模式和混杂模式。
严格模式的排版和JS 运作模式是 以该浏览器支持的最高标准运行。
混杂模式,向后兼容,模拟老式浏览器,防止浏览器无法兼容页面。
click在ios上有300ms延迟,原因及如何解决?
(1)粗暴型,禁用缩放
< meta name=”viewport” content=”width=device-width, user-scalable=no”>
(2)利用FastClick,其原理是:
检测到touchend事件后,立刻出发模拟click事件,并且把浏览器300毫秒之后真正出发的事件给阻断掉
addEventListener参数
addEventListener(event, function, useCapture)
其中,event指定事件名;function指定要事件触发时执行的函数;useCapture指定事件是否在捕获或冒泡阶段执行。
前端优化
降低请求量:合并资源,减少HTTP 请求数,minify / gzip 压缩,webP,lazyLoad。
加快请求速度:预解析DNS,减少域名数,并行加载,CDN 分发。
缓存:HTTP 协议缓存请求,离线缓存 manifest,离线数据缓存localStorage。
渲染:JS/CSS优化,加载顺序,服务端渲染,pipeline。
GET和POST的区别
get和post是http常见的请求方法,还有很多比如patch、delete、put、options等等
get参数通过url传递,post放在request body中。
get请求在url中传递的参数是有长度限制的,而post没有。
get比post更不安全,因为参数直接暴露在url中,所以不能用来传递敏感信息。
get请求只能进行url编码,而post支持多种编码方式
get请求会浏览器主动cache,而post支持多种编码方式。
get请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留。
GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。
GET产生一个TCP数据包;POST产生两个TCP数据包。
说一下浏览器缓存
缓存分为两种:强缓存和协商缓存,根据响应的header内容来决定。
强缓存相关字段有expires,cache-control。如果cache-control与expires同时存在的话,cache-control的优先级高于expires。
协商缓存相关字段有Last-Modified/If-Modified-Since,Etag/If-None-Match
浏览器在生成页面的时候,会生成那两颗树?
构造两棵树,DOM树和CSSOM规则树.当浏览器接收到服务器相应来的HTML文档后,会遍历文档节点,生成DOM树,CSSOM规则树由浏览器解析CSS文件生成,
怎么看网站的性能如何
检测页面加载时间一般有两种方式,一种是被动去测:就是在被检测的页面置入脚本或探针,当用户访问网页时,探针自动采集数据并传回数据库进行分析,另一种主动监测的方式,即主动的搭建分布式受控环境,模拟用户发起页面访问请求,主动采集性能数据并分析,在检测的精准度上,专业的第三方工具效果更佳,比如说性能极客
浏览器输入网址到页面渲染全过程
DNS解析 TCP连接发送 HTTP请求服务器 处理请求并返回HTTP报文 浏览器解析渲染页面 连接结束
HTML5和CSS3用的多吗?你了解它们的新属性吗?有在项目中用过吗?
html5:
1)标签增删
8个语义元素 header section footer aside nav main article figure
内容元素mark高亮 progress进度
新的表单控件calander date time email url search
新的input类型 color date datetime datetime-local email
移除过时标签big font frame frameset
2)canvas绘图,支持内联SVG。支持MathML
3)多媒体audio video source embed track
4)本地离线存储,把需要离线存储在本地的文件列在一个manifest配置文件
5)web存储。localStorage、SessionStorage
css3:
CSS3边框如border-radius,box-shadow等;CSS3背景如background-size,background-origin等;CSS3 2D,3D转换如transform等;CSS3动画如animation等。
link标签和@import标签的区别
link属于html标签,而@import是css提供的
页面被加载时,link会同时被加载,而@import引用的css会等到页面加载结束后加载。
link是html标签,因此没有兼容性,而@import只有IE5以上才能识别。
link方式样式的权重高于@import的。
transition和animation的区别
animation和transition大部分属性是相同的,他们都是随时间改变元素的属性值,他们的主要区别是transition需要触发一个事件才能改变属性,而animation不需要触发任何事件的情况下才会随时间改变属性值,并且transition为2帧,从from .... to,而animation可以一帧一帧的。
BFC(块级格式化上下文,用于清楚浮动,防止margin重叠等)
直译成:块级格式化上下文,是一个独立的渲染区域,并且有一定的布局规则。
BFC区域不会与float box重叠
BFC是页面上的一个独立容器,子元素不会影响到外面
计算BFC的高度时,浮动元素也会参与计算
那些元素会生成BFC:
根元素
float不为none的元素
position为fixed和absolute的元素
display为inline-block、table-cell、table-caption,flex,inline-flex的元素
overflow不为visible的元素
visibility=hidden, opacity=0,display:none
opacity=0,该元素隐藏起来了,但不会改变页面布局,并且,如果该元素已经绑定一些事件,如click事件,那么点击该区域,也能触发点击事件的visibility=hidden,该元素隐藏起来了,但不会改变页面布局,但是不会触发该元素已经绑定的事件display=none,把元素隐藏起来,并且会改变页面布局,可以理解成在页面中把该元素删除掉一样。
双边距重叠问题(外边距折叠)
多个相邻(兄弟或者父子关系)普通流的块元素垂直方向marigin会重叠
折叠的结果为:
两个相邻的外边距都是正数时,折叠结果是它们两者之间较大的值。
两个相邻的外边距都是负数时,折叠结果是两者绝对值的较大值。
两个外边距一正一负时,折叠结果是两者的相加的和。
position属性 比较
固定定位fixed:
元素的位置相对于浏览器窗口是固定位置,即使窗口是滚动的它也不会移动。Fixed定位使元素的位置与文档流无关,因此不占据空间。 Fixed定位的元素和其他元素重叠。
相对定位relative:
如果对一个元素进行相对定位,它将出现在它所在的位置上。然后,可以通过设置垂直或水平位置,让这个元素“相对于”它的起点进行移动。 在使用相对定位时,无论是否进行移动,元素仍然占据原来的空间。因此,移动元素会导致它覆盖其它框。
绝对定位absolute:
绝对定位的元素的位置相对于最近的已定位父元素,如果元素没有已定位的父元素,那么它的位置相对于<html>。 absolute 定位使元素的位置与文档流无关,因此不占据空间。 absolute 定位的元素和其他元素重叠。
粘性定位sticky:
元素先按照普通文档流定位,然后相对于该元素在流中的flow root(BFC)和 containing block(最近的块级祖先元素)定位。而后,元素定位表现为在跨越特定阈值前为相对定位,之后为固定定位。
默认定位Static:
默认值。没有定位,元素出现在正常的流中(忽略top, bottom, left, right 或者 z-index 声明)。
inherit:
规定应该从父元素继承position 属性的值。
z-index的定位方法
z-index属性设置元素的堆叠顺序,拥有更好堆叠顺序的元素会处于较低顺序元素之前,z-index可以为负,且z-index只能在定位元素上奏效,该属性设置一个定位元素沿z轴的位置,如果为正数,离用户越近,为负数,离用户越远,它的属性值有auto,默认,堆叠顺序与父元素相等,number,inherit,从父元素继承z-index属性的值
line-height和height的区别
line-height一般是指布局里面一段文字上下行之间的高度,是针对字体来设置的,height一般是指容器的整体高度
设置一个元素的背景颜色,背景颜色会填充哪些区域?
background-color设置的背景颜色会填充元素的content、padding、border区域
知道属性选择器和伪类选择器的优先级吗
属性选择器和伪类选择器优先级相同
inline-block、inline和block的区别;为什么img是inline还可以设置宽高
Block是块级元素,其前后都会有换行符,能设置宽度,高度,margin/padding水平垂直方向都有效。
Inline:设置width和height无效,margin在竖直方向上无效,padding在水平方向垂直方向都有效,前后无换行符
Inline-block:能设置宽度高度,margin/padding水平垂直方向 都有效,前后无换行符
overflow的原理
要讲清楚这个解决方案的原理,首先需要了解块格式化上下文,A block formatting context is a part of a visual CSS rendering of a Web page. It is the region in which the layout of block boxes occurs and in which floats interact with each other.翻译过来就是块格式化上下文是CSS可视化渲染的一部分,它是一块区域,规定了内部块盒 的渲染方式,以及浮动相互之间的影响关系
当元素设置了overflow样式且值部位visible时,该元素就构建了一个BFC,BFC在计算高度时,内部浮动元素的高度也要计算在内,也就是说技术BFC区域内只有一个浮动元素,BFC的高度也不会发生塌缩,所以达到了清除浮动的目的
css布局
六种布局方式总结:圣杯布局、双飞翼布局、Flex布局、绝对定位布局、表格布局、网格布局。
圣杯布局是指布局从上到下分为header、container、footer,然后container部分定为三栏布局。这种布局方式同样分为header、container、footer。圣杯布局的缺陷在于 center 是在 container 的padding中的,因此宽度小的时候会出现混乱。
双飞翼布局给center 部分包裹了一个 main 通过设置margin主动地把页面撑开。
Flex布局是由CSS3提供的一种方便的布局方式。
绝对定位布局是给container 设置position: relative和overflow: hidden,因为绝对定位的元素的参照物为第一个postion不为static的祖先元素。 left 向左浮动,right 向右浮动。center 使用绝对定位,通过设置left和right并把两边撑开。 center 设置top: 0和bottom: 0使其高度撑开。
表格布局的好处是能使三栏的高度统一。
网格布局可能是最强大的布局方式了,使用起来极其方便,但目前而言,兼容性并不好。网格布局,可以将页面分割成多个区域,或者用来定义内部元素的大小,位置,图层关系。
说一下闭包
一句话可以概括:闭包就是能够读取其他函数内部变量的函数,或者子函数在外调用,子函数所在的父函数的作用域不会被释放。
(1)什么是闭包: 闭包是指有权访问另外一个函数作用域中的变量的函数。闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。闭包就是就是函数的“堆栈”在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配。当在一个函数内定义另外一个函数就会产生闭包。
(2)为什么要用: 匿名自执行函数:我们知道所有的变量,如果不加上var关键字,则默认的会添加到全局对象的属性上去,这样的临时变量加入全局对象有很多坏处,比如:别的函数可能误用这些变量;造成全局对象过于庞大,影响访问速度(因为变量的取值是需要从原型链上遍历的)。除了每次使用变量都是用var关键字外,我们在实际情况下经常遇到这样一种情况,即有的函数只需要执行一次,其内部变量无需维护,可以用闭包。 结果缓存:我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部的引用,从而函数内部的值可以得以保留。
类的继承和创建
(1)类的创建(es5):new一个function,在这个function的prototype里面增加属性和方法。
下面来创建一个Animal类:
// 定义一个动物类
function Animal (name) {
// 属性
this.name = name || ‘Animal’;
// 实例方法
this.sleep = function(){
console.log(this.name + ‘正在睡觉!’);
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + ‘正在吃:’ + food);
};
这样就生成了一个Animal类,实力化生成对象后,有方法和属性。
(2)类的继承——原型链继承
–原型链继承
1 | function Cat(){ } |
介绍:在这里我们可以看到new了一个空对象,这个空对象指向Animal并且Cat.prototype指向了这个空对象,这种就是基于原型链的继承。
特点:基于原型链,既是父类的实例,也是子类的实例
缺点:无法实现多继承
(3)构造继承:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
1 | function Cat(name){ |
特点:可以实现多继承
缺点:只能继承父类实例的属性和方法,不能继承原型上的属性和方法。
(4)实例继承和拷贝继承
实例继承:为父类实例添加新特性,作为子类实例返回
拷贝继承:拷贝父类元素上的属性和方法
上述两个实用性不强,不一一举例。
(5)组合继承:相当于构造继承和原型链继承的组合体。通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
1 | function Cat(name){ |
特点:可以继承实例属性/方法,也可以继承原型属性/方法
缺点:调用了两次父类构造函数,生成了两份实例
(6)寄生组合继承:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性
1 | function Cat(name){ |
// 创建一个没有实例方法的类
1 | var Super = function(){}; |
//将实例作为子类的原型
1 | Cat.prototype = new Super(); |
较为推荐
说说前端中的事件流
HTML中与javascript交互是通过事件驱动来实现的,例如鼠标点击事件onclick、页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。想要知道这些事件是在什么时候进行调用的,就需要了解一下“事件流”的概念。
什么是事件流:事件流描述的是从页面中接收事件的顺序,DOM2级事件流包括下面几个阶段。
事件捕获阶段
处于目标阶段
事件冒泡阶段
addEventListener:addEventListener 是DOM2 级事件新增的指定事件处理程序的操作,这个方法接收3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。
IE只支持事件冒泡。
如何让事件先冒泡后捕获
在DOM标准事件模型中,是先捕获后冒泡。但是如果要实现先冒泡后捕获的效果,对于同一个事件,监听捕获和冒泡,分别对应相应的处理函数,监听到捕获事件,先暂缓执行,直到冒泡事件被捕获后再执行捕获之间。
说一下事件委托
事件委托指的是,不在事件的发生地(直接dom)上设置监听函数,而是在其父元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的触发,通过判断事件发生元素DOM的类型,来做出不同的响应。
举例:最经典的就是ul和li标签的事件监听,比如我们在添加事件时候,采用事件委托机制,不会在li标签上直接添加,而是在ul父元素上添加。
好处:比较合适动态元素的绑定,新添加的子元素也会有监听函数,也可以有事件触发机制。
mouseover和mouseenter的区别
mouseover:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是mouseout
mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是mouseleave
js的new操作符做了哪些事情
new 操作符新建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象。
改变函数内部this指针的指向函数(bind,apply,call的区别)
通过apply和call改变函数的this指向,他们两个函数的第一个参数都是一样的表示要改变指向的那个对象,第二个参数,apply是数组,而call则是arg1,arg2…这种形式。通过bind改变this作用域会返回一个新的函数,这个函数不会马上执行。
apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法。
call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法。
bind除了返回是函数以外,它的参数和call一样。
js的各种位置,比如clientHeight,scrollHeight,offsetHeight ,以及scrollTop, offsetTop,clientTop的区别?
clientHeight:表示的是可视区域的高度,不包含border和滚动条
offsetHeight:表示可视区域的高度,包含了border和滚动条
scrollHeight:表示了所有区域的高度,包含了因为滚动被隐藏的部分。
clientTop:表示边框border的厚度,在未指定的情况下一般为0
scrollTop:滚动后被隐藏的高度,获取对象相对于由offsetParent属性指定的父坐标(css定位的元素或body元素)距离顶端的高度。
js拖拽功能的实现
首先是三个事件,分别是mousedown,mousemove,mouseup
当鼠标点击按下的时候,需要一个tag标识此时已经按下,可以执行mousemove里面的具体方法。
clientX,clientY标识的是鼠标的坐标,分别标识横坐标和纵坐标,并且我们用offsetX和offsetY来表示元素的元素的初始坐标,移动的举例应该是:
鼠标移动时候的坐标-鼠标按下去时候的坐标。
也就是说定位信息为:
鼠标移动时候的坐标-鼠标按下去时候的坐标+元素初始情况下的offetLeft.
还有一点也是原理性的东西,也就是拖拽的同时是绝对定位,我们改变的是绝对定位条件下的left
以及top等等值。
补充:也可以通过html5的拖放(Drag 和 drop)来实现
JS中的垃圾回收机制
必要性:由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。
这段话解释了为什么需要系统需要垃圾回收,JS不像C/C++,他有自己的一套垃圾回收机制(Garbage Collection)。JavaScript的解释器可以检测到何时程序不再使用一个对象了,当他确定了一个对象是无用的时候,他就知道不再需要这个对象,可以把它所占用的内存释放掉了。例如:
var a=”hello world”;
var b=”world”;
var a=b;
//这时,会释放掉”hello world”,释放内存以便再引用
垃圾回收的方法:标记清除、计数引用。
标记清除
这是最常见的垃圾回收方式,当变量进入环境时,就标记这个变量为”进入环境“,从逻辑上讲,永远不能释放进入环境的变量所占的内存,永远不能释放进入环境变量所占用的内存,只要执行流程进入相应的环境,就可能用到他们。当离开环境时,就标记为离开环境。
垃圾回收器在运行的时候会给存储在内存中的变量都加上标记(所有都加),然后去掉环境变量中的变量,以及被环境变量中的变量所引用的变量(条件性去除标记),删除所有被标记的变量,删除的变量无法在环境变量中被访问所以会被删除,最后垃圾回收器,完成了内存的清除工作,并回收他们所占用的内存。
引用计数法
另一种不太常见的方法就是引用计数法,引用计数法的意思就是每个值没引用的次数,当声明了一个变量,并用一个引用类型的值赋值给改变量,则这个值的引用次数为1,;相反的,如果包含了对这个值引用的变量又取得了另外一个值,则原先的引用值引用次数就减1,当这个值的引用次数为0的时候,说明没有办法再访问这个值了,因此就把所占的内存给回收进来,这样垃圾收集器再次运行的时候,就会释放引用次数为0的这些值。
用引用计数法会存在内存泄露,下面来看原因:
function problem() {
var objA = new Object();
var objB = new Object();
objA.someOtherObject = objB;
objB.anotherObject = objA;
}
在这个例子里面,objA和objB通过各自的属性相互引用,这样的话,两个对象的引用次数都为2,在采用引用计数的策略中,由于函数执行之后,这两个对象都离开了作用域,函数执行完成之后,因为计数不为0,这样的相互引用如果大量存在就会导致内存泄露。
特别是在DOM对象中,也容易存在这种问题:
var element=document.getElementById(’‘);
var myObj=new Object();
myObj.element=element;
element.someObject=myObj;
这样就不会有垃圾回收的过程。
eval是做什么的
它的功能是将对应的字符串解析成js并执行,应该避免使用js,因为非常消耗性能(2次,一次解析成js,一次执行)
如何理解前端模块化
前端模块化就是复杂的文件编程一个一个独立的模块,比如js文件等等,分成独立的模块有利于重用(复用性)和维护(版本迭代),这样会引来模块之间相互依赖的问题,所以有了commonJS规范,AMD,CMD规范等等,以及用于js打包(编译等处理)的工具webpack
对象深度克隆的简单实现
1 | function deepClone(obj){ |
ES5的常用的对象克隆的一种方式。注意数组是对象,但是跟对象又有一定区别,所以我们一开始判断了一些类型,决定newObj是对象还是数组
实现一个once函数,传入函数参数只执行一次
1 | function ones(func){ |
js监听对象属性的改变
我们假设这里有一个user对象,
(1)在ES5中可以通过Object.defineProperty来实现已有属性的监听
Object.defineProperty(user,’name’,{
set:function(key,value){
}
})
缺点:如果id不在user对象中,则不能监听id的变化
(2)在ES6中可以通过Proxy来实现
var user = new Proxy({},{
set:function(target,key,value,receiver){
}
})
这样即使有属性在user中不存在,通过user.id来定义也同样可以这样监听这个属性的变化哦~
如何实现一个私有变量,用getName方法可以访问,不能直接访问
(1)通过defineProperty来实现
obj={
name:yuxiaoliang,
getName:function(){
return this.name
}
}
object.defineProperty(obj,”name”,{
//不可枚举不可配置
});
(2)通过函数的创建形式
function product(){
var name=’yuxiaoliang’;
this.getName=function(){
return name;
}
}
var obj=new product();
==
和===
、以及Object.is的区别
(1)==
主要存在:强制转换成number,null==undefined
1 | " "==0 //true |
(2)Object.js
主要的区别就是+0!=-0
而NaN==NaN
(相对比===
和==
的改进)
setTimeout、setInterval和requestAnimationFrame之间的区别
这里有一篇文章讲的是requestAnimationFrame:http://www.cnblogs.com/xiaohuochai/p/5777186.html
与setTimeout和setInterval不同,requestAnimationFrame不需要设置时间间隔,
大多数电脑显示器的刷新频率是60Hz,大概相当于每秒钟重绘60次。大多数浏览器都会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验也不会有提升。因此,最平滑动画的最佳循环间隔是1000ms/60,约等于16.6ms。
RAF采用的是系统时间间隔,不会因为前面的任务,不会影响RAF,但是如果前面的任务多的话,
会响应setTimeout和setInterval真正运行时的时间间隔。
特点:
(1)requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率。
(2)在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量
(3)requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销。
实现一个两列等高布局,讲讲思路
为了实现两列等高,可以给每列加上 padding-bottom:9999px;
margin-bottom:-9999px;同时父元素设置overflow:hidden;
this的指向 哪几种
默认绑定:全局环境中,this默认绑定到window。
隐式绑定:一般地,被直接对象所包含的函数调用时,也称为方法调用,this隐式绑定到该直接对象。
隐式丢失:隐式丢失是指被隐式绑定的函数丢失绑定对象,从而默认绑定到window。显式绑定:通过call()、apply()、bind()方法把对象绑定到this上,叫做显式绑定。
new绑定:如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。对于this绑定来说,称为new绑定。
【1】构造函数通常不使用return关键字,它们通常初始化新对象,当构造函数的函数体执行完毕时,它会显式返回。在这种情况下,构造函数调用表达式的计算结果就是这个新对象的值。
【2】如果构造函数使用return语句但没有指定返回值,或者返回一个原始值,那么这时将忽略返回值,同时使用这个新对象作为调用结果。
【3】如果构造函数显式地使用return语句返回一个对象,那么调用表达式的值就是这个对象。
数组移除第一个元素的方法
splice和shift方法
事件委托
把一个元素响应事件(click、keydown……)的函数委托到另一个元素;
优点:减少内存消耗、动态绑定事件。
dom是什么,你的理解?
文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标志语言的标准编程接口。在网页上,组织页面(或文档)的对象被组织在一个树形结构中,用来表示文档中对象的标准模型就称为DOM。
事件代理
事件代理是利用事件的冒泡原理来实现的,何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件,举个例子:页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件代理,代理它们父级代为执行事件。 事件代理/事件委托:利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的事件, 简而言之:事件代理就是说我们将事件添加到本来要添加的事件的父节点,将事件委托给父节点来触发处理函数,这通常会使用在大量的同级元素需要添加同一类事件的时候,比如一个动态的非常多的列表,需要为每个列表项都添加点击事件,这时就可以使用事件代理,通过判断e.target.nodeName来判断发生的具体元素,这样做的好处是减少事件绑定,同事动态的DOM结构任然可以监听,事件代理发生在冒泡阶段
箭头函数和function的区别
箭头函数根本就没有绑定自己的this,在箭头函数中调用 this 时,仅仅是简单的沿着作用域链向上寻找,找到最近的一个 this 拿来使用
arguments
arguments是类数组对象,有length属性,不能调用数组方法
可用Array.from()转换
箭头函数获取arguments
可用…rest参数获取
数组去重
法一:indexOf循环去重
法二:ES6 Set去重;Array.from(new Set(array))
法三:Object 键值对去重;把数组的值存成 Object 的 key 值,比如 Object[value1] = true,在判断另一个值的时候,如果 Object[value2]存在的话,就说明该值是重复的。
es6的常用
promise,await/async,let,const,块级作用域,箭头函数
引用类型常见的对象
Object、Array、RegExp、Date、Function、特殊的基本包装类型(String、Number、Boolean)以及单体内置对象(Global、Math)等
JS的数据类型
字符串,数字,布尔,数组,null,Undefined,symbol,对象。
JavaScript中的轮播实现原理?假如一个页面上有两个轮播,你会怎么实现?
图片轮播的原理就是图片排成一行,然后准备一个只有一张图片大小的容器,对这个容器设置超出部分隐藏,在控制定时器来让这些图片整体左移或右移,这样呈现出来的效果就是图片在轮播了。
如果有两个轮播,可封装一个轮播组件,供两处调用
js对象类型,基本对象类型以及引用对象类型的区别
分为基本对象类型和引用对象类型
基本数据类型:按值访问,可操作保存在变量中的实际的值。基本类型值指的是简单的数据段。基本数据类型有这六种:undefined、null、string、number、boolean、symbol。
引用类型:当复制保存着对象的某个变量时,操作的是对象的引用,但在为对象添加属性时,操作的是实际的对象。引用类型值指那些可能为多个值构成的对象。
引用类型有这几种:Object、Array、RegExp、Date、Function、特殊的基本包装类型(String、Number、Boolean)以及单体内置对象(Global、Math)。
js加载过程阻塞,解决方法。
指定script标签的async属性。
如果async=”async”,脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行)
如果不使用async 且 defer=”defer”:脚本将在页面完成解析时执行
private和public
public:public表明该数据成员、成员函数是对所有用户开放的,所有用户都可以直接进行调用
private:private表示私有,私有的意思就是除了class自己之外,任何人都不可以直接使用
怎么获得对象上的属性:比如说通过Object.key()
从ES5开始,有三种方法可以列出对象的属性
for(let I in obj)该方法依次访问一个对象及其原型链中所有可枚举的类型
object.keys:返回一个数组,包括所有可枚举的属性名称
object.getOwnPropertyNames:返回一个数组包含不可枚举的属性
js原型链,原型链的顶端是什么?Object的原型是什么?Object的原型的原型是什么?在数组原型链上实现删除数组重复数据的方法
能够把这个讲清楚弄明白是一件很困难的事,
首先明白原型是什么,在ES6之前,JS没有类和继承的概念,JS是通过原型来实现继承的,在JS中一个构造函数默认带有一个prototype属性,这个的属性值是一个对象,同时这个prototype对象自带有一个constructor属性,这个属性指向这个构造函数,同时每一个实例都会有一个proto_属性指向这个prototype对象,我们可以把这个叫做隐式原型,我们在使用一个实例的方法的时候,会先检查这个实例中是否有这个方法,没有的话就会检查这个prototype对象是否有这个方法,
基于这个规则,如果让原型对象指向另一个类型的实例,即constructor1.protoytpe=instance2,这时候如果试图引用constructor1构造的实例instance1的某个属性p1,
首先会在instance1内部属性中找一遍,
接着会在instance1._proto_(constructor1.prototype)即是instance2中寻找p1
搜寻轨迹:instance1->instance2->constructor2.prototype……->Object.prototype;这即是原型链,原型链顶端是Object.prototype
补充学习:
每个函数都有一个prototype属性,这个属性指向了一个对象,这个对象正是调用该函数而创建的实例的原型,那么什么是原型呢,可以这样理解,每一个JavaScript对象在创建的时候就会预制管理另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型继承属性,如图:
那么怎么表示实例与实例原型的关系呢,这时候就要用到第二个属性_proto
这是每一个JS对象都会有的一个属性,指向这个对象的原型,如图:
既然实例对象和构造函数都可以指向原型,那么原型是否有属性指向构造函数或者实例呢,指向实例是没有的,因为一个构造函数可以生成多个实例,但是原型有属性可以直接指向构造函数,通过constructor即可
接下来讲解实例和原型的关系:
当读取实例的属性时,如果找不到,就会查找与对象相关的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层,那么原型的原型是什么呢,首先,原型也是一个对象,既然是对象,我们就可以通过构造函数的方式创建它,所以原型对象就是通过Object构造函数生成的,如图:
那么Object.prototype的原型呢,我们可以打印console.log(Object.prototype.proto === null),返回true
null表示没有对象,即该处不应有值,所以Object.prototype没有原型,如图:
图中这条蓝色的线即是原型链,
最后补充三点:
constructor:
function Person(){
}
var person = new Person();
console.log(Person === person.constructor);
原本person中没有constructor属性,当不能读取到constructor属性时,会从person的原型中读取,所以指向构造函数Person
proto:
绝大部分浏览器支持这个非标准的方法访问原型,然而它并不存在与Person.prototype中,实际上它来自Object.prototype,当使用obj.proto时,可以理解为返回来Object.getPrototype(obj)
继承:
前面说到,每个对象都会从原型继承属性,但是引用《你不知道的JS》中的话,继承意味着复制操作,然而JS默认不会复制对象的属性,相反,JS只是在两个对象之间创建一个关联,这样子一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,叫委托更合适
let const var的区别 ,什么是块级作用域,如何用ES5的方法实现块级作用域(立即执行函数),ES6 呢
提起这三个最明显的区别是var声明的变量是全局或者整个函数块的,而let,const声明的变量是块级的变量,var声明的变量存在变量提升,let,const不存在,let声明的变量允许重新赋值,const不允许
JS中string的startwith和indexof两种方法的区别
JS中startwith函数,其参数有3个,stringObj,要搜索的字符串对象,str,搜索的字符串,position,可选,从哪个位置开始搜索,如果以position开始的字符串以搜索字符串开头,则返回true,否则返回false
Indexof函数,indexof函数可返回某个指定字符串在字符串中首次出现的位置
有了解过事件模型吗,DOM0级和DOM2级有什么区别,DOM的分级是什么
JSDOM事件流存在如下三个阶段:
事件捕获阶段
处于目标阶段
事件冒泡阶段
JSDOM标准事件流的触发的先后顺序为:先捕获再冒泡,点击DOM节点时,事件传播顺序:事件捕获阶段,从上往下传播,然后到达事件目标节点,最后是冒泡阶段,从下往上传播
DOM节点添加事件监听方法addEventListener,中参数capture可以指定该监听是添加在事件捕获阶段还是事件冒泡阶段,为false是事件冒泡,为true是事件捕获,并非所有的事件都支持冒泡,比如focus,blur等等,我们可以通过event.bubbles来判断
事件模型有三个常用方法:
event.stopPropagation:阻止捕获和冒泡阶段中,当前事件的进一步传播,
event.stopImmediatePropagetion,阻止调用相同事件的其他侦听器,
event.preventDefault,取消该事件(假如事件是可取消的)而不停止事件的进一步传播,
event.target:指向触发事件的元素,在事件冒泡过程中这个值不变
event.currentTarget = this,时间帮顶的当前元素,只有被点击时目标元素的target才会等于currentTarget,
最后,对于执行顺序的问题,如果DOM节点同时绑定了两个事件监听函数,一个用于捕获,一个用于冒泡,那么两个事件的执行顺序真的是先捕获在冒泡吗,答案是否定的,绑定在被点击元素的事件是按照代码添加顺序执行的,其他函数是先捕获再冒泡
setTimeout(fn,100);100毫秒是如何权衡的
etTimeout()函数只是将事件插入了任务列表,必须等到当前代码执行完,主线程才会去执行它指定的回调函数,有可能要等很久,所以没有办法保证回调函数一定会在setTimeout指定的时间内执行,100毫秒是插入队列的时间+等待的时间
深浅拷贝的区别和实现
数组的浅拷贝:
如果是数组,我们可以利用数组的一些方法,比如slice,concat方法返回一个新数组的特性来实现拷贝,但假如数组嵌套了对象或者数组的话,使用concat方法克隆并不完整,如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或数组,就会只拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化,我们把这种复制引用的拷贝方法称为浅拷贝,
深拷贝就是指完全的拷贝一个对象,即使嵌套了对象,两者也互相分离,修改一个对象的属性,不会影响另一个
如何深拷贝一个数组
1、这里介绍一个技巧,不仅适用于数组还适用于对象!那就是:
1 | var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}] |
原理是JOSN对象中的stringify可以把一个js对象序列化为一个JSON字符串,parse可以把JSON字符串反序列化为一个js对象,通过这两个方法,也可以实现对象的深复制。
但是这个方法不能够拷贝函数
浅拷贝的实现:
以上三个方法concat,slice ,JSON.stringify都是技巧类,根据实际项目情况选择使用,我们可以思考下如何实现一个对象或数组的浅拷贝,遍历对象,然后把属性和属性值都放在一个新的对象里即可
1 | var shallowCopy = function(obj) { |
深拷贝的实现
那如何实现一个深拷贝呢?说起来也好简单,我们在拷贝的时候判断一下属性值的类型,如果是对象,我们递归调用深拷贝函数不就好了~
1 | var deepCopy = function(obj) { |
不同数据类型的值的比较,是怎么转换的,有什么规则
去除字符串首尾空格
使用正则(^\s)|(\s$)即可
如何判断一个数组(讲到typeof差点掉坑里)
instanceof
Object.prototype.call.toString()
数组常用方法
push(),pop(),shift(),unshift(),splice(),sort(),reverse(),map()等