前端面试经

1 ,sessionStorage 、localStorage 和 cookie 之间的区别

共同点:用于浏览器端存储的缓存数据

不同点:

(1)、存储内容是否发送到服务器端:当设置了Cookie后,数据会发送到服务器端,造成一定的宽带浪费;web storage,会将数据保存到本地,不会造成宽带浪费;

(2)、数据存储大小不同:Cookie数据不能超过4K,适用于会话标识;web storage数据存储可以达到5M;

(3)、数据存储的有效期限不同:cookie只在设置了Cookid过期时间之前一直有效,即使关闭窗口或者浏览器;sessionStorage,仅在关闭浏览器之前有效;localStorage,数据存储永久有效;

(4)、作用域不同:cookie和localStorage是在同源同窗口中都是共享的;sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;

Web Storage与Cookie相比存在的优势:

(1)、存储空间更大:IE8下每个独立的存储空间为10M,其他浏览器实现略有不同,但都比Cookie要大很多。

(2)、存储内容不会发送到服务器:当设置了Cookie后,Cookie的内容会随着请求一并发送的服务器,这对于本地存储的数据是一种带宽浪费。而WebStorage中的数据则仅仅是存在本地,不会与服务器发生任何交互。

(3)、更多丰富易用的接口:Web Storage提供了一套更为丰富的接口,如setItem,getItem,removeItem,clear等,使得数据操作更为简便。cookie需要自己封装。

(4)、独立的存储空间:每个域(包括子域)有独立的存储空间,各个存储空间是完全独立的,因此不会造成数据混乱。

2.position的absolute与fixed共同点与不同点

(1)、static(静态定位):默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)。

(2)、relative(相对定位):生成相对定位的元素,通过top,bottom,left,right的设置相对于其正常(原先本身)位置进行定位。可通过z-index进行层次分级。

(3)、absolute(绝对定位):生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。可通过z-index进行层次分级。

(4)、fixed(固定定位):生成绝对定位的元素,相对于浏览器窗口进行定位。元素的位置通过"left", "top", "right" 以及 "bottom" 属性进行规定。可通过z-index进行层次分级。

absolute和fixed的相同点:都会脱离文档流

不同点:absolute相对是第一个有定位的祖元素进行定位,fixed相对于浏览器进行定位。在有滚动条的页面中,absolute会跟着祖元素进行移动,fixed固定在页面的具体位置。

3.数组方法的扩展

数组方法的扩展,如map,reduce,fliter,forEach,indexOf方法

(1)、map(function(element))

与forEach类似,遍历数组,回调函数返回值组成一个新数组返回,新数组索引结构和原数组一致,原数组不变.

var a = [1, 2, 3, 4, 5, 6]

console.log(a.map(function(e){

return e + e

})) // [1, 4, 6, 8, 10, 12]

console.log(a) //[1, 2, 3, 4, 5, 6]

(2)、reduce(function(v1, v2), value) / reduceRight(function(v1, v2), value)

遍历数组,调用回调函数,将数组元素组合成一个值,reduce从索引最小值开始,reduceRight反向,方法有两个参数

回调函数:把两个值合为一个,返回结果

value,一个初始值,可选

var a = [1, 2, 3, 4, 5, 6]

var b = a.reduce(function(v1, v2){

return v1 + v2

})

console.log(a) // 21

var b = a.reduceRight(function(v1, v2){

return v1 - v2

}, 100)

console.log(b) // 79

(3)、filter(function(element))

返回数组的一个子集,回调函数用于逻辑判断是否返回,返回true则把当前元素加入到返回数组中,false则不加

新数组只包含返回true的值,索引缺失的不包括,原数组保持不变

var a = [1, 2, 3, 4, 5, 6]

console.log(a.filter(function(e){

return e > 3;

})) // [4, 5, 6]

console.log(a) //[1, 2, 3, 4, 5, 6]

(4)、forEach(element, index, array)

遍历数组,参数为一个回调函数,回调函数有三个参数:

当前元素

当前元素索引值

整个数组

var arr = new Array(1, 2, 3, 4);

arr.forEach(function(e,i,array){

array[i]= e + 1; //每项加1

});

console.log(arr); //[2, 3, 4, 5,]

(5)、.indexOf(element) / .lastIndexOf(element)

这两个方法用于查找数组内指定元素位置,查找到第一个后返回其索引,没有查找到返回-1,indexOf从头至尾搜索,lastIndexOf反向搜索

var a = [1,2,3,6,2,7,4]

console.log(a.indexOf(2)) // 1 正数第一个2

console.log(a.indexOf(8)) //-1 数组中没有那个元素

console.log(a.lastIndexOf(2)) // 4 倒数第一个2

console.log(a.lastIndexOf(8)) //-1 数组中没有那个元素

4.如何用原生js给一个按钮绑定两个onclick事件?

Var btn=document.getElementById(‘btn’);

//事件监听 绑定多个事件 

var btn4 = document.getElementById("btn4");

btn4.addEventListener("click",hello1);

btn4.addEventListener("click",hello2);

function hello1(){

alert("hello 1");

}

function hello2(){

alert("hello 2"); 

}  

5,原生Js事件绑定的三种方式

(1)、html标签事件绑定:属性赋值 ,这个在该元素的properties属性中可以查到, 也可以在事件监听中看到

function show(){  console.log('show');}

function print(){  console.log('print');}

<button onclick="show()" id="btn1" onclick="print()">html标签事件绑定</button>//触发的方法只有show方法

