前端面试题三

89、介绍js基本数据类型

1)ECMAScript中有5种基本数据类型: Undefined、Null、Boolean、Number和String

1种复杂的数据类型—Object,Object本质上是由一组无序的名值对组成的

其中Undefined、Null、Boolean、Number都属于基本类型。Object、Array和Function则属于引用类型,String有些特殊

2)变量

ES6前声明变量只有:var   function

ES6声明变量有:const---声明基本类型的常量变量值不能修改,引用类型的常量内部值可以修改只是保证地址一样就可以了    let   Symbol

3)typeof操作---可以检测基本数据类型,返回字符串

var a 
console.log(typeof a);  //'undefined'
a = 1
console.log(typeof a);  //'number'
a = 'aa'
console.log(typeof a);  //'string'
a = true
console.log(typeof a);  //'boolean'
a = null
console.log(typeof a);  //'object'
a = []
console.log(typeof a);  //'object'
a = {}
console.log(typeof a);  //'object'

Boolean()函数的转换

96、编写一个方法,判断字符串是否是这样组成的,第一个必须为数字,最后一个必须为 字母

// \S---匹配任何非空白字符      \s匹配任何空白字符
var c =  /^[0-9][\s|\S]*[a-zA-Z]$/;
var str = '122'
console.log(c.test(str)); // true

正则表达式——判断字符串组成,第一个必须是字母,后面可以是字母、数字、下划线,总长度为5-20

//判断字符串是否是这样组成的,第一个必须是字母,后面可以是字母、数字、下划线,总长度为5-20
var c =  /^[a-zA-Z]\w{4,19}$/;
//  /是转义   ^  是开头   [a-zA-Z]是字母出现一次    \w是任意字符   {4,11}是长度 $ 是结束
var str = 'ss4442'
console.log(c.test(str)); // true

98、如何隐藏一个dom元素

css中隐藏DOM元素常见的5种方法

opacity:0           //将透明度设置为0,透明度为0的元素任然占据页面空间,响应用户交互
visibility:hidden   //将元素隐藏,被隐藏的元素任然占据页面空间,不响应用户交互
diaplay:none        //被隐藏的元素不在占据页面空间,不响应用户交互,相当于该元素不存在
position:absolute   //通过top/right/bottom/left的值将元素移到页面不可见的地方
clip-path:polygon(0px,0px,0px,0px,0px,0px,0px,0px)  //通过裁剪的方式

100、如何添加HTML事件,有几种方法?(至少两种方式)

在JavaScript中,有三种常用的绑定事件的方法:
(1)在DOM元素中直接绑定
(2)在JavaScript代码中绑定
(3)绑定事件监听函数

(1)在DOM元素中直接绑定

//原生函数
<input onclick="alert('谢谢支持')" type="button" value="点击我,弹出警告框" />

//自定义函数
<input onclick="myAlert()" type="button" value="点击我,弹出警告框" />

<script type="text/javascript">
   function myAlert(){
     alert("谢谢支持");
   }
</script>


(2)在JavaScript代码中绑定---JavaScript代码与HTML标签分离,文档结构清晰,便于管理和开发

<input id="demo" type="button" value="点击我,显示 type 属性" />

<script type="text/javascript">
    document.getElementById("demo").onclick=function(){
        alert(this.getAttribute("type")); // this 指当前发生事件的HTML元素,这里是<div>标签
    }
</script>

(3)绑定事件监听函数

function addEvent(obj,type,handle){
    try{ // Chrome、FireFox、Opera、Safari、IE9.0及其以上版本
        obj.addEventListener(type,handle);
    }catch(e){
        try{ // IE8.0及其以下版本
            obj.attachEvent('on' + type,handle);
        }catch(e){ // 早期浏览器
            obj['on' + type] = handle;
        }
    }
}

104、前端常规开发优化策略(至少两种方式)(也就是性能优化的方法)

(1) 减少http请求次数:css spirit,js/cs的合并,使用缓存--本地缓存、cookie

(2) JS,CSS源码压缩

(3) 用变量保存DOM节点查找的结果,减少DOM操作次数,优化javascript性能

(4)用setTimeout来避免页面失去响应

(5) 用hash-table来优化查找

(6) 当需要设置的样式很多时,设置className而不是直接操作style 

(7)少用全局变量

(8)缓存DOM

(9)避免使用CSS Expression(计算频繁)

(10) 图片预加载

(11) 避免在页面的主体布局中使用table,table要等其中的内容完全下载之后才会显示出来,显示比div css布局慢

34、你如何对网站的文件和资源进行优化?期待的解决方案包括

● 文件合并(目的是减少http请求):Web性能优化最佳实践中最重要的一条是减少HTTP 请求,减少HTTP请求的方案主要有合并JavaScript和CSS文件、CSS Sprites(雪碧图)、图像映射 (Image Map)和使用Data URI来编码图片。

● 文件压缩:目的是直接减少文件体积,减少文件加载时间
●  使用 CDN (内容分发网络)来托管资源。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。从而使用户就近取得数据,提升浏览网站的速度。
 缓存的使用(并且多个域名来提供缓存),可以减少阿星服务器请求的次数,加快加载速度。

服务端开启GZIP ,对用户请求的页面进行压缩处理,以达到节省网络带宽,提高浏览网站速度的作用

33、静态资源CDN如何使用   更新ing。。。。。。。

静态资源包括:图片,css文件,js文件等

静态资源CDN使用分为5步

35、为了让网页更快的加载,你会如何处理你的css文件和js文件,以及图片文件,页面性能优化你还知道哪些方法

怎么解决卡顿的问题(性能优化的方法)?

参考1     https://blog.csdn.net/tangxiujiang/article/details/79791545

参考2     https://blog.csdn.net/tangxiujiang/article/details/79775574

53、前端性能优化的点

1)减少HTTP请求次数:合并样式和脚本,使用css sprites,初始首屏之外的图片资源按需加载,静态资源延迟加载、懒加载 

2)利用缓存:缓存Ajax,使用CDN,使用外部js和css文件以便缓存,添加Expires头,服务端配置Etag,减少DNS查找等

3)请求宽带:压缩文件,开启GZIP

4)代码层面优化:

尽量使用id来查询节点;将一个列表的长度用一个变量缓存;减少DOM操作,将一个多次使用的DOM节点用一个变量缓存;尽量减少全局变量的使用;多个变量的声明合并;避免使用with(with会创建自己的作用域,会增加作用域链长度)

避免使用css表达式;

5)控制资源文件加载优先级:样式放在顶部,脚本放在底部

6)减少重排

参考链接

53、移动端端性能优化的点

PC端性能优化的方法都适用于移动端

参考链接

https://blog.csdn.net/tangxiujiang/article/details/79791545

53、移动端白屏的解决方案--其实也就是性能优化方面

白屏的基本原因可以归结为网速和静态资源

1)css文件加载需要一些时间,在加载的过程中页面是空白

解决:可以考虑将css代码前置和内联

2)首屏无实际的数据内容,等待异步加载数据,再渲染页面,导致白屏

解决:首屏直接同步渲染html后续的滚屏等操作再采用异步请求数据和渲染html

3)首屏内联js的执行,会阻塞页面的渲染

解决:尽量不在首屏html代码中放置内联脚本

还有一些其他的解决办法:

1)在服务器端,使用模板引擎渲染所有页面

1、减少文件加载体积,如html压缩,js压缩

2、加快js执行速度 比如常见的无限滚动的页面,可以使用js先渲染一个屏幕范围内的东西

3、提供一些友好的交互,比如提供一些假的滚动条

4、使用本地存储处理静态文件

57、回流和重绘的解释、关系及区别?

1)当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建,这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘

2)当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color,这就称为重绘

注意:回流必将引起重绘,而重绘不一定会引起回流

回流:指的是浏览器为了重新渲染页面的需要而进行的重新计算元素的几何大小和位置,他的开销是非常大的,回流可以理解为渲染树需要重新进行计算,一般最好触发元素的重构,避免元素的回流;比如通过添加class来添加css样式,而不是直接在DOM上设置,当需要操作某一块元素的时候,最好使其脱离文档流,这样就不会引起回流了,比如设置position:absolute或者fixed,或者display:none,等操作结束后在显示




回流何时发生:当页面布局和几何属性改变时就需要回流。下述情况会发生浏览器回流:

1、添加、删除、修改可见的DOM元素
2、DOM元素位置改变
3、修改元素的css样式,元素尺寸改变——边距、填充、边框、宽度和高度
4、DOM元素内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变
5、页面初始化的渲染
6、浏览器窗口尺寸改变——resize事件发生时
7、浏览器窗口滚动



怎样能减少页面的回流和重绘
1. 直接改变className,如果动态改变样式,则使用cssText(考虑没有优化的浏览器)
2. 让要操作的元素进行”离线处理”,处理完后一起更新
a) 使用DocumentFragment进行缓存操作,引发一次回流和重绘;
b) 使用display:none技术,只引发两次回流和重绘;
c) 使用cloneNode(true or false) 和 replaceChild 技术,引发一次回流和重绘;
3.不要经常访问会引起浏览器flush队列的属性,如果你确实要访问,利用缓存
4. 让元素脱离动画流,减少回流的Render Tree的规模

浏览器的渲染过程: 下载文档渲染页面的过程中

1、浏览器会通过解析HTML文档构建DOM树

2、其次根据css构建render树,render树中不包含定位和几何信息 

3、javascript在代码解析的过程中,可能会修改生成的dom树、css render tree,之后根据dom树和css  render tree构建

染树(含有元素的定位和几何信息)。在这个过程中css会根据选择器匹配HTML元素。渲染树包括了每个元素的大小,边距等样

 式属性渲染树不包含隐藏元素及head元素不可见元素。最后浏览器根据元素的坐标和大小来计算每个元素的位置,并绘制这

些元素到页面上。


 

105、如何控制网页在网络传输过程中的数据量