<button onclick="show();print()" id="btn1">html标签事件绑定</button>//一个事件,触发两个方法 

(2)、js事件绑定:属性赋值,这个在该元素的properties属性中可以查到,也可以在事件监听中看到

<button id="btn2">js事件绑定</button> 

document.getElementById("btn2").onclick = show;

document.getElementById("btn2").onclick = print;

//只能触发print方法,如果需要同时触发两个方法,只能使用事件监听

(3)、事件监听:只可以在该元素的事件监听中看到

<button id="btn3">事件监听</button> //show和print两个方法都可以触发document.getElementById("btn3").addEventListener("click",show);document.getElementById("btn3").addEventListener("click",print);//移除事件监听document.getElementById("btn3").removeEventListener("click");

6.关于事件冒泡、事件捕获和事件委托

事件冒泡:会从当前触发的事件目标一级一级往上传递,依次触发,直到document为止。

事件捕获:会从document开始触发,一级一级往下传递,依次触发,直到真正事件目标为止。

事件委托:是基于事件冒泡的,本来需要给子元素添加的事件转移到父元素上面,然后判断操作的是哪一个子元素进行相应的操作。

(注意

非IE下的目标元素获取采用 ***event.target***方法获取。IE下的目标元素获取采用***window.event.srcElement***方法获取

)

补充:关于js的浏览器兼容问题,一般用能力检测来解决,if(){}else{}

我们平时工作一般都是用jquery,IE这些特殊情况早就帮我们做好兼容啦。

jquery在1.7的版本之后,最流行的事件监听方法是$(元素).on(事件名,执行函数),它还有一种事件委托的写法$(委托给哪个元素).on(事件名,被委托的元素,执行函数

最后说一点,如果元素被阻止冒泡了,千万别去用事件委托的方式监听事件,因为事件委托的原理是利用事件冒泡,当冒泡被阻止,就无法监听了。

7.请说出三种减少页面加载时间的方法

(1)、 尽量减少页面中重复的HTTP请求数量

比较直接的理解就是要减少调用其他页面、文件的数量。我们在使用css格式控制的时候,经常会采用background载入很多图形文件,而每个background的图像都会产生1次HTTP请求,一般我们为了让页面生动活泼会大量使用background来加载背景图,要改善这个状况,可以采用css的1个有用的background-position属 性来加载背景图,我们将需要频繁加载的多个图片合成为1个单独的图片,需要加载时可以采用:background:url(....) no-repeat x-offset y-offset;的形式加载即可将这部分图片加载的HTTP请求缩减为1个。

(2)、 服务器开启gzip压缩

即将需要传输的内容压缩后传输到客户端再解压,这样在网络上传输的 数据量就会大幅减小。通常在服务器上的Apache、Nginx可以直接开启这个设置,也可以从代码角度直接设置传输文件头,增加gzip的设置,也可以从 负载均衡设备直接设置。不过需要留意的是,这个设置会略微增加服务器的负担。建议服务器性能不是很好的网站,要慎重考虑。

(3)、. css样式的定义放置在文件头部

(4)、. Javascript脚本放在文件末尾

我们都知道网页文件的载人是从上到下的加载的,而有很多Javascript脚本执行效率比较低下,或者在网页前面都不需要执行的,如果将这些脚本放置到页面比较靠前的位置,很可能会导致网站内容载入速度下降甚至无**常加载,所以一般将这些脚本放置在网页文件末尾,一定要放 置在前面的脚本要改用所谓的“后载入”方式加载,在主体网页加载完成后再加载,防止其影响到主体网页的加载速度。

(5)、 压缩Javascript、CSS代码

一般js、css文件中存在大量的空格、换行、注释,这些利于阅读,如果能够压缩掉,将会很有利于网络传输。这方面的工具也有很多,可以在百度里搜索一下关键字“css代码压缩”,或者“js代码压缩”将会发现有很多网站都提供这样的功能,当然了你也可以自己写程序来做这个工作,如果你会的话。就拿我们这个网站来说吧。刚开始上传这个网站的时候,我的很多Css代码都没有压缩,后面发现了这个问题,我就上网找了相关的网站的压缩代码的功能,最后就把很多CSS文件都压缩了。这个压缩比率还是比较高的,一般都有50%左右。由此可见,这个代码压缩对于网页的加载还是很有用的。

(6)、 Ajax采用缓存调用

Ajax调用都采用缓存调用方式,一般采用附加特征参数方式实现,注意其中的<script src=”xxx.js?{VERHASH}”,{VERHASH}就是特征参数,这个参数不变化就使用缓存文件,如果发生变化则重新下载新文件或更新信息。

(7)、 尽可能减少DCOM元素

这个很好理解,就是尽可能减少网页中各种<>元素数量,例如<table>的冗余很严重,而我们完全可以用<div>取代之。

(8)、. 使用多域名负载网页内的多个文件、图片

(9)、 使用CDN

(10)、 在服务器端配置control-cache  last-modify-date

(11)、.在服务器配置Entity-Tag     if-none-match

8.css伪类和伪元素的区别、优先级

(1)、伪类选择器

伪类通过冒号(:)进行定义,它定义了元素的状态,如点击按下、点击完等。以前都是直接操作元素的样式,现在可为元素的状态改样式,看上去更“动态”。

伪类一般反映无法在CSS中轻松或可靠检测到的某个元素的状态或属性。

伪类更多地是定义元素的状态。

伪类选择器:1)E:link  2)E:visited  3)E:hover  4)E:active  5)E:not(S) 匹配不包含S的E元素  6)E:first-child  7)E:last-child  8)E:only-child  9)E:empty  10)E:checked  11)E:nth-child(n)

(2)、伪类选择器

伪元素选择器

伪对象即伪元素,表示DOM外部的某种文档结构。

伪元素改变文档结构,在结构外另加一个没有实际存在的元素(即伪元素)。

常用伪元素:1)E:before/E::before  2)E:after/E::after

9.input有哪些新类型

常用的并且能为大多数浏览器所识别的类型大概有:text、password、number、button、reset、submit、hidden、radio、checkbox、file、image、color、range、date、month、week、time、datetime-local。

另外还有一些类型:tel、email、url、datetime、search。这些类型部分浏览器不支持识别或校验。

10.怎样在css文件中导入另一个css文件

@import url(style.css)css的路径要和本来css路径一致,如果不是在同一目录下,那么就在url后面写入相应的路径了

11.jquery九大选择器的用法举例

12.js创建类(封装)

13.let const var比较

(1)、 let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

{

    let a =10;

    var b= 8;

}

console.log(a);//ReferenceError: a is not defined(let声明的变量只在当前代码块内有效)

console.log(b);//1

(2)、不存在变量提升

对比:var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined

// var 的情况

console.log(a); // 输出undefined

var a = 2;

// let 的情况

console.log(b); // 报错ReferenceError

let b = 2;

(3)、不允许重复声明

let不允许在相同作用域内,重复声明同一个变量。

(4)、暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。在代码块内,使用let命令声明变量之前,该变量都是不可用的。

这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

var tmp = 888;

if (true) {

  tmp = 'abc'; // ReferenceError

  let tmp;

}

说明: 由于存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,同一个作用域内,不能重复声明同一个变量,所以在let声明前,对tmp进行赋值则报错

const

(1)、 const声明一个只读的常量。一旦声明,常量的值就不能改变。

14.箭头函数与普通函数有什么区别

(1). 箭头函数this为父作用域的this,不是调用时的this

  (2). 箭头函数不能作为构造函数,不能使用new

  (3).箭头函数没有arguments,caller,callee

  (4).箭头函数通过call和apply调用,不会改变this指向,只会传入参数

  (5). 箭头函数没有原型属性

  (6). 箭头函数不能作为Generator函数,不能使用yield关键字

(7). 箭头函数返回对象时,要加一个小括号

(8). 箭头函数在ES6 class中声明的方法为实例方法,不是原型方法

(9). 多重箭头函数就是一个高阶函数,相当于内嵌函数

const add = x => y => y + x;

//相当于

function add(x){

  return function(y){

    return y + x;

  };

}

15.如何判断this?箭头函数的this是什么

this的绑定规则有四种:默认绑定,隐式绑定,显式绑定,new绑定 。

   (1)、 函数是否在 new 中调用(new绑定),如果是,那么 this 绑定的是新创建的对象。

   (2)、 函数是否通过 call,apply 调用,或者使用了 bind (即显示绑定),如果是,那么this绑定的就是指定的对象。

   (3)、 函数是否在某个上下文对象中调用(隐式绑定),如果是的话,this 绑定的是那个上下文对象。一般是 obj.foo()

  (4)、  如果以上都不是,那么使用默认绑定。如果在严格模式下,则绑定到 undefined,否则绑定到全局对象。

   (5)、 如果把 null 或者 undefined 作为 this 的绑定对象传入 call、apply 或者 bind, 这些值在调用时会被忽略,实际应用的是默认绑定规则。

 (6)、   箭头函数没有自己的 this, 它的this继承于上一层代码块的this。

16. typeof()和instanceof()的用法区别

相同点:JavaScript 中 typeof 和 instanceof 常用来判断一个变量是否为空,或者是什么类型的。

    typeof的定义和用法:返回值是一个字符串,用来说明变量的数据类型。

    (1)、typeof 一般只能返回如下几个结果:number,boolean,string,function,object,undefined。

    (2)、typeof 来获取一个变量是否存在,如 if(typeof a!="undefined"){alert("ok")},而不要去使用 if(a) 因为如果 a 不存在(未声明)则会出错。

    (3)、对于 Array,Null 等特殊对象使用 typeof 一律返回 object,这正是 typeof 的局限性。

    Instanceof定义和用法:instanceof 用于判断一个变量是否属于某个对象的实例。

    实例演示:

    a instanceof b?alert("true"):alert("false"); //a是b的实例?真:假

    var a = new Array();

    alert(a instanceof Array);  // true

    alert(a instanceof Object)  // true

    如上,会返回 true,同时 alert(a instanceof Object) 也会返回 true;这是因为 Array 是 object 的子类。

    function test(){};

    var a = new test();

    alert(a instanceof test)  // true

    细节:

    (1)、如下,得到的结果为‘N’,这里的 instanceof 测试的 object 是指 js 语法中的 object,不是指 dom 模型对象。

    if (window instanceof Object){ alert('Y')} else {  alert('N');}  // 'N'

17. ES6新的特性有哪些?