(1)减少数据量最显著的方法是启用GZIP 压缩
(2)保持良好的编程习惯,避免重复的CSS,JavaScript代码,多余的HTML标签和属性

52、前端工程师的价值体现在哪里

1)为简化用户使用,提供技术支持(交互部分)
2)为多个浏览器兼容性提供支持
3)为提高用户浏览速度(浏览器性能)提供支持
4)为跨平台或者其他基于webkit或其他渲染引擎的应用提供支持
5)为展示数据提供支持(数据接口)

106、var stringArray = [ "this","is","chunchujie"],请在控制台输出“this is chunchujie”

stringArray = [ "this","is","chunchujie"]
var str = ''
stringArray.forEach(function(item){
  str = str + item + ' ';
})
str.replace(/\s*$/,'')
console.log(str)

109、请在网页上输出九九乘法表

使用for循环实现

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            td {
                width: 200px;
                height: 40px;
                border: 1px solid #CCCCCC;
            }
            tr {
                text-align: center;
            }
        </style>
    </head>
    <body>
        
        <table>
            <th>九九乘法表</th>         
        </table>
        
        <script>  
            var table = document.getElementsByTagName('table')[0];        
            for(var i=1;i<10;i++){
                var str = '';
                var tr = document.createElement('tr');
                for(var j=1;j<=i;j++){
                    str = i + '*' + j + '=' + i*j;
                    var td = document.createElement('td');
                    td.innerText = str;
                    tr.appendChild(td);
                }
                table.appendChild(tr);
            }
                    
        </script>
    </body>
</html>

上面频繁进行回流和重绘,影响性能,利用变量将要进行的变化的代码保留。进行一次重绘,性能会好很多
 

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            td {
                width: 200px;
                height: 40px;
                border: 1px solid #CCCCCC;
            }
            tr {
                text-align: center;
            }
        </style>
    </head>
    <body>
        
        <table>
            <th>九九乘法表</th>         
        </table>
        
        <script>  
            var table = document.getElementsByTagName('table')[0];    
            var str = '';    
            for(var i=1;i<10;i++){
                let str1 = '';
               
                for(var j=1;j<=i;j++){
                    str1 += `<td>${i}*${j}=${i*j}</td>`;
                }
                str += `<tr>${str1}</tr>`;
               
            }
            table.innerHTML = str;     
        </script>
    </body>
</html>

111、请解释jsonp的工作原理

解释jsonp 的原理 以及为什么不是ajax

jsonp的原理:jsonp之所以能跨域,是因为他并不是发送ajax请求,并不是利用XMLHTTPRequest对象和服务端进行通信,他其实是利用动态创建的script标签,而script标签是没有同源策略限制的,可以跨域的。创建script标签,然后将其src,指向我们真实的服务端的地址,在这个地址的后面有一个参数比如calback=a,然后服务端可以解析到这个url,中的callback=a,服务端在返回的数据时,就会调用a方法,去包裹一段数据,然后返回这段js代码,相当于在前端去执行这个a方法。那么在前端发送请求之前,就要在window上去注册这个a方法,那么在服务端返回这个a方法执行的时候,就可以去之前在window上定义的a方法中获得数据了

116、如何实现下列代码:

var number  =[ 1,2,3,4,5];

number.square();//[1,4,9,16,25]

number.average();//3

number.sum();//15

number.even()://[2,4]

在原型上面扩展方法

var number  =[ 1,2,3,4,5];

// number.square();//[1,4,9,16,25]
// 
// number.average();//3

// number.sum();//15

// number.even()://[2,4]

Array.prototype.square = function(){
	var len = this.length;
	var newArr = [];
	if(!len){
		return
	}
	for(var i = 0;i<len;i++){
		newArr.push(this[i] * this[i]);
	}
	return newArr;
}
console.log(number.square());  //[ 1, 4, 9, 16, 25 ]


Array.prototype.average = function(){
	var len = this.length;
	var sum = 0;
	if(!len){
		return
	}
	for(var i = 0;i<len;i++){
		sum = sum + this[i];
	}
	return sum/len;
}
console.log(number.average());   //3

Array.prototype.sum = function(){
	var len = this.length;
	var sum = 0;
	if(!len){
		return
	}
	for(var i = 0;i<len;i++){
		sum = sum + this[i];
	}
	return sum;
}
console.log(number.sum()); //15

Array.prototype.even = function(){
	var len = this.length;
	var newArr = [];
	if(!len){
		return
	}
	for(var i = 0;i<len;i++){
		if(this[i] % 2 === 0){
			newArr.push(this[i]);
		}
	}
	return newArr;
}
console.log(number.even()); [2,4]

121、js获取来源页地址显示在页面上(js获取当前页的来源页,即上一页)

var ref=document.referre

122、jQuery  Mobile 是什么

1)jQuery Mobile 是一个为触控优化的框架,用于创建移动 web 应用程序
2)jQuery 适用于所有流行的智能手机和平板电脑
3)jQuery Mobile 构建于 jQuery 库之上,这使其更易学习,如果您通晓 jQuery 的话
4)它使用 HTML5、CSS3、JavaScript 和 AJAX 通过尽可能少的代码来完成对页面的布局

为什么使用jQuery Mobile

jQuery Mobile 将“写得更少、做得更多”这一理念提升到了新的层次:它会自动为网页设计交互的易用外观,并在所有移动设计上保持一致。
提示:您不需要为每种移动设备或 OS 编写一个应用程序:
Android 和 Blackberry 用 Java 编写
iOS 用 Objective C 编写
Windows Phone 用 C# 和 .net 编写
jQuery Mobile 解决了这个问题,因为它只用 HTML、CSS 和 JavaScript,这些技术都是所有移动 web 浏览器的标准

126、想实现一个对页面某个结点的拖拽?如何做?(使用原生JS)

128、jquery与jQuery UI有什么区别

1)jQuery是一个js库,主要提供的功能选择器、属性修改和事件绑定
2)jQuery UI则是在jQuery的基础上,利用jQuery的扩展性,设计的插件。提供了一些常用的界面元素,诸如对话框、拖动行为、改变大小行为等;
3)jQuery本身注重于后台,没有漂亮的界面,而jQuery UI则补充了前者的不足,他提供了华丽的展示界面,使人更容易接受。既有强大的后台,又有华丽的前台。jQuery UI是jQuery插件,只不过专指由jQuery官方维护的UI方向的插件

130、一个div宽高100px,点击变大,当它的宽高等于400px开始缩小,当宽高缩小至100px时, 开始放大;再次点击暂定缩小或放大,再再次点击,div继续放大或缩小

第二个功能还没有实现????

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            *{
                margin:0;
                padding: 0;
            }
            .container{
                width:600px;
                height: 600px;
                display: table-cell;
                vertical-align: middle;
                background: black;
            }
            .child{
                height:100px;
                width: 100px;
                margin:0 auto;
                background: red;
            }

            .anima{
                animation:mymove 5s infinite;
                -webkit-animation:mymove 10s infinite; /*Safari and Chrome*/
            }

            @keyframes mymove{
                0%{
                    transform:scale(1,1)
                }
                50%{
                    transform:scale(4,4)
                }
                100%{
                    transform:scale(1,1)
                }
            }

            @-webkit-keyframes mymove{
                from{
                    transform:scale(1,1)
                }
                to{
                    transform:scale(4,4)
                }
            }
            
        </style>
    </head>
    <body>
        <div id='container' class="container">
            <div id='child' class="child"></div>
        </div>
        <script type="text/javascript">
            document.getElementById('child').onclick = function(){
                var flag = true;
                if(flag){
                    document.getElementById('child').classList.toggle('anima');
                }else{

                }
                
            }
        </script>
    </body>
</html>

jQuery添加类和删除类

//添加类,可以添加多个
$(selector).addClass(class1 class2)
//可以删除多个类
$(selector).removeClass(class1 class2)
//直接设置单个css
$('#id').css('background','red');
//设置多个css
$('#id').css({
  'backgroundColor':'red',
  'fontSize':'12px'
})

js添加删除类
classList属性------返回元素的类名,作为 DOMTokenList 对象

element.classList
.classList
//可以同时添加多个类
document.getElementById("myDIV").classList.add("mystyle", "anotherClass", "thirdClass");
//可以同时删除多个类
document.getElementById("myDIV").classList.remove("mystyle", "anotherClass", "thirdClass");
//返回布尔值,判断指定的类名是否存在
var x = document.getElementById("myDIV").classList.contains("mystyle");
返回布尔值,判断指定的类名是否存在
var x = document.getElementById("myDIV").classList.contains("mystyle");
//添加/删除类交替进行
document.getElementById("myDIV").classList.toggle("newClassName");

131、静态资源CDN如何使用

133、Postcss是啥

PostCSS 本身是一个功能比较单一的工具。它提供了一种方式用 JavaScript 代码来处理 CSS。它负责把 CSS 代码解析成抽象语法树结构(Abstract Syntax Tree,AST),再交由插件来进行处理。插件基于 CSS 代码的 AST 所能进行的操作是多种多样的,比如可以支持变量和混入(mixin),增加浏览器相关的声明前缀,或是把使用将来的 CSS 规范的样式规则转译(transpile)成当前的 CSS 规范支持的格式。从这个角度来说,PostCSS 的强大之

function sortAB(a,b){
  let arr = a.concat(b);
  arr.sort((a1,a2)=>a-b);
  return arr
}

处在于其不断发展的插件体系。目前 PostCSS 已经有 200 多个功能各异的插件。开发人员也可以根据项目的需要,开发出自己的 PostCSS 插件

 

PostCSS 从其诞生之时就带来了社区对其类别划分的争议。这主要是由于其名称中的 post,很容易让人联想到 PostCSS 是用来做 CSS 后处理(post-processor)的,从而与已有的 CSS 预处理(pre-processor)语言,如 SASS 和 LESS 等进行类比。实际上,PostCSS 的主要功能只有两个:第一个就是前面提到的把 CSS 解析成 JavaScript 可以操作的 AST,第二个就是调用插件来处理 AST 并得到结果。因此,不能简单的把 PostCSS 归类成 CSS 预处理或后处理工具。PostCSS 所能执行的任务非常多,同时涵盖了传统意义上的预处理和后处理。PostCSS 是一个全新的工具,给前端开发人员带来了不一样的处理 CSS 的方式

134、Java和Javascript的共同点

144、下面这段代码的运行结果是什么?

            //number和boolean通过==判断相等的时候
            //false相等于0,true相等于1
            console.log(1 == true)   //true
            console.log(0 == false); //true
            console.log(3 == true); //false

            //string和boolean通过==判断相等的时候
            //false相等于''和'0',true相等于'1'
            console.log('' == false); //true
            console.log('0' == false); //true
            console.log('1' == true); //true
            console.log('sss' == true); //false

            
            console.log({} == false); //false
            console.log({} == true); //false
            console.log({a:0} == false); //false

            console.log( 2 == {valueOf: function( ){return 2}});  //true
            var a

            console.log( a == NaN ); //false

            console.log( NaN == NaN ); //false

            console.log( 8 == undefined );  //false
            console.log( 0 == undefined);   //false

            console.log( 2 == {toString:function(){return 2}}); //true

            console.log( undefined == null ); //true

            console.log( null == 1); //false

            console.log({toString:function(){return 1},valueOf:function(){return []}}); //  {toString: ƒ, valueOf: ƒ}

            console.log(1 == '1'); //true

146、[2,6,7]和[3,5,8]  =>  [2,3,5,6,7,8]

var b;
function a(){
	var a = 'a';
	B = function(){
		return  a + 'B';
	}

	return a;
}

console.log(a()); //a

console.log(B()); //aB

1)先将两个数组进行拼接,然后在升序

function sort(a,b){
	var merge = a.concat(b);
	console.log(merge);
	console.log(a);
	merge = quickSort(merge);
	return merge;
}

function quickSort(arr){
	var len = arr.length;
	if(len < 2){
		return arr;
	}
	var midIndex = Math.floor(len/2);
	var midEle = arr.splice(midIndex,1);
	var left = [],
	    right = [],
	    newLen = len-1;
	for(var i=0;i<newLen;i++){
		if(arr[i]>midEle){
			right.push(arr[i]);
		}else{
			left.push(arr[i]);
		}
	}
	return quickSort(left).concat(midEle,quickSort(right));
}

var a = [3,2,4];
var b = [97,8,5];
console.log(sort(a,b));

2)先将两个数组升序排序,然后使用归并排序

function sort(a,b){
	a = quickSort(a);
	b = quickSort(b);

	var merge = mergeSort(a,b);
	return merge;
}

function mergeSort(a,b){
	var arr = [];
	while(a.length && b.length){
		if(a[0] < b[0]){
			arr.push(a.shift());
		}else{
			arr.push(b.shift());
		}
	}

	while(a.length){
		arr.push(a.shift());
	}

	while(b.length){
		arr.push(b.shift());
	}

	return arr;
}

function quickSort(arr){
	var len = arr.length;
	if(len < 2){
		return arr;
	}
	var midIndex = Math.floor(len/2);
	var midEle = arr.splice(midIndex,1);
	var left = [],
	    right = [],
	    newLen = len-1;
	for(var i=0;i<newLen;i++){
		if(arr[i]>midEle){
			right.push(arr[i]);
		}else{
			left.push(arr[i]);
		}
	}
	return quickSort(left).concat(midEle,quickSort(right));
}

var a = [3,2,4];
var b = [97,8,5];
console.log(sort(a,b));

147、将一个十六进制字符串转换为十进制数

// 二进制与十进制的互转
let a = 100;
console.log(a.toString(2));//1010
console.log(parseInt('1010',2));//10
// 十六进制与十进制的互转
console.log(a.toString(16));//64
console.log(parseInt('64',16));//100

151、下面这段代码的运行结果是什么?

var arr = [1,2,3,4,true,'bbb',new Date()];
arr.length = 5;   //通过改变Array的length属性,可以修改Array
console.log(arr); //[ 1, 2, 3, 4, true ]
arr.length = 6;
console.log(arr); //[ 1, 2, 3, 4, true, <1 empty item> ]
arr[9] = 9;       //通过索引操作也可以修改array
console.log(arr); //[ 1, 2, 3, 4, true, <4 empty items>, 9 ]

152、下面这段代码的运行结果是什么

var arr=[1,2,3,4,5];
arr.splice(1,2,3,4,5);
console.log(arr);  //[ 1, 3, 4, 5, 4, 5 ]

154、合并数组[4,1,3,9,6,2]和[8,5,3,2,1,4,7],然后去重,取出偶数倒排

function fun(arr1,arr2){
	let arr = arr1.concat(arr2);
	let set = new Set(arr);
	arr = [...set];
	let even = [];
	for(let item of arr){
		if(item % 2 === 0){
			even.push(item);
		}
	}
    //even = arr.filter(function(val){
    //      return val%2 === 0
    //})



	even.sort( (a,b)=>b-a );
	return even;
}

let arr1 = [1,4,2];
let arr2 = [1,4,3];
console.log(fun(arr1,arr2));

164、实时监测用户在input内输入的字符数应该监听哪个事件(oninput/onpropertychange(ie))

键盘相关事件:onkeypress   onkeydown   onkeyup  oninput  onchange  onpropertychange

onkeydown/onkeypress/onkeyup
使用这三个事件监听输入框值变化,不能监听到右键的复制、粘贴、剪切的操作

onkeydown
按下键盘上的任意键(不包括PrScrn键)时触发;如果一直按着键不放,则会一直触发此事件。

onkeypress
按下键盘上的可显示字符键(可以参考此文的键盘按键分类一节)时触发,如果一直按着键不放,则会一直触发此事件。

onkeyup
释放键盘上的任意键(不包括PrScrn键)时触发

1、是否可以捕获组合键?
onkeydown/onkeyup可以捕获组合键,onkeypress 只能捕获单个字符。 
在捕获组合键时建议使用 onkeyup 事件。

2、是否区分大小写字符?
onkeypress 能区分字符的大小写,onkeydown/onkeyup不能区分。

3、是否区分主键盘和小键盘的数字?
onkeypress不区分主键盘和小键盘的数字,onkeydown/onkeyup则可以区分。

4、触发顺序
先 onkeydown, 再 onkeypress, 最后onkeyup

oninput/onpropertychange
上面讲到用 keydown/keypress/keyup无法监听右键粘贴复制操作,于是就有了 oninput 事件。

oninput是 HTML5的新事件,可以在输入框( textarea, input:text/password/search等)的value值发生变化时(通过 JS修改输入值除外)立即触发,所以可以监听右键粘贴复制操作。但 IE9.0以下版本不支持,此时需要用到IE特有的 onpropertychange事件。在 Safari5.0以下版本,oninput 不支持 textarea 元素。


onpropertychange IE特有的事件,与 oninput不同的是,只要绑定对象的相关属性(不单 value 值)发生变化(包括 通过JS脚本来修改)都会触发此事件。

onchange
要触发这个事件有2个必备条件: 
1、和onpropertychange一样,只要绑定对象的相关属性发生了变化就会触发此事件。但和onpropertychange不同,通过JS脚本改变属性时无法触发); 

2、输入框失去焦点后触发,所以无法做到实时监听

84、字符串去重:用一个对象去标识字符是否已经存在,没有存在的时候就将该字符添加到新的字符串里面,有的话不需要做任何处理

let str = 'aabbbss';
let set = new Set(str.split(''));
let arr = [...set];
let str2 = arr.join('');
console.log(str2); //abs
function removeMultiChar(str){
	if(!str){
		return '输入类型不符合要求';
	}else if(typeof(str)!=='string'){
		return '输入参数必须为字符串';
	}

	var obj = {};
	var newStr = '';
	var len =  str.length;
	for(var i=0;i<len;i++){
		if(!obj[str.charAt(i)]){
			obj[str.charAt(i)] = 1;
			newStr = newStr+str.charAt(i);
		}
	}
	return newStr;
}
var str = 'abcdar';
console.log(removeMultiChar(str));

用一个新的变量保存没有重复的字母和search()函数匹配,没有找到则返回-1,否则返回字母的索引,charAt()

function remove(str){
  if(!str){
    return '输入类型不符合要求';
  }else if(typeof(str)!=='string'){
    return '输入参数必须为字符串';
  }
  var str1 = '';
  var len =str.length;
  var flag;
  for(var i=0;i<len;i++){
    flag = str1.search(str.charAt(i));
    if(flag < 0){
      str1 += str.charAt(i);
    }
  }
  return str1;
}
str = 'qqsa';
console.log( remove(str));

84、统计字符串中字母个数

可以将str转成arr,然后arr作为Set的参数,得到不重复的元素集合set,通过set.size获取元素个数

let str = 'aabbbss';
let set = new Set(str.split(''));
let len = set.size;

console.log(len); //3
function countCharsNum(str){
	if(!str){
		return '输入参数不能为空';
	}else if(typeof(str)!=='string'){
		return '输入参数必须为字符串';
	}
	var len = str.length;
	var obj = {};
	var num = 0;
	var curChar = '';
	for(var i=0;i<len;i++){
		curChar = str.charAt(i);
		if(!obj[curChar]){
			obj[curChar] = 1;
			num++;
		}
	}
	return num;
}

var str = 'abcdffffff';
console.log(countCharsNum(str));

84、统计字符号串中字最多字母数和字母;

function countMostChar(str){
	if(!str){
		return '输入不能为空';
	}else if(typeof(str) !=='string'){
		return '输入必须为字符串';
	}
	var obj = {};
	var len = str.length;
	var temp;
	var arr = [];
	var max = 0;
	for(var i=0;i<len;i++){
		temp = str.charAt(i);
		if(!obj[temp]){
			obj[temp] = 1;
		}else{
			obj[temp]++;
		}
	}
	for(var key in obj){
		if(max < obj[key]){
			max = obj[key];
			arr = [];
			arr.push(key);
		}else if(max == obj[key]){
			arr.push(key);
		}
	}
	return {
		'count':max,
		'char':arr
	};
}