(1)、不一样的变量声明:const和let

   (2)、模板字符串

   (3)、.箭头函数(Arrow Functions)

     (4)、 函数的参数默认值

    (5)、Spread / Rest 操作符

     (6)、二进制和八进制字面量

   (7)、.对象和数组解构

    (8)、对象超类

   (9)、for...of 和 for...in

 (10)、.ES6中的类(ES6 中支持 class 语法,不过,ES6的class不是新的对象继承模型,它只是原型链的语法糖表现形式。)

18.深拷贝和浅拷贝的区别?如何实现

两者的区别:一个对象浅复制后,是深层次的对象地址的复制,并没有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,

    则另一个对象的属性也会发生改变,而深复制的则是开辟了一个新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。

    如何实现深拷贝

     (1)、 JSON.stringify()

    缺点: JSON.stringify()无法正确处理函数

   (2)、递归实现深拷贝(jquery 提供一个$.extend可以用来做深拷贝;)

19.说一下JS中类型转换的规则?

toString() // 返回对象的字符串表示形式

    valueOf()  // 返回对象的数字表示形式

20.原始类型有哪几种?null是对象吗?

原始类型:undefined、null、string、number、boolean、symbol(es6新增)

    null其实并不是一个对象,尽管typeof null 输出的是object,但是这其实是一个bug。

    在js最初的版本中使用的是32位系统,为了性能考虑地位存储变量的类型信息,000开头表示为对象类型,然而null为全0,故而null被判断为对象类型。

数据封装类对象:String,Boolean,Number,Array,和Object;

    其他对象:Function,Arguments,Math,Date,RegExp,Error

数据类型:null、undefined、number、boolean、string

21.简述同步和异步的区别

同步是阻塞模式,异步是非阻塞模式。

同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;

异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。

22.box-sizing常用的属性有哪些?分别有什么作用?

属性值box-sizing: content-box|border-box|inherit;

(1)、content-box

 这是box-sizing的默认属性值

· 是CSS2.1中规定的宽度高度的显示行为

· 在CSS中定义的宽度和高度就对应到元素的内容框

· 在CSS中定义的宽度和高度之外绘制元素的内边距和边框

(2)、border-box

· 在CSS中微元素设定的宽度和高度就决定了元素的边框盒

· 即为元素在设置内边距和边框是在已经设定好的宽度和高度之内进行绘制

· CSS中设定的宽度和高度减去边框和内间距才能得到元素内容所占的实际宽度和高度

(Q2)content-box:宽度和高度分别应用到元素的内容框。在宽度和高度之外绘制元素的内边距和边框(元素默认效果)。

border-box:元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制。通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度。

23.px和em的区别

px表示像素 (计算机屏幕上的一个点:1px = 1/96in),是绝对单位,不会因为其他元素的尺寸变化而变化;

em表示相对于父元素的字体大小。em是相对单位 ,没有一个固定的度量值,而是由其他元素尺寸来决定的相对值。

23.清楚浮动的方法

1)父级div定义height。

2)结尾处加空div标签clear:both。

3)父级div定义伪类:after和zoom。

4)父级div定义overflow:hidden。

5)父级div定义overflow:auto。

6)父级div也浮动,需要定义宽度。

7)父级div定义display:table。

8)结尾处加br标签clear:both。

9.) 比较好的是第3种方式,好多网站都这么用。

1 .父级div定义height

原理:父级div手动定义height,就解决了父级div无法自动获取到高度的问题。

优点:简单、代码少、容易掌握。

缺点:只适合高度固定的布局,要给出精确的高度,如果高度和父级div不一样

时,会产生问题。

2,结尾处加空div标签clear:both。

原理:添加一个空div,利用css提高的clear:both清除浮动,让父级div能自动获取到高度。

优点:简单、代码少、浏览器支持好、不容易出现怪问题。

缺点:不少初学者不理解原理;如果页面浮动布局多,就要增加很多空div,让人感觉很不好

3,父级div定义 伪类:after 和zoom

原理:IE8以上和非IE浏览器才支持:after,原理和方法2有点类似,zoom(IE转有属性)可解决ie6,ie7浮动问题 。

优点:浏览器支持好、不容易出现怪问题(目前:大型网站都有使用,如:腾迅,网易,新浪等等)。

缺点:代码多、不少初学者不理解原理,要两句代码结合使用才能让主流浏览器都支持。

4,父级div定义overflow:hidden

原理:必须定义width或zoom:1,同时不能定义height,使用overflow:hidden时,浏览器会自动检查浮动区域的高度。

优点:简单、代码少、浏览器支持好。

缺点:不能和position配合使用,因为超出的尺寸的会被隐藏。

24.eval是做什么的?

它的功能是把对应的字符串解析成JS代码并运行;

应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)。

由JSON字符串转换为JSON对象的时候可以用eval,var obj =eval('('+ str +')')。

25.DOM怎样添加、移除、移动、复制、创建和查找节点

(1)、创建节点、追加节点

1、createElement(标签名)创建一个元素节点(具体的一个元素)。

2、appendChild(节点)追加一个节点。

3、createTextNode(节点文本内容)创建一个文本节点

        var oDiv = document.createElement("div");//创建一个div元素,因为是document对象的方法。

var oDivText = document.createTextNode("666");//创建一个文本节点内容是“666”,因为是document对象的方法。

oDiv.appendChild(oDivText);//父级.appendChild(子节点);在div元素中添加“666”

document.body.appendChild(oDiv);//父级.appendChild(子节点);;document.body是指向<body>元素

document.documentElement.appendChild(createNode);//父级.appendChild(子节点);;document.documentElement是指向<html>元素

(2)、插入节点