var str = 'abbcda';
console.log(countMostChar(str));

84、统计字符号串“aaaabbbccccddfggh”中字母个数或统计最多字母数;

写一个函数count:统计传入字符串中每个字符的次数,并返回一个结果对象(区分大小写)

如count('javaScript')会返回一个统计结果对象,该对象表示 javaScript 的字符统计结果。

count('javaScript'); // 返回结果为 {j: 1, a: 2, v: 1, S: 1, c: 1, r: 1, i: 1, p: 1, t: 1}
function count(str) {
  var obj = {}; // 统计对象
  var i = 0;
  var len = str.length;
  for (; i < len; i++){
    var curChar = str.charAt(i); 
    // 如果结果对象存在该字符的属性,则自增,否则置为1
    if (obj[curChar]) {
      obj[curChar]++;
    } else {
      obj[curChar] = 1;
    }
  }
  // 返回结果
  return obj;
}

var str = "javaScript";
console.log(count(str));

写一个函数,获取输入字符串中字母的个数

function count(str) {
  var obj = {}; // 统计对象
  var i = 0;
  var len = str.length;
  for (; i < len; i++){
    var curChar = str.charAt(i); 
    // 如果结果对象存在该字符的属性,则自增,否则置为1
    if (obj[curChar]) {
      obj[curChar]++;
    } else {
      obj[curChar] = 1;
    }
  }
  // 返回结果
  var arr = Object.keys(obj);//通过Object.keys()获取对象可枚举属性所组成的数组,并通过length获取对象长度
  return arr.length;
}

var str = "javaScript";
console.log(count(str));

写一个函数,获取输入字符串中出现次数最多的字母或者字母出现最多的次数

function count(str) {
  var obj = {}; // 统计对象
  var i = 0;
  var len = str.length;
  var temp,max,element;
  for (; i < len; i++){
    var curChar = str.charAt(i); 
    // 如果结果对象存在该字符的属性,则自增,否则置为1
    if (obj[curChar]) {
      obj[curChar]++;
    } else {
      obj[curChar] = 1;
    }
  }

  max = 0;
  for( temp in obj ){
    if( max < obj[temp] ){
        max = obj[temp];
        element = temp;
    }
  }
  return element;    //出现次数最多的字母
  // return max //字母出现最多的次数

}

var str = "javaScript";
console.log(count(str));

85、写一个函数reWriteTrim,清除字符串前后的空格(兼容所有浏览器)

编程实现javascript在String中写一个trim,要求能够去除一个字符串开始和结尾的空格

// 用正则去匹配可以匹配任何的浏览器
function reWriteTrim(str){
    if (str && typeof str === "string") {
        return str.replace(/(^\s*)|(\s*)$/g,""); //去除前后空白符
    }
}


var str = " javaScript ";
console.log(reWriteTrim(str));

去除所有空格: str = str.replace(/\s*/g,"");     

去除两头空格: str = str.replace(/^\s*|\s*$/g,"");

去除左空格: str = str.replace( /^\s*/, “”);

去除右空格: str = str.replace(/(\s*$)/g, "");

86、实现一个函数clone,可以对javascript中5种主要的数据类型(包括number string object array boolean)进行值复制;

  /**
* 对象克隆
* 支持基本数据类型及对象,深度复制
* 递归方法
*/
function clone(obj) {
   var o;
   switch( typeof(obj) ){
        case 'undefined': o = obj; break;
        case 'string': o = obj +''; break;
        case 'number': o = obj - 0; break;
        case 'boolean': o = obj; break;
        case 'object':
            if( obj === null ){
                o = null;
            }else{
                 //注意Object.prototype.toString.call(obj)返回的是一个字符串'[object Array]',slice(8,-1)包括第一个括号,所以是8不是7
                if( Object.prototype.toString.call(obj).slice(8,-1)  === 'Array' ){
                    o = [];
                    for( var i =0;i<obj.length;i++ ){
                        o.push(clone(obj[i]));
                    }
                }else{
                    o = {};
                    for( var index in obj ){
                        o[index] = clone(obj[index]);
                    }
                }
            }
            break;
        default: o = obj; break;
   }
   return o;
}


var obj = {'a':1,'b':2};
var obj1 = clone(obj);
console.log(obj);

87、将数组[“a”,“b”,“c”]转化为字符串;

function arrayToString( arr ){
    var str = '';
    for(var i =0;i<arr.length;i++){
        str = str + (arr[i]);
    }
    return str;
}

var arr = ['a','b','c'];
console.log(arrayToString(arr));
console.log(arr.join(''));

88、获取event目标对象的方法(要求兼容性);

// 事件对象的获取很简单,很久前我们就知道IE中事件对象是
// 作为全局对象( window.event )存在的,Firefox中则是做为
// 句柄( handler )的第一个参数传入内的
// 所以一行代码就可以搞定
var evt = window.event || arguments[0]; 
// 添加事件监听使用addEventListener或IE专有的attachEvent 
<div id="d4">Div4 Element</div> 
<script type="text/javascript"> 
    var d4 = document.getElementById('d4'); 

    function clk(){
        alert(window.event);
    } 

    if(d4.addEventListener){ 
        d4.addEventListener('click',clk,false); 
    } 
    if(d4.attachEvent){ 
        d4.attachEvent('onclick',clk); 
    } 
</script> 

89、去除字符串中多余的字母---将字符串str转成数组arr,数组作为Set()的参数---new Set(arr) = set,则无重复元素数组arr1=[...set],则无重复字符串str1 = arr1.join('')

// 一:遍历数组法
// 新建一新数组,遍历传入数组,值不在新数组就加入该新数组中;注意点:
// 判断值是否在数组的方法“indexOf”是ECMAScript5 方法,IE8以下不支持,
// 需多写一些兼容低版本浏览器代码
// function removeMultiElement(arr){
//     // 判断浏览器是否支持indexOf ,indexOf 为ecmaScript5新方法 IE8以下(包括IE8, IE8只支持部分ecma5)不支持
//     if (!Array.prototype.indexOf){
//       // 新增indexOf方法
//       Array.prototype.indexOf = function(item){
//         var result = -1, a_item = null;
//         if (this.length == 0){
//           return result;
//         }
//         for(var i = 0, len = this.length; i < len; i++){
//           a_item = this[i];
//           if (a_item === item){
//             result = i;
//             break;
//           }  
//         }
//         return result;
//       }
//     }

//     var newArr = [];
//     var len = arr.length;
//     for( var i =0;i<len;i++ ){
//         // indexOf()函数返回找到元素的下标,找不到则返回-1
//         if( newArr.indexOf(arr[i]) == -1 ){
//             newArr.push(arr[i]);
//         }
//     }

//     return newArr;
// }

// 二:数组下标判断法:
// 还是得调用“indexOf”性能跟方法1差不多,实现思路:
// 如果当前数组的第i项在当前数组中第一次出现的位置不是i,
// 那么表示第i项是重复的,忽略掉。否则存入结果数组。


// function removeMultiElement(arr){
        // 判断浏览器是否支持indexOf ,indexOf 为ecmaScript5新方法 IE8以下(包括IE8, IE8只支持部分ecma5)不支持
//     if (!Array.prototype.indexOf){
//       // 新增indexOf方法
//       Array.prototype.indexOf = function(item){
//         var result = -1, a_item = null;
//         if (this.length == 0){
//           return result;
//         }
//         for(var i = 0, len = this.length; i < len; i++){
//           a_item = this[i];
//           if (a_item === item){
//             result = i;
//             break;
//           }  
//         }
//         return result;
//       }
//     }
//     var n = [arr[0]]; //结果数组
//     var len = arr.length;
//     //从第二项开始遍历
//     for(var i = 1; i < len; i++) {
//         //如果当前数组的第i项在当前数组中第一次出现的位置不是i,
//         //那么表示第i项是重复的,忽略掉。否则存入结果数组
//         if (arr.indexOf(arr[i]) == i){
//             n.push(arr[i]);
//         }
//     }
//     return n;
// }

// 方法三:优化遍历数组法,类似选择排序
// 思路:获取没重复的最右一值放入新数组(检测到有重复值时终止当前循环同时进入顶层循环的下一轮判断)
// function removeMultiElement(arr){
//   var r = [];
//   for(var i = 0, len = arr.length; i < len; i++) {
//     for(var j = i + 1; j < len; j++){
//        if (arr[i] === arr[j]) j = ++i;
//     }
//     r.push(arr[i]);
//   }
//   return r;
// }

var arr = [17,6,1,6];
console.log(removeMultiElement(arr));
function removeStr(str){
	if( str && (typeof(str) === 'string') ){
		var len = str.length;
		var newStr = '';
		for(var i=0;i<len;i++){
			for(var j=i+1;j<len;j++){
				if(str.charAt(i)===str.charAt(j)){
					j=++i;
				}
			}
			newStr = newStr + str.charAt(i);
		}
		return newStr;
	}else{
		return '输入参数不符合要求';
	}
}

var str='sssdd';
console.log(removeStr(str));

89、给定arr1,arr2合并去重,返回result

concat() + Set() +...

let arr1 = [1,1,2];
let arr2 = [2,3,3];
let arr3 = arr1.concat(arr2);
let set = new Set(arr3);
let arr4 = [...set];
console.log(arr4);
function concatAndDisRepeat(arr1,arr2){
  if(arguments.length !== 2){
    console.log('参数个数为2个');
    return
  }else if(arguments[0].constructor !== Array || arguments[1].constructor !== Array){
    console.log('参数必须为数组');
    return
  }else if( arr1.length===0 && arr2.length===0 ){
    console.log('数组不能为空');
    return [];
  }
  var arr = arr1.concat(arr2);
  var flag;
  var result = [];
  arr.forEach(function(ele){
    flag = result.indexOf(ele);
    if( flag === -1 ){
      result.push(ele);
    }
  });
  return result;
}