1、appendChild(节点)也是一种插入节点的方式,还可以添加已经存在的元素,会将其元素从原来的位置移到新的位置。

2、insertBefore(a,b)是参照节点,意思是a节点会插入b节点的前面。

        var oDiv = document.createElement("div");//创建一个div元素,因为是document对象的方法。

var oDiv1 = document.getElementById("div1");

          document.body.insertBefore(oDiv,oDiv1);//在oDiv1节点前插入新创建的元素节点

ul.appendChild(ul.firstChild); //把ul的第一个元素节点移到ul子节点的末尾

(3)、删除、移除节点

1、removeChild(节点) 删除一个节点,用于移除删除一个参数(节点)。其返回的被移除的节点,被移除的节点仍在文档中,只是文档中已没有其位置了。

              var removeChild = document.body.removeChild(div1);//移除document对象的方法div1

(4)、替换节点

1、replaceChild(插入的节点,被替换的节点) ,用于替换节点,接受两个参数,第一参数是要插入的节点,第二个是要被替换的节点。返回的是被替

          var replaceChild= document.body.replaceChild(div1,div2); //将div1替换div2

(5)、查找节点

1、childNodes 包含文本节点和元素节点的子节点。

2、children也可以获取子节点,而且兼容各种浏览器。包括IE6-8

3、parentNode:获取父节点

3、A、firstChild ; firstElementChild查找第一个子节点。此存在浏览器兼容问题:firstChild是IE兼容,firstElementChild是非IE兼容。

B、lastChild ; lastElementChild查找最后一个子节点。此存在浏览器兼容问题:lastChild 是IE兼容,lastElementChild是非IE兼容。

C、nextSibling ; nextElementSibling查找下一个兄弟节点。也是存在兼容性问题。

D、previousSibling ; previousElementSibling查找上一个兄弟节点。也是存在兼容性问题。

        console.log(oList.childNodes[i]);//在控制器日志中显示找到的元素节点

        console.log(oChild.parentNode);//在控制器日志中显示父节点

console.log(oList.children);//在控制器日志中显示oList子节点

26.写一个返回闭包的函数

闭包函数是指有权访问另一个函数作用域中的变量的函数,

    创建闭包函数最常见的方式是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量

    闭包的特点:1 函数嵌套函数,

                2 函数内部可以引用外部的参数和变量

                3 参数和变量不会被垃圾回收机制回收

    闭包的优点:1 希望一个变量长期驻扎在内存中

                2 避免全局变量的污染

                3 私有变量存在

    闭包的实现 1:函数嵌套函数

              2 外层函数返回内层函数

              3 外面有一全局变量接受外层函数

function fun1() {

        var sum=0;

        function fun2() {

            sum++;

            return sum

        }

        return fun2

    }

27.null和undefined的区别

null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。

undefined:

(1)变量被声明了,但没有赋值时,就等于undefined。

(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。

(3)对象没有赋值的属性,该属性的值为undefined。

(4)函数没有返回值时,默认返回undefined。

null:

(1) 作为函数的参数,表示该函数的参数不是对象。

(2) 作为对象原型链的终点。

28.new操作符具体干了什么呢?

(1)创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。

(2)属性和方法被加入到 this 引用的对象中。

(3)新创建的对象由 this 所引用,并且最后隐式的返回 this 

29.JSON 的了解?

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小。

格式:采用键值对,例如:{'age':'12','name':'back'}

30.js延迟加载的方式有哪些?

共有:defer和async、动态创建DOM方式(用得最多)、按需异步载入js

(1)defer属性:(页面load后执行)

HTML 4.01 为<script>标签定义了defer属性。

用途:表明脚本在执行时不会影响页面的构造。也就是说,脚本会被延迟到整个页面都解析完毕之后再执行

在<script>元素中设置defer属性,等于告诉浏览器立即下载,但延迟执行

<head>

    <script src="test1.js" defer="defer"></script>

    <script src="test2.js" defer="defer"></script>

</head>

(2)async属性:(页面load前执行)

HTML5 为 <script>标签定义了 async属性。与defer属性类似,都用于改变处理脚本的行为。同样,只适用于外部脚本文件。 

目的:不让页面等待脚本下载和执行,从而异步加载页面其他内容。异步脚本一定会在页面 load 事件前执行。不能保证脚本会按顺序执行。

<head>

    <script src="test1.js" async></script>

    <script src="test2.js" async></script>

</head>

<body>

(3)动态创建Dom:

//这些代码应被放置在</body>标签前(接近HTML文件底部)

<script type="text/javascript"> 

   function downloadJSAtOnload() { 

       varelement = document.createElement("script"); 

       element.src = "defer.js"; 

       document.body.appendChild(element); 

   } 

   if (window.addEventListener) 

   window.addEventListener("load",downloadJSAtOnload, false); 

   else if (window.attachEvent) 

    window.attachEvent("onload",downloadJSAtOnload); 

  else

  window.onload =downloadJSAtOnload; 

</script> 

31.ECMAScript6 怎么写class么,为什么会出现class这种东西?

32.常见兼容性问题

33.函数防抖节流的原理

34.深拷贝和浅拷贝的区别?如何实现

两者的区别:一个对象浅复制后,是深层次的对象地址的复制,并没有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,

    则另一个对象的属性也会发生改变,而深复制的则是开辟了一个新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。

    如何实现深拷贝

    1. JSON.stringify()

    缺点: JSON.stringify()无法正确处理函数

    2.递归实现深拷贝(jquery 提供一个$.extend可以用来做深拷贝;)

35.JavaScript原型,原型链 ? 有什么特点?

36.call() 和 apply() 的区别和作用

apply()函数有两个参数:第一个参数是上下文,第二个参数是参数组成的数组。如果上下文是null,则使用全局对象代替。

如:function.apply(this,[1,2,3]);

call()的第一个参数是上下文,后续是实例传入的参数序列。

如:function.call(this,1,2,3);

37.使用递归完成1到100的累加

  function num(n){

    if(n==1) return 1;

    return num(n-1)+n;

  }

num(100);///console.log(num(100));  5050

38.如何改变函数内部的this指针的指向

(1)、可以使用局部变量来代替this指针

  var name = "zhar";

    var obj = {

name : "zhar",

    say : function(){

        var _this = this;//使用一个变量指向 this

        setTimeout(function(){

        console.log(_this.name);

        },0);

    }

    }

    obj.say();

   (2)、使用call 或 apply 方法

    fun.call(thisObj[,arg1[,arg2[,...]]])中的第一个参数就是要更改this指向的对象,为必选参数; 之后的参数要根据调用的函数是否需要传入参数(为可选的)

    apply的作用和call一样,不同的是传参的形式。apply需要以数组的形式传递参数

    如:function.apply(this,[1,2,3]);

    如:function.call(this,1,2,3);

38.随机取1-10之间的整数

var num = Math.random();

    alert(num);  //所得到的的值是0-1之间的 随机数,每次刷新都不同

    var num=Math.floor(Math.random()*10+1);

    alert(num);  //所得到的的是1-10之间的随机数,每次刷新都不同

    如果要2-10之间则将括号内1改为2 即可

39.取数组的最大值(ES5、ES6)

// ES5 的写法

    Math.max.apply(null, [14, 3, 77, 30]);

    // ES6 的写法

    Math.max(...[14, 3, 77, 30]);

40.数组排序相关

结合sort和函数排序:

数组由小到大进行排序:sort,sortnum;

var arr = [3,43,23,45,65,90];

function sortnum(a,b){

return a-b;

}

arr = arr.sort(sortnum);

console.log(arr);

// [3, 23, 43, 45, 65, 90]

数组由大到小进行排序:sort,sortnum;

var arr = [3,43,23,45,65,90];

function sortnum(a,b){

return a+b;

}

arr = arr.sort(sortnum);

console.log(arr);

// [90, 65, 45, 23, 43, 3]

冒泡排序:即实现数组由小到大进行排序;思路为:每次比较相邻的两个数,如果后一个比前一个小,换位置。如果要实现由大到小排序,使用reverse()即可;

var arr = [3, 1, 4, 6, 5, 7, 2];

function bubbleSort(arr) {

var len = arr.length;

for (var i = len; i >= 2; --i) {

for (var j = 0; j < i - 1; j++) {

if (arr[j + 1] < arr[j]) {

var temp;

temp = arr[j];

arr[j] = arr[j + 1];

arr[j + 1] = temp;

}

}

}

return arr;

}

var arr2 = bubbleSort(arr);

console.log(arr2);  // [1, 2, 3, 4, 5, 6,7]

var arr3 = arr2.reverse();

console.log(arr3);  //  [7, 6, 5, 4,3, 2, 1]

快速排序:

思路:采用二分法,取出中间数,数组每次和中间数比较,小的放到左边,大的放到右边。

var arr = [3, 1, 4, 6, 5, 7, 2];

function quickSort(arr) {

if(arr.length == 0) {

return [];  //返回空数组

}

var cIndex = Math.floor(arr.length / 2);

var c = arr.splice(cIndex, 1);

var l = [];

var r = [];


for (var i = 0; i < arr.length; i++) {

if(arr[i] < c) {

l.push(arr[i]);

} else {

r.push(arr[i]);

}

}

return quickSort(l).concat(c, quickSort(r));

}

console.log(quickSort(arr));

//[1, 2, 3, 4, 5, 6, 7]

41.数组的翻转(非reverse())

方法一:

var arr = [1,2,3,4];

var arr2 = [];

while(arr.length) {

var num = arr.pop(); //删除数组最后一个元素并返回被删除的元素

arr2.push(num);

}

console.log(arr2);

// [4, 3, 2, 1]

方法二:

var arr = [1,2,3,4];

var arr2 = [];

while(arr.length){

var num = arr.shift(); //删除数组第一个元素并返回被删除的元素

arr2.unshift(num);

}

console.log(arr2);

42.正则表达式

1、写一个function,清除字符串前后的空格。(兼容所有浏览器)

function trim(str) {

if (str && typeof str === "string") {

return str.replace(/(^\s*)|(\s*)$/g,""); //去除前后空白符

}

}

2、使用正则表达式验证邮箱格式

var reg = /^(\w)+(\.\w+)*@(\w)+((\.\w{2,3}){1,3})$/;

var email = "example@qq.com";

console.log(reg.test(email));  // true

43.编写一个方法 去掉一个数组的重复元素

方法一:

var arr = [0,2,3,4,4,0,2];

var obj = {};

var tmp = [];

for(var i = 0 ;i< arr.length;i++){

if( !obj[arr[i]] ){

obj[arr[i]] = 1;

tmp.push(arr[i]);

}

}

console.log(tmp);

结果如下:[0,2, 3, 4]

方法二:

var arr = [2,3,4,4,5,2,3,6],

arr2 = [];

for(var i = 0;i< arr.length;i++){

if(arr2.indexOf(arr[i]) < 0){

arr2.push(arr[i]);

}

}

console.log(arr2);

结果为:[2, 3,4, 5, 6]

方法三:

var arr = [2,3,4,4,5,2,3,6];

var arr2 =

arr.filter(function(element,index,self){

return self.indexOf(element) === index;

});

console.log(arr2);

结果为:[2, 3,4, 5, 6]

44.实现一个函数clone 可以对Javascript中的五种主要数据类型(Number、string、Object、Array、Boolean)进行复制

var test = {

  a: [1,2,3],

  b: 'sfasdf',

  c: {

    d: 1,

    e: true,

    f: ['a', 'b', 'c']

  },

  d: null,

}

function clone(val) {

  if(typeof val === 'number' || typeof val ==='string' || typeof val === 'boolean' || val === null) {

    return val;

  }

if(Object.prototype.toString.call(val) === '[object Array]') {

    return val.map(v=>clone(v));

  }

  if(Object.prototype.toString.call(val) === "[object Object]") {

  return Object.keys(val).reduce((prev, key) => {

    prev[key] = clone(val[key]);

    return prev;

  }, {});

  }

}

const newTest = clone(test);

console.log(newTest);

45.如何消除一个数组里面重复的元素

方法一:

Array.prototype.method1 = function(){

      var arr[];    //定义一个临时数组

      for(var i = 0; i < this.length; i++){    //循环遍历当前数组

          //判断当前数组下标为i的元素是否已经保存到临时数组

          //如果已保存,则跳过,否则将此元素保存到临时数组中

          if(arr1.indexOf(this[i]) == -1){

              arr.push(this[i]);

          }

      }

      return arr;

  }

方法二:

Array.prototype.method2 = function(){ 

            var h{};    //定义一个hash表 

            var arr[];  //定义一个临时数组 


            for(var i = 0; i < this.length; i++){    //循环遍历当前数组 

                //对元素进行判断,看是否已经存在表中,如果存在则跳过,否则存入临时数组 

                if(!h[this[i]]){ 

                    //存入hash表 

                    h[this[i]] = true; 

                    //把当前数组元素存入到临时数组中 

                    arr.push(this[i]); 

                } 

            } 

            return arr; 

        } 

方法三:

Array.prototype.method3 = function(){ 

            //直接定义结果数组 

            var arr=[] ;

            for(var i = 1; i < this.length; i++){    //从数组第二项开始循环遍历此数组 

                //对元素进行判断: 

                //如果数组当前元素在此数组中第一次出现的位置不是i 

                //那么我们可以判断第i项元素是重复的,否则直接存入结果数组 

                if(this.indexOf(this[i]) == i){ 

                    arr.push(this[i]); 

                } 

            } 

            return arr; 


        } 

方法四:

Array.prototype.method4 = function(){ 

            //将数组进行排序 

            this.sort(); 

            //定义结果数组 

            var arr=[]; 

            for(var i = 1; i < this.length; i++){    //从数组第二项开始循环遍历数组 

                //判断相邻两个元素是否相等,如果相等说明数据重复,否则将元素写入结果数组 

                if(this[i] !== arr[arr.length - 1]){ 

                    arr.push(this[i]); 

                }             

            } 

            return arr; 


        }

eg:

        var arr = [112,112,34,'你好',112,112,34,'你好','str','str1']; 

        alert(arr.method1());  / alert(arr.method2()); / alert(arr.method3()); / alert(arr.method4());

方法1和方法3都用到了数组的indexOf()方法,此方法主要用来查找元素在数组中第一次出现的位置。比较浪费资源和时间。

方法2使用的是hash表,把已经出现过的元素通过下标形式写入到一个object内,下标的引用要比用数组indexOf()方法搜索节省时间。

方法4是先将数组排序,然后一次比较相邻的两个元素的值,排序使用的是js原生的sort()方法

46.$(document).ready()方法和window.onload有什么区别?

(1)、window.onload方法是在网页中所有的元素(包括元素的所有关联文件)完全加载到浏览器后才执行的。

(2)、$(document).ready() 方法可以在DOM载入就绪时就对其进行操纵,并调用执行绑定的函数。

47.如何用jQuery禁用浏览器的前进后退按钮?

$(document).ready(function() {

window.history.forward(1);

//OR window.history.forward(-1);

});

48. jquery中$.get()提交和$.post()提交有区别吗?

相同点:都是异步请求的方式来获取服务端的数据;

异同点:

(1)、请求方式不同:$.get() 方法使用GET方法来进行异步请求的。$.post() 方法使用POST方法来进行异步请求的。

(2)、参数传递方式不同:get请求会将参数跟在URL后进行传递,而POST请求则是作为HTTP消息的实体内容发送给Web服务器的,这种传递是对用户不可见的。

(3)、数据传输大小不同:get方式传输的数据大小不能超过2KB 而POST要大的多

(4)、安全问题: GET 方式请求的数据会被浏览器缓存起来,因此有安全问题

49.get和post请求区别

浏览器回退:GET在浏览器回退时是无害的,而POST会再次提交请求。

收藏书签:GET可以,而POST不能

浏览器缓存:GET请求会被浏览器主动cache,而POST不会,除非手动设置。

请求编码:GET请求只能进行url编码,而POST支持多种编码方式。

浏览历史:GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。

参数个数:GET请求在URL中传送的参数是有长度限制的,而POST么有。

参数数据类型:GET只接受ASCII字符,而POST没有限制。

安全:GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。

传递方式:GET参数通过URL传递,POST放在Request body中。

请求限制:大多数浏览器通常都会限制url长度在2K个字节,而大多数服务器最多处理64K大小的url。

本质区别

GET和POST本质上两者没有任何区别。他们都是HTTP协议中的请求方法。底层实现都是基于TCP/IP协议。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。

GET产生一个TCP数据包;POST产生两个TCP数据包。

对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);