arr1 = [1,1,2];
arr2 = [1,2,3];
console.log(concatAndDisRepeat(arr1,arr2));

第三阶段 WebApp、jQuery、Ajax、JSONP、MVVM框架、Nodejs

1、什么是Web workers?为什么我们需要他

A、Web workers的定义:Web Workers为WEB前端网页上的脚本,提供了一种能在后台进程中运行的方法。
一旦它被创建,Web Workers就可以通过postMessage()向任务池发送任务请求,
执行完之后再通过postMessage()返回消息给创建者指定的事件处理程序(通过onmessage进行捕获)。 


Web Workers进程能够在不影响用户界面的情况下处理任务,并且,它还可以使用XMLHttpRequest来处理I/O
,无论responseXML和channel属性是否为null。

B、使用Web workers的原因:通过使用Web Worker, 我们可以在浏览器后台运行Javascript, 而不占用浏览器自身线程(Web work实现多线程)。Web Worker可以提高应用的总体性能,并且提升用户体验。
 

<span style="color:#cc33cc">Web Worker主线程</span>
  1.通过 worker = new Worker( url ) 加载一个JS文件来创建一个worker,同时返回一个worker实例。

   2.通过worker.postMessage( data ) 方法来向worker发送数据。

   3.绑定worker.onmessage方法来接收worker发送过来的数据。

   4.可以使用 worker.terminate() 来终止一个worker的执行。

在项目中用过哪些js插件?

1)主要是用了jquery插件去实现大部分的功能以及书写形式以及Bootstrap.js

2)用了一个提示插件toastr.js,可以以弹窗提示的效果呈现

3)在移动端用了一个具有触摸滑动效果的插件swiper.js,比如轮播图播放以及手动滑动效果

4)在PC端用了一个轮播图的插件masterSlider.js,用来展示自定义背景图的一些默认图片,左边是一张大图显示,右边是小图的形式展示

5)Velocity 是一个简单易用、高性能、功能丰富的轻量级JS动画库。它能和 jQuery 完美协作,并和$.animate()有相同的 API, 但它不依赖 jQuery,可单独使用。 Velocity 不仅包含了 $.animate() 的全部功能, 还拥有:颜色动画、转换动画(transforms)、循环、 缓动、SVG 动画、和滚动动画 等特色功能。


它比 $.animate() 更快更流畅,性能甚至高于 CSS3 animation, 是 jQuery 和 CSS3 transition 的最佳组合,它支持所有现代浏览器,最低可兼容到 IE8 和 Android 2.3。

2、列一个手机端可以实现手势滑动的插件或类库(移动端触摸滑动插件)

A、zepto库

B、jquery UI

C、swiper.js(官网地址),具有开源、免费、功能强大的特点,是目前应用较广泛的移动端网页触摸内容滑动js插件

D、TouchSlide(官网地址),TouchSlide 是纯javascript打造的触屏滑动特效插件,面向手机、平板电脑等移动终端,能实现触屏焦点图、触屏Tab切换、触屏多图切换等常用效果。也是大话主席 superslide旗下的一款移动端触摸滑动插件。superslide也是PC端优秀的js特性插件。

E、iSlider(地址),iSlider是一个表现出众,无任何插件依赖的手机平台javascript滑动组件。它能够处理任何元素,例如图片或者DOM元素。是百度团队开发完成的。同时-iSlider也是目前最 轻量、高性能的移动滑动方案。 

F、better-scroll

3、请说一下移动端常见的适配不同屏幕大小的方法。

A、响应式布局:就是页面元素的位置随着屏幕尺寸的变换而变化,通常使用百分比来定位,而在设计上要预留一些可被“压缩”的空间

1)rem缩放    2)使用功能百分比+媒体查询      3)使用flexbox解决方案

B、Cover布局:就是跟background-size的cover属性一样,保持页面的宽高比,取宽或者高之中的较小者占满屏幕,超出的内容会被隐藏。此布局适合于主要内容集中在中部边沿没有重要内容的设计

C、Contain布局:根background-size的contain属性一样,保持页面的宽高比,取宽或者高中的较大者占满屏幕不足的部分用背景填充。设计上需要背景为单色或者可平铺的背景。

4、本地存储(包括localStorage和sessionStorage)和cookies之间的区别是什么?(请描述一下 cookies,sessionStorage 和 localStorage 的区别)

localStorage冲突如何解决?-----同时好多人向localStorage写数据,如果有重复的key怎么解决

1)可以针对功能给key加前缀

什么是本地存储(Web storage)?

通过本地存储(Local Storage),web 应用程序能够在用户浏览器中对数据进行本地的存储

在 HTML5 之前,应用程序数据只能存储在 cookie 中,包含在每个服务器请求本地存储则更安全,其信息不会被传输到服务器,并且可在不影响网站性能的前提下,将大量数据存储于本地,一般是5MB左右,cookie 一般4kB左右。

本地存储经由起源地(origin)(经由域和协议)。所有页面,从起源地,能够存储和访问相同的数据

什么是cookie?

cookie是由W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。  文章- 1  评论- 13 

由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。

HTML5 存储类型有哪些,以及与他们的区别,本地存储的类别

HTML 本地存储提供了两个在客户端存储数据的对象:

a) window.localStorage - 存储没有截止日期的数据,当浏览器被关闭时数据不会被删除,在下一天、周或年中,都是可用的

b) window.sessionStorage - 针对一个 session 来存储数据(当关闭浏览器标签页时数据会丢失)

localStorage和sessionStorage的相同点:

● localStorage和sessionStorage都是本地存储在客户端存储数据的对象

● 他们都只能存储字符串类型的对象

● 不同的浏览器无法共享localStorage或sessionStorage中的信息

localStorage和sessionStorage的不同点:

● localStorage生命周期是永久的,这意味着除非用户显示在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在。

● sessionStorage生命周期为当前窗口或标签页,一旦窗口或标签页被关闭了,那么所有通过sessionStorage存储的数据也就被清空了。

● 相同浏览器的不同页面间可以共享相同的 localStorage(页面属于相同域名和端口)

 相同浏览器的不同页面或标签页间无法共享sessionStorage的信息。这里需要注意的是,页面及标签页仅指顶级窗口,如果一个标签页包含多个iframe标签且他们属于同源页面,那么他们之间是可以共享sessionStorage的。

Cookie:保存登录信息
localStorage:保存购物车信息,游戏数据
sessionStorage:需要在一些页面共享数据

不要在存储系统中存储敏感信息,或者进行加密

下面来看看localStorage和sessionStorage以及cookie的具体区别

实现度对cookie的封装

<!doctype html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <title>alert标签名</title>  
</head>  
<body>  
    <script>  
        setCookie('age','1');  
        var age = getCookie('age');  
        console.log(age);  
        delCookie('age');  
         age = getCookie('age');  
        console.log(age);  
        //设置cookie  
        function setCookie(name, value, days) {  
            days = days || 30;  
            var exp = new Date();  
            exp.setTime(exp.getTime() + days * 24 * 60 * 60 * 1000);//toUTCString()将根据世界时,将日期对象转换为字符串  
            document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + ";expires=" + exp.toUTCString();  
        }  
        //获取cookie  
        function getCookie(name) {  
            var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");  
            if (arr = document.cookie.match(reg)){  
              //getCookie('name')  
              //结果: ["name=jiang;", "", "jiang", ";", index: 0, input: "name=jiang; name=jiang", groups: undefined]  
              console.log(arr);  
               return decodeURIComponent(arr[2]);  
            }  
            else return null;  
  
        }  
        //删除cookie  
        function delCookie(name) {  
            var exp = new Date();  
            exp.setTime(exp.getTime() - 1);  
            var value = getCookie(name);  
            if (value != null){  
               document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + ";expires=" + exp.toUTCString();  
            }   
        }  
    </script>  
</body>  
</html>  

cookie有哪些字段,携带在HTTP的请求头中,cookie的字段

5、前端存储的类型有哪些(针对客户端)

1、cookie,H5之前存储主要是用cookies。cookies缺点客户端每次发送请求的时候都会讲数据携带在HTTP请求头中,存储数据的大小是4k之内。可以设置数据的有效期,默认是关闭浏览器失效。cookie存储不安全,可以被盗取cookie中的信息
主要应用:购物车、客户登录

2、本地存储localStorage:设置的数据永久有效,除非人为删除;每一个域名存储的数据大小是5M;数据存储在客户端浏览器中,不会和服务端发生交互;

3、本地存储sessionStorage:针对当前会话有效,一旦关闭浏览器则失效;每一个域名存储的数据大小是5M;数据存储在客户端浏览器中,不会和服务端发生交互

4、离线缓存(Application Cache):离线浏览、 提升页面载入速度、 降低服务器压力

5、Web SQL:关系数据库,通过SQL语句访问。Web SQL 数据库 API 并不是 HTML5 规范的一部分,但是它是一个独立的规范,引入了一组使用 SQL 操作客户端数据库的 APIs, Web SQL 数据库可以在最新版的 Safari, Chrome 和 Opera 浏览器中工作

6、IndexedDB:索引数据库 (IndexedDB) API(作为 HTML5 的一部分)对创建具有丰富本地存储数据的数据密集型的离线 HTML5 Web 应用程序很有用。同时它还有助于本地缓存数据,使传统在线 Web 应用程序(比如移动 Web 应用程序)能够更快地运行和响应

7、userData:IE支持

服务端:

session

5、浏览器缓存有哪些

1)强缓存:强缓存如果命中,浏览器直接从自己的缓存中读取资源,不会发请求到服务器

2)协商缓存:当强缓存没有命中的时候,浏览器一定会发送一个请求到服务器,通过服务器端依据资源的另外一些http header验证这个资源是否命中协商缓存,如果协商缓存命中,服务器会将这个请求返回(304),若未命中请求,则将资源返回客户端,并更新本地缓存数据(200)