而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

50.写出一个简单的$.ajax()的请求方式?

$.ajax({

url:'http://www.baidu.com',

type:'POST',

data:data,

cache:true,

headers:{},

beforeSend:function(){},

success:function(){},

error:function(){},

complete:function(){}

});

51.Ajax的优缺点及工作原理?

定义和用法:

AJAX = Asynchronous JavaScript and XML(异步的JavaScript 和 XML)。Ajax 是一种用于创建快速动态网页的技术。Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

传统的网页(不使用 Ajax)如果需要更新内容,必须重载整个网页页面。

优点:

1.减轻服务器的负担,按需取数据,最大程度的减少冗余请求

2.局部刷新页面,减少用户心理和实际的等待时间,带来更好的用户体验

3.基于xml标准化,并被广泛支持,不需安装插件等,进一步促进页面和数据的分离

缺点:

1.AJAX大量的使用了javascript和ajax引擎,这些取决于浏览器的支持.在编写的时候考虑对浏览器的兼容性.

2.AJAX只是局部刷新,所以页面的后退按钮是没有用的.

3.对流媒体还有移动设备的支持不是太好等

AJAX的工作原理:

1.创建ajax对象(XMLHttpRequest/ActiveXObject(Microsoft.XMLHttp))

2.判断数据传输方式(GET/POST)

3.打开链接open()

4.发送send()

5.当ajax对象完成第四步(onreadystatechange)数据接收完成,判断http响应状态(status)200-300之间或者304(缓存)执行回调函数

52.jQuery的事件委托方法bind 、live、delegate、on之间有什么区别?

(1)、bind 【jQuery 1.3之前】

定义和用法:主要用于给选择到的元素上绑定特定事件类型的监听函数;

语法:bind(type,[data],function(eventObject));

特点:

(1)、适用于页面元素静态绑定。只能给调用它的时候已经存在的元素绑定事件,不能给未来新增的元素绑定事件。

(2)、当页面加载完的时候,你才可以进行bind(),所以可能产生效率问题。

实例如下:$( "#members li a").bind( "click", function( e ) {} );

(2)、live 【jQuery 1.3之后】

定义和用法:主要用于给选择到的元素上绑定特定事件类型的监听函数;

语法:live(type, [data], fn);

特点:

(1)、live方法并没有将监听器绑定到自己(this)身上,而是绑定到了this.context上了。

(2)、live正是利用了事件委托机制来完成事件的监听处理,把节点的处理委托给了document,新添加的元素不必再绑定一次监听器。

(3)、使用live()方法但却只能放在直接选择的元素后面,不能在层级比较深,连缀的DOM遍历方法后面使用,即$(“ul”").live...可以,但$("body").find("ul").live...不行;

实例如下:$( document ).on("click", "#members li a", function( e ) {} );

(3)、delegate 【jQuery 1.4.2中引入】

定义和用法:将监听事件绑定在就近的父级元素上

语法:delegate(selector,type,[data],fn)

特点:

(1)、选择就近的父级元素,因为事件可以更快的冒泡上去,能够在第一时间进行处理。

(2)、更精确的小范围使用事件代理,性能优于.live()。可以用在动态添加的元素上。

实例如下:

$("#info_table").delegate("td","click",function(){/*显示更多信息*/});

$("table").find("#info").delegate("td","click",function(){/*显示更多信息*/});

(4)、on 【1.7版本整合了之前的三种方式的新事件绑定机制】

定义和用法:将监听事件绑定到指定元素上。

语法:on(type,[selector],[data],fn)

实例如下:$("#info_table").on("click","td",function(){/*显示更多信息*/});参数的位置写法与delegate不一样。

说明:on方法是当前JQuery推荐使用的事件绑定方法,附加只运行一次就删除函数的方法是one()。

总结:.bind(), .live(), .delegate(),.on()分别对应的相反事件为:.unbind(),.die(), .undelegate(),.off()

53.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容

  • 如何控制alert中的换行?\n alert(“p\np”); 请编写一个JavaScript函数 parseQu...
    heyunqiang99阅读 1,082评论 0 6
  • 概要 64学时 3.5学分 章节安排 电子商务网站概况 HTML5+CSS3 JavaScript Node 电子...
    阿啊阿吖丁阅读 8,994评论 0 3
  • 单例模式 适用场景:可能会在场景中使用到对象,但只有一个实例,加载时并不主动创建,需要时才创建 最常见的单例模式,...
    Obeing阅读 2,045评论 1 10
  • 前端开发面试题 面试题目: 根据你的等级和职位的变化,入门级到专家级,广度和深度都会有所增加。 题目类型: 理论知...
    怡宝丶阅读 2,566评论 0 7
  • 简述JavaScript起源起源于美国的Netscape公司,原名为LiveScript,后改为JavaScrip...
    3ab670b99521阅读 2,973评论 0 0