5、cookie、session、application区别

1)cookie数据存放在客户的浏览器上,session数据放在服务器上

cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗(cookie劫持);同时用户可以在console中看到所有的cookie并通过document.cookie修改cookie

解决cookie安全性问题:

a)、在服务端对cookie使用密钥进行加密

考虑到安全应当使用session

单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie

每次发送请求的时候,cookie中的数据都会携带在HTTP请求头,如果数据存放过多就会造成网页性能下降的问题

cookie可以设置失效的时间,默认是关闭浏览器的时候失效

2)session会在一定时间内保存在服务器上,也可以设置有效期,默认是关闭浏览器就失效

当访问增多,会比较占用你服务器的性能

考虑到减轻服务器性能方面,应当使用COOKIE

session基于cookie实现的,cookie中有一个session的id,服务器利用sessionId找到session文件、读取、写入

不安全:由于用户可以看到所有的cookie信息,那么也可以看到sessionId,从而可以实现session劫持

所以个人建议: 将登陆信息等重要信息存放为session, 其他信息如果需要保留,可以放在cookie中

3)Application   数据存储在服务器端,可以存储任意大小的数据,多个用户共享的应用级别的作用域,相比前两者,这个存在时间是最长的,只有当关闭服务器的时候才失效

详细介绍链接:https://www.cnblogs.com/breezeblew/archive/2008/05/02/1179143.html

点击打开链接

7、异步加载js的方式有哪些?同步和异步的区别?如何解决跨域问题

为什么异步加载js文件?加载方式?(至少两种方式)

异步加载的方式有4种

a)  使用jquery框架,即$(document).ready(function(){})或者写成$(function(){}),(DOM结构绘制完毕就执行,不必等到所有资源都加载完成)。注意需要引入jquery并且能兼容所有浏览器

$(document).ready(function() {
    alert("加载完成!");
});

b)  给<script>标签添加属性async='async'

async属性只适用于外部脚本,不能保证脚本按顺序执行,异步下载一旦下载完立即执行会阻塞页面渲染,HTML5新增属性需要chrom  firefox ie9支持

<script type="text/javascript" src="xxx.js" async="async"></script>

c)  给<script>标签添加属性defer='defer'

defer属性只适用于外部脚本,能保证脚本按顺序执行,异步下载等到DOM树渲染完之后才执行,兼容所有浏览器。

<script type="text/javascript" src="xxx.js" defer="defer"></script>

d)加载es6模块的时候设置type=module,默认应用defer属性----即HTML解析器在遇到有src属性的<script type='module'>时,模块文件便开始下载,直到文档被完全解析,模块才会执行

<script  type='module'  src='module.js'></script>

d)  动态创建<script>标签,并插入到document中,这样就做到非阻塞的下载js代码。兼容所有浏览器。立即开始异步加载 js

(function(){
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = "http://code.jquery.com/jquery-1.7.2.min.js";
    var tmp = document.getElementsByTagName('script')[0];
    tmp.parentNode.insertBefore(script, tmp);
})();

e)  onload时的异步加载,在低版本的IE中不能用onload()

(function() {
     function async_load(){
         var s = document.createElement('script');
         s.type = 'text/javascript';
         s.async = true;
         s.src = 'js/jQuery.js';
         var x = document.getElementsByTagName('script')[0];
         x.parentNode.insertBefore(s, x);
     }
     if (window.attachEvent)
         window.attachEvent('onload', async_load);//IE浏览器下,事件名要加上on
     else
         window.addEventListener('load', async_load, false);//非IE下,事件名不需要加上on
 })(); 

这和前面的方式差不多,但关键是它不是立即开始异步加载 js ,而是onload 时才开始异步加载。这样就解决了阻塞onload 事件触发的问题。

判断js加载完成,实现按需加载,兼容IE

function  loadScript(url,calback){  
  
    var script = document.createElement('script');  
  
    script.type = 'text/javascript';  
  
    script.async = 'async';  
  
    script.src  = url;  
    var reg = /^(complete|loaded)$/  
  
    document.body.appendChild(script);  
  
    if(script.readyState){  
        //IE下  
        script.onreadystatechange = function(){      
            if( reg.test(script.readyState) ){       
                script.onreadystatechange = null;  
                callback();  
            }  
         }  
  
    }else{  
        script.onload = function(){  
            callback();  
        }  
    }  
}  

补充:DOMContentLoaded 与 OnLoad 事件

DOMContentLoaded : 页面(document)已经解析完成,页面中的dom元素已经可用。但是页面中引用的图片、subframe可能还没有加载完

OnLoad:页面的所有资源都加载完毕(包括图片)。浏览器的载入进度在这时才停止。

同步加载和异步加载的区别

a)  同步加载:我们平时最常使用的就是在一个<script>标签里面只有一个src属性,并且给这个src属性赋值,这就是同步加载模式。

<script src="js/jQuery.js"></script> 

同步加载,又称阻塞加载,会阻止浏览器的后续处理解析,因此停止了后续的文件加载(如图像)、渲染、代码执行。

b)  异步加载:异步加载又叫做非阻塞加载,浏览器在下载或者执行js的同时,还会继续进行后续页面的处理

区别:同步加载网络 timeline 是瀑布模型,而异步加载的网络 timeline 是并发模型

8、HTML中支持onload事件的标签元素

<body>, <script>,<link>,<img>,<frame>, <frameset>, <iframe> 

8、Web应用从服务器主动推送Data到客户端有那些方式

a)  AJAX 轮询(long-polling)方式

实现方式简单,前端浏览器都支持。但是这种方式会有非常严重的问题,客户端不断的向服务器发起请求,导致服务器资源浪费,且会加重网络负载

传统的Ajax轮询方式:客户端定时向服务器端发送请求,服务端接收到请求后马上回应,不管数据是否有效。

Ajax长轮询:它是Ajax轮询的升级版,客户端向服务器端发送请求,服务端接收到请求后,保持连接,检查数据是否有更新,有的话返回信息并断开连接;数据没有更新的话,就一直和客户端保持连接,不返回信息。等到了服务端设置的超时的时间之后,还是没有检查到数据更新,那么服务端就会返回超时消息。客户端这边,不管请求成功还是失败,或者请求超时,都会再次向服务端发送请求。这一过程,在这一页面在浏览器打开期间,都会循环不断。

function checkStatus(){
	var url = '填写具体的请求地址';
	var data = {用POST请求方式,则需要一些一些数据};//GET方法不需要数据data变量
	//这里使用jquery中封装的方法$.ajax()
	$.ajax({
		url:url,
		data:data,
		type:'POST',
		datatype:'json',
		timeout:200000,
		success:function(res){
			//todo
			checkStatus();
		},
		error:fucntion(res){
			//tode
			checkStatus();
		},
		complete:fucntion(XMLHttpRequest,statusText){
			if(statusText==='timeout'){
				//todo
				checkStatus();
			}
		}
	});
}

b) comet方式:comet是一种用于web的推送技术,能够让服务器实时的将更新的信息传送到客户端,而不需要客户端发出请求。

目前实现comet方式的方法有两种:

一:长轮询:长轮询 (long polling) 是在打开一条连接以后保持,等待服务器推送来数据再关闭,可以采用HTTP长轮询和XHR长轮询两种方式。

HTTP长轮询+JSONP长轮询:把 script 标签附加到页面上以让脚本执行。服务器会挂起连接直到有事件发生,接着把脚本内容发送回浏览器,然后重新打开另一个 script 标签来获取下一个事件,从而实现长轮询的模型。

XHR长轮询:客户端发送一个到服务器端的 AJAX 请求,然后等待响应;服务器端需要一些特定的功能允许请求被挂起,只要一有事件发生,服务器端就会在挂起的请求中送回响应并关闭该请求。客户端 JavaScript 响应处理函数在处理完服务器返回的信息后,再次发出请求,重新建立连接;如此循环。

二、<iframe>标签:一种 HTML 标记, 通过在 HTML 页面里嵌入一个隐蔵帧,然后将这个隐蔵帧的 SRC 属性设为对一个长连接的请求,服务器端就能源源不断地往客户端输入数据

c)  HTML5新引入的WebSocket,可以实现服务器主动发送数据至网页端,它和HTTP一样,是一个基于HTTP的应用层协议,跑的是TCP,即依赖 HTTP 协议进行一次握手 ,握手成功后,数据就直接从 TCP 通道传输,与 HTTP 无关了。所以本质上还是个长连接,双向通信,意味着服务器端和客户端可以同时发送并响应请求,而不再像HTTP的请求和响应模式。

WebSocket的定义:

WebSocket 是Web应用程序的传输协议,它提供了双向的,按序到达的数据流。他是一个Html5协议,WebSocket的连接是持久的,他通过在客户端和服务器之间保持双工连接,服务器的更新可以被及时推送给客户端,而不需要客户端以一定时间间隔去轮询

为什么需要WebSocket?

● HTTP 协议是一种无状态的、无连接的、单向应用层协议

● 它采用了请求/响应模型

● 通信请求只能由客户端发起,服务端对请求做出应答处理

● 这种通信模型有一个弊端:HTTP 协议无法实现服务器主动向客户端发起消息

● 这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦

● 大多数 Web 应用程序将通过频繁的异步JavaScript和XML(AJAX)请求实现长轮询

● 轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)

因此WebSocket应运而生,需要一种可以保持连接、进行全双工通信的协议

● WebSocket 连接允许客户端和服务器之间进行全双工通信,以便任一方都可以通过建立的连接将数据推送到另一端● WebSocket 只需要建立一次连接,就可以一直保持连接状态,这相比于轮询方式的不停建立连接显然效率要大大提高

WebSocket的应用场景

实时性要求高的场景:社交聊天、弹幕、多玩家游戏、协同编辑、股票基金实时报价、体育实况更新、视频会议/聊天、基于位置的应用、在线教育、智能家居等需要高实时的场景

WebSocket表示当前状态的readyState属性,属性值如下:

WebSocket.OPENING(0):正在连接
WebSocket.OPEN(1):已经建立连接
WebSocket.CLOSING(2):正在关闭连接
WebSocket.CLOSE(3):已经关闭连接

WebSocket发送数据:send(任意字符串),复杂数据需要将数据系列化,如下面所示:

var message ={
   time:new Date(),
    text:'hi'
}
socket.send(JSON.stringify(message));

WebSocket接收数据:服务器向客户端发送信息,触发message()事件,把数据存在event.data中

socket.onmessage=function(event){
  var data = event.data;
}

WebSocket其他事件

open():在成功建立连接时触发

error():在发生错误时触发,连接不能持续

close():在连接关闭时触发

9、jQuery中如何将数组转化为json字符串,然后在转化回来

JSON.stringify()方法,将数组和对象转换成json字符串

JSON.parse()方法,把一个json字符串解析成对象

10、调用new的过程发生了什么?

1)创建了一个实例对象(一个空对象)

2)该实例对象继承构造函数的原型中的属性和方法

3)构造函数中的this对象指向该实例对象

4)执行构造函数。如果构造函数中显式的返回了一个对象,那么new出的就不再是新创建的空对象,而是return指定的对象。否则一律返回新建空对象

10、简单概括一下jQuery的实现原理

1)jQuery的代码都是写在一个立即执行函数里面,形成私有作用域,避免命名空间污染

2)window 对象上有两个公共的接口,分别是 $ 和 jQuery:

window.jQuery = window.$ = jQuery;

 这一句话将我们在闭包当中定义的jQuery对象导出为全局变量jQuery和$,因此我们才可以在外部直接使用jQuery和$window是默认的JS上下文环境,因此将对象绑定到window上面,就相当于变成了传统意义上的全局变量

3)jQuery.fn指向jQuery.prototype,这样可以达到书写简洁的目的。

2)jQuery()和$()是jQuery中最常用的方法,他们的调用结果是返回一个jQuery实例对象

3)编写组件通常的做法是将组件封装成一个对象,需要用的时候则通过new运算符来创建一个实例。但是jQuery( )无须我们用new手工实例化,它会自动返回一个实例(即隐藏了new的过程)。这是因为在jQuery()函数中返回了jQuery.prototype.init()的实例对象,而jQuery.prototype.init.prototype=jQuery.prototype,这样new出来的init()实例对象能继承所有jQuery的方法,从而解决函数调用的问题。

var nodeList = (context || document).querySelectorAll(selector);

init()函数中将DOM节点赋值给了自己this[i] = nodeList[i],因此返回的init对象是一个类数组,包含了DOM节点列表,还包括一些其他的方法。

var jQuery = function(){
  return new jQuery.prototype.init();
}
jQuery.prototype = {
  constructor: jQuery,
  init: function(){
    this.jquery = 1.0;
    return this;
  },
  jquery: 2.0,
  each: function(){
    console.log('each');
    return this;
  }
}
jQuery.prototype.init.prototype = jQuery.prototype;
jQuery().each() //'each'

这样就形成了jQuery的一个核心框架

4)jQuery中的链式调用,使得代码书写简洁,而且返回的都是同一个对象,提高代码效率。实现原理是在原型函数的后面返回this对象

5)jQuery中的一个重要函数extend(),可以对本身 jQuery 的属性和方法进行扩展(jQuery.extend()---静态函数),又可以对原型的属性和方法进行扩展(jQuery.fn.extend---实例函数)。如果extend()函数只有一个object对象参数,那么将该object扩展到jQuery的命名空间中(浅拷贝);如果有多个object,则表示将第二个参数及之后的参数属性拷贝到第一个对象上(浅拷贝);如果第一个参数是boolean类型,true表示深拷贝,false表示浅拷贝。如果有两个参数,那么将第二个参数object的属性拷贝到jQuery的命名空间中;如果有多于两个参数,那么就将第三个参数及之后的参数的属性拷贝到第二个参数上面。

6)jQuery中的ready()方法:它的实现原理就是,维护一个函数数组,然后通过监听DOMContentLoaded事件,不停的判断DOM是否加载完毕,通过标记isReady是否被设置来判断,未被设置那就是说页面未加载完,就会把要执行的函数用一个数组缓存起来,当页面加载完后,再把缓存的函数一一执行

具体实现:

jquery脚本加载的时候,会设置一个isReady的标记,监听DOMContentLoaded事件(这个不是什么浏览器都有的,不同浏览器,jquery运作方式不一样).当然遇到调用ready函数的时候,如果isReady未被设置,那就是说页面未加载完,就会把要执行的函数用一个数组缓存起来,当页面加载完后,再把缓存的函数一一执行

页面加载过程:

  1. 解析HTML结构
  2. 加载并解析外部脚本
  3. DOM树构建完成,执行脚本    //DOMInteractive –> DOMContentLoaded
  4. 加载图片、样式表文件等外部文件
  5. 页面加载完毕   //window.onload

涉及到的事件

a)DOMContentLoaded: 
触发时机
:当页面的DOM树解析好触发 ;DOMContentLoaded事件不直接等待CSS文件、图片的加载完成

b)document.onload: 
触发时机当整个html文档加载的时候就触发了,也就是在body元素加载之前就开始执行了

c)window.onload: 
当页面全部加载完成(包括所有资源)

d)onreadytstatechange: 
对象状态变更时触发这个事件,一旦document的readyState属性发生变化就会触发

原生JS的window.onload与jquery的$(document).ready(function(){}) 有什么不同?

window.onload是js原生的事件,$(function(){})是Jquery的方法(等价于$(document).ready(function(){}) )

两者的区别:

● window.onload():当页面所有的资源都加载完成之后,才执行window.onload()方法。如果同一个js文件里面定义了多个window.onload(),那么只执行最后一个window.onload()方法

● $(function(){}):监听DOMContentLoaded事件,在DOM树渲染完成后执行该方法,如果有多个定义依次执行

可以看出$(function(){})在window.onload前执行

比如:页面中只有一个img标签,当img节点创建完后就会执行$(function(){})中的代码,当img的src指定的图片完全加载完后才会触发window.onload事件。

document.ready的实现----通过监听事件DOMContentLoaded

document.ready = function(callback) {
    if (document.addEventListener) {
        document.addEventListener('DOMContentLoaded', function() {
            document.removeEventListener('DOMContentLoaded', arguments.callee, false);
            callback();
        }, false);
    }else if (document.attachEvent) {// 兼容ie
        document.attachEvent('onreadytstatechange', function() {
            if (document.readyState == "complete") {
                document.detachEvent("onreadystatechange", arguments.callee);
                callback();
            }
        });
    }
}

jQuery的编码逻辑核心

1)、查找(创建)jQuery对象:$("selector");

2)、调用jQuery对象的方法,完成我们需要完成的工作:$("selector").doOurWork();

下面是对理解源码的一些问题

1)为什么$(selector)之后,返回的是jQuery对象?

答:从jQuery的源代码中,我们可以知道:var $ = jQuery 。因此当我们$(selector)操作时,其实就是jQuery(selector),创建的是一个jQuery对象。当然正确的写法应该是这样的:var jq = new $(selector); 而jQuery使用了一个小技巧在外部避免了new,在jquery方法内部:

var jQuery = function(){
  return new jQuery.prototype.init();
}

2)为什么创建一个jQuery对象之后,我们可以这样写$(selector).each(function(index){…});进行遍历操作呢?
答:其实jQuery(selector)方法调用时,在jQuery(selector)方法内部最后返回的是一个数组:return this.setArray(a); 而each方法体内部是一个for循环,在循环体内是这样调用的:method.call(this[i],i)

3)为什么jQuery能做到jQuery对象属性/方法/事件的插件式扩展?
答:如果您有一些javasciprt的面向对象方面的知识,就会知道,在jQuery.prototype原型对象上的扩展属性/方法和事件,将会给jQuery的对象“扩展”。基于这一点,jQuery是这样写的:jQuery.fn = jQuery.prototype 

10、jQuery.fn.init()中返回的this指的是什么对象?为什么要返回this?

init()方法中返回的this指向init的实例对象,而init.prototype等于jQuery.prototype,所以也是jQuery的实例对象;

返回this是为了实现链式调用

10、jQuery中如何将数组转化为json字符串,然后在转化回来

array是特殊的object,可以利用object的JSON.stringify()转化为json字符串,在利用JSON.parse()转化回来

10、jQuery.extend()和jQuery.fn.extend()的区别

jQuery.extend()是给jQuery对象或者其他对象扩展属性和方法的;jQuery.fn.extend()是给jQuery实例对象扩展属性和方法的

10、一个jQuery对象可以同时绑定多个事件,这是如何实现的

底层实现原理是利用addEventListener()和attachEvent()做了兼容事件绑定

10、给jQuery扩展一个新的空方法,方法名称为newFunc

有两种实现方法:扩展到对象层面--jQuery.extend(),扩展的是静态方法,可以直接使用$调用;扩展到选择器函数对象层面----jQuery.fn.extend(),扩展的方法是实例的方法,由$('#id名')或者$('.类名')调用

$.fn是指jquery的命名空间,在选择器函数对象层面上添加方法

jQuery.extend() = jQuery.fn.extend()实现对对象的扩展,可以给jQuery扩展属性方法,同时可以实现深复制的功能和浅复制的功能

extend()方法实现的功能

1)将两个或更多对象的内容合并到第一个对象(如果只有一个参数对象,则将其扩展到jQuery对象上)---实现默认字段的覆盖

浅拷贝

jQuery.extend( target [, object1 ] [, objectN ] )
function getOpt(target, obj1, obj2, obj3){
 $.extend(target, obj1, obj2, obj3);
 return target;
}
 
var _default = {
 name : 'wenzi',
 age : '25',
 sex : 'male'
}
var obj1 = {
 name : 'obj1'
}
var obj2 = {
 name : 'obj2',
 age : '36'
}
var obj3 = {
 age : '67',
 sex : {'error':'sorry, I dont\'t kown'}
}
getOpt(_default, obj1, obj2, obj3); // {name: "obj2", age: "67", sex: {error: "sorry, I dont't kown"}}

$.extend()其实是有返回值的,返回的就是修改后的第一个参数的值

2)为jQuery扩展方法或属性----如果extend()函数只传一个对象参数,jQuery对象本身被默认为目标对象,浅拷贝

$.extend({
 _name : 'wenzi',
 _getName : function(){
    return this._name;
 }
})
 
$._name; // wenzi
$._getName(); // wenzi

3)深度拷贝和浅度拷贝----若第一个参数是boolean类型,且值是true(深拷贝)或者false(浅拷贝),把第二个参数作为目标参数进行合并

jQuery.extend( [deep ], target, object1 [, objectN ] )
                //深复制
                var obj = {name:'wenzi', score:80};
                var obj1 = {score:{english:80, math:90}}
                $.extend(true, obj, obj1);
                obj.score.english = 10;
                console.log(obj.score.english); // 10
                console.log(obj1.score.english); // 80

                //浅复制
                var obj = {name:'wenzi', score:80};
                var obj1 = {score:{english:80, math:90}}
                $.extend(false, obj, obj1);
                obj.score.english = 10;
                console.log(obj.score.english); // undefined
                console.log(obj1.score.english); // 80

a) 扩展到jQuery对象层面

        jQuery.extend({
            newFun: function(){
                console.log('hello');
            }
        });//扩展到对象层面,$.newFun();这样调用
        $.newFun(); //调用

b) 扩展到选择器函数对象层面:

        jQuery.fn.extend({
            newFun: function(){
                console.log('hello');
            }
        });//选择器层面。通过$("选择器表达式").newFun();这样调用
        $('div').newFun()

jQuery中的extend()实现原理,如何实现深拷贝(递归赋值)

大致过程:对后一个参数进行循环,然后把后面参数上所有的字段都给了第一个字段,若第一个参数里有相同的字段,则进行覆盖操作,否则就添加一个新的字段

1)对第一个参数做判断,如果不是Boolean类型,且只有一个参数,那么就把jQuery作为target,然后把第一个参数上的字段都赋给target,最后返回target(浅拷贝);如果有多于一个参数,那么第一个参数就是target,然后把后面参数的字段都赋给target,最后返回target(浅拷贝)

2)第一个参数是boolean类型,表示深浅拷贝,true表示深拷贝,false表示浅拷贝。只有两个参数,那么就把jQuery作为target,把第二个参数的字段赋给target,然后返回target。多于两个参数,把第二个参数作为target,然后把后面的参数的字段赋给target,最后面返回target.

具体思路:

1)保存第一个参数到target变量中,如果没有参数则target={},将变量i初始化为1,用变量length保存实际传参个数,变量deep初始化为false(用于判断是否为深度遍历)

2)接着判断第一个参数即target是否为boolean类型,如果是的话,将第一个参数即target赋值给deep,target的值变成第二个参数的值,如果没有第二个参数,那么target={},修改i=2。如果不是直接跳到第3)步

3)如果目标参数即target既不是Object也不是Function,那么target={}

4)如果目标参数target后面没有参数了(i=1或者第一个参数为boolean类型的有2个参数的情况,i = length判断),则目标对象target=this表示jQuery对象,而target表示的参数不在是目标对象,此时i--。【一个参数且为对象i=0;两个或以上对象参数i=1;有两个参数第一个参数为Boolean第二个为object,i=1;有两个或以上参数,第一个为Boolean,剩下的为object,i=2】

5)从下标i开始,对参数进行遍历,  如果参数不为空对象,那么对对象的属性进行遍历

a)  若参数中字段的值就是目标参数,停止赋值,防止无限的循环嵌套

    var _default = {name : 'wenzi'};
    var obj = {name : _default}
    $.extend(_default, obj);
    console.log(_default);

b)  若deep为true,且当前参数中name字段的值存在且为object类型或Array类型,则进行深度赋值

c)  若copy是简单的类型且存在值,则直接进行赋值

6)返回target

 源码如下:

// 为与源码的下标对应上,我们把第一个参数称为`第0个参数`,依次类推
jQuery.extend = jQuery.fn.extend = function() {
	var options, 
	 	name, 
	 	src, 
	 	copy, 
	 	copyIsArray, 
	 	clone,
	    target = arguments[0] || {}, // 默认第0个参数为目标参数
	 	i = 1, // i表示从第几个参数开始将目标参数与其进行合并,默认从第1个参数开始向第0个参数进行合并
	 	length = arguments.length,
		deep = false; // 默认为浅拷贝
	 
	// 判断第0个参数的类型,若第0个参数是boolean类型,则获取其为true还是false
	// 同时将第1个参数作为目标参数,i从当前目标参数的下一个
	// Handle a deep copy situation
	if ( typeof target === "boolean" ) {
	    deep = target;
 
 		// Skip the boolean and the target
 		// 如果第一个参数是Boolean类型
 		target = arguments[ i ] || {};
		i++;
	}
 
	// 判断目标参数的类型,若目标参数既不是object类型,也不是function类型,则为目标参数重新赋值空对象
	// Handle case when target is a string or something (possible in deep copy)
	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
	 	target = {};
	}
 
	// 若目标参数后面没有参数了,如$.extend({_name:'wenzi'}), $.extend(true, {_name:'wenzi'})
	// 则目标参数即为jQuery本身,而target表示的参数不再为目标参数
	// Extend jQuery itself if only one argument is passed
	if ( i === length ) {
		target = this;
		i--;
	}
	 
	// 从第i个参数开始遍历
	for ( ; i < length; i++ ) {
		// 获取第i个参数,且该参数不为null和undefind,在js中null和undefined,如果不区分类型,是相等的,null==undefined为true,
		// 因此可以用null来同时过滤掉null和undefind
		// 比如$.extend(target, {}, null);中的第2个参数null是不参与合并的
		// Only deal with non-null/undefined values
		if ( (options = arguments[ i ]) != null ) {
	  
			// 使用for~in获取该参数中所有可枚举的属性
			// Extend the base object
			for ( name in options ) {
				src = target[ name ]; // 目标参数中name字段的值
				copy = options[ name ]; // 当前参数中name字段的值,有可能是值,Object,Array
		 
				// 若参数中属性的值就是目标参数,停止赋值,进行下一个字段的赋值
				// 这是为了防止无限的循环嵌套,我们把这个称为,在下面进行比较详细的讲解
				// Prevent never-ending loop
				if ( target === copy ) {
				   continue;
				}
		 
				// 若deep为true,且当前参数中name字段的值存在且为object类型或Array类型,则进行深度赋值
				// Recurse if we're merging plain objects or arrays
				// jQuery.isPlainObject()返回值为Boolean类型,如果指定的参数是纯粹的对象,则返回true,否则返回false
				if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
					// 若当前参数中name字段的值为Array类型
					// 判断目标参数中name字段的值是否存在,若存在则使用原来的,否则进行初始化
					if ( copyIsArray ) {
						//被复制的属性的值类型为Array
					   copyIsArray = false;
					   //判断该字段在target对象是否存在,存在且为Array,则直接使用原对象,否则创建空的Array
					   clone = src && jQuery.isArray(src) ? src : [];
					 
					}else{
						// 被复制的属性的值得类型为Object
					   //判断该字段在target对象是否存在,若存在且为Object则直接使用,否则创建空的Object
					   clone = src && jQuery.isPlainObject(src) ? src : {};
					}
		 
					// 递归处理,此处为2.2
					// Never move original objects, clone them  
					target[ name ] = jQuery.extend( deep, clone, copy );
		 
					// deep为false,则表示浅度拷贝,直接进行赋值
				// Don't bring in undefined values
				}else if ( copy !== undefined ) {			
					// 若copy是简单的类型且存在值,则直接进行赋值
				    // 若原对象存在name属性,则直接覆盖掉;若不存在,则创建新的属性
				    target[ name ] = copy;
				}
		    }
	 	}
	}
	 
	// 返回修改后的目标参数
	// Return the modified object
	return target;
};

11、以下代码的输出结果是什么?为什么?

for(var i=0;i<3;i++){
	setTimeout(function(){
		console.log(i);
	},0);
}

输出的结果是3个3,因为在主程序中遇到异步事件的时候,会将异步事件放到事件队列里面去,等到主程序执行完之后,在去执行事件队列里面的事件,此时主程序已经执行完,i变为3,由于每次输出都是i的值,所以是3个3

11、定时器的执行顺序或者机制

javascript是单线程的,浏览器遇到setTimeout或者setInterval会先执行完当前的代码块,在此之前会把定时器推入浏览器的待执行事件队列里面,等到浏览器执行完当前代码之后会看一下事件队列里面有没有任务,有的话才执行定时器的代码。 所以即使把定时器的时间设置为0还是会先执行当前的一些代码,如下面所示:

function test() {
	var bb = 0;
	var testSet = setInterval(function(){
		bb++;
		console.log(11);
		if(bb<10){
			clearInterval(testSet);
		}
	},0);
	var test2 = setTimeout(function(){
		console.log(22);
	},0)
	for(var i=0;i<10;i++){
		console.log('aa');
	}
}
test() ;

输出结果

aa
aa
aa
aa
aa
aa
aa
aa
aa
aa
11
22

11、html中title属性和alt属性的区别

1)alt属性是用于img标签的,当图片不显示的时候会出现alt属性里面的内容,当图片显示的时候不会显示alt中的内容

2)title属性可以用在除了html,head,script,meta,title,param,base,basefont之外的所有标签。

title属性的功能是提示,当鼠标放在标签上的时候,会出现一些提示信息。额外的说明信息和非本质的信息请使用title属性。title属性值可以比alt属性值设置的更长;为链接添加描述性文字,特别是当连接本身并不是十分清楚的时候,设置title属性可以表达链接的目的

猜你喜欢

转载自blog.csdn.net/tangxiujiang/article/details/88717923