前端面经总结(非常全面

前端面经总结(非常全面

本文摘自原文:https://juejin.im/post/5b94d8965188255c5a0cdc02#html

前言

本文源自一篇掘金文,博主看了之后体会非常大,这篇文字的篇幅很大,范围很广,为了加深印象和消化得彻底一点,就对着原文来敲一敲顺便记录下来了!(毕竟博主已经被n家企业拒了 哭

另外我针对自己的问题,还附加了一些其他人的文章的补充,以方便理解和扩充知识,希望也能帮助大家哈哈哈哈~

目录

Html相关

Html语义化

意义:根据内容的结构化(内容语义化),选择合适的标签(代码语义化)便于开发者阅读和写出更优雅代码的同时让浏览器的爬虫和机器很好地解析。

其中需要注意的是:

  • 尽可能少使用无语义的标签div和span

这一点上我貌似就犯了错误哈哈,以后一定要注意才行(捂脸

  • 在语义不明显时,既可以使用div或p时,尽量用p,因为在默认情况下有上下间距,对兼容特殊的中断有利

  • 不要使用纯样式标签,如:b、font、u等,改用css来设置样式

  • 需要强调的文本,可以包含在strong或者em标签中(浏览器预设样式,能用CSS指定就不用这些),strong默认样式是加粗(不要用b),em是斜体(不要用i)

  • 使用表格时,标题要用caption,表头用thead,主体部分用tbody包围,尾部用tfoot包围。表头和一般单元格要区分开,表头用th,单元格用td

总感觉表单好麻烦啊~

  • 表单域要用fieldset标签包起来,并用legend标签说明表单的用途

  • 每个input标签对应的说明文本都需要使用label标签,并且通过为input设置id属性,在lable标签中设置for=someld来让说明文本和相对应的input关联起来

原来如此,看来之前犯错了,尬

meta viewport相关

天呐!这都是啥!!好多没见过的meta!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE html>  H5标准声明,使用 HTML5 doctype,不区分大小写
<head lang=”en”> 标准的 lang 属性写法
<meta charset=’utf-8′> 声明文档使用的字符编码
<meta http-equiv=”X-UA-Compatible” content=”IE=edge,chrome=1″/> 优先使用 IE 最新版本和 Chrome
<meta name=”description” content=”不超过150个字符”/> 页面描述
<meta name=”keywords” content=””/> 页面关键词
<meta name=”author” content=”name, email@gmail.com”/> 网页作者
<meta name=”robots” content=”index,follow”/> 搜索引擎抓取
<meta name=”viewport” content=”initial-scale=1, maximum-scale=3, minimum-scale=1, user-scalable=no”> 为移动设备添加 viewport
<meta name=”apple-mobile-web-app-title” content=”标题”> iOS 设备 begin
<meta name=”apple-mobile-web-app-capable” content=”yes”/> 添加到主屏后的标题(iOS 6 新增)
是否启用 WebApp 全屏模式,删除苹果默认的工具栏和菜单栏
<meta name=”apple-itunes-app” content=”app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL”>
添加智能 App 广告条 Smart App Banner(iOS 6+ Safari)
<meta name=”apple-mobile-web-app-status-bar-style” content=”black”/>
<meta name=”format-detection” content=”telphone=no, email=no”/> 设置苹果工具栏颜色
<meta name=”renderer” content=”webkit”> 启用360浏览器的极速模式(webkit)
<meta http-equiv=”X-UA-Compatible” content=”IE=edge”> 避免IE使用兼容模式
<meta http-equiv=”Cache-Control” content=”no-siteapp” /> 不让百度转码
<meta name=”HandheldFriendly” content=”true”> 针对手持设备优化,主要是针对一些老的不识别viewport的浏览器,比如黑莓
<meta name=”MobileOptimized” content=”320″> 微软的老式浏览器
<meta name=”screen-orientation” content=”portrait”> uc强制竖屏
<meta name=”x5-orientation” content=”portrait”> QQ强制竖屏
<meta name=”full-screen” content=”yes”> UC强制全屏
<meta name=”x5-fullscreen” content=”true”> QQ强制全屏
<meta name=”browsermode” content=”application”> UC应用模式
<meta name=”x5-page-mode” content=”app”> QQ应用模式
<meta name=”msapplication-tap-highlight” content=”no”> windows phone 点击无高光
设置页面不缓存
<meta http-equiv=”pragma” content=”no-cache”>
<meta http-equiv=”cache-control” content=”no-cache”>
<meta http-equiv=”expires” content=”0″>

附:(对viewport不太了解的童鞋可以参考
https://www.cnblogs.com/diantao/p/5292652.html

canvas相关

1
2
3
4
5
6
7
//使用前需要获得上下文环境,暂不支持3d
//常用api:
fillRect(x,y,width,height); //实心矩形
strokeRect(x,y,width,height); //空心矩形
fillText("Hello world",200,200); //实心文字
strokeText("Hello world",200,300); //空心文字
//各种东西!!!

新标签兼容低版本

  • ie9之前版本通过createElement创建html5新标签
  • 引入html5shiv.js

CSS相关

盒模型

  • IE盒模型会把border、padding、及自身算上(不算margin),标准的则之算上自身窗体大小,对此可以在CSS中进行设置,代码如下:
1
2
3
4
/* 标准模型 */
box-sizing:content-box;
/*IE模型*/
box-sizing:border-box;
  • 盒模型从外到里的层次分别为margin、border、padding、content

盒模型

  • js中几种获得DOM元素宽高的方式:
1
2
3
4
5
dom.style.width/height  //该方法只能获取dom元素内联样式所设置的宽高,即用当前标签的style属性添加的样式,而外联样式无法获取(内外联等样式说明详见附加链接
dom.style.currentStyle.width/height //该方式仅支持IE浏览器,获取的是页面渲染完成后的结果,即无论任何方式的样式都可获取
window.getComputedStyle(dom).width/height //该方式的原理与第二种相同,但支持更多浏览器,兼容性较好一些
dom.getBoundingClientRect().width/height
dom.offsetWidth/offsetHeight //兼容性最佳的一种方式,也是最常用的一种,推荐

附:
内外联等样式详细介绍:
https://blog.csdn.net/sunshinerou/article/details/72789870

  • 拓展各种获得宽高的方式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//获取屏幕高度、宽度(屏幕分辨率
window.screen.height/width

//获取屏幕工作区域的高度、宽度(去掉状态栏
window.screen.availHeight/availWidth

//网页全文的高度、宽度
document.body.scrollHeight/Width

//滚动条卷上去的高度、向右卷的宽度
document.body.scrollTop/scrollLeft

//网页可见区域的高度、宽度(不加边线
document.body.clientHeight/clientWidth

//网页可见区域的高度、宽度(加边线
document.body.offsetHeight/offsetWdith
  • 边距重叠解决方案(BFC) BFC原理

内部的box会在垂直方向,一个接一个的放置每个元素的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)

box垂直方向的距离由margin决定,属于同一个bfc的两个相邻box的margin会发生重叠

bfc的区域不会与浮动区域的box重叠

bfc是一个页面上的独立容器,外面的元素不会影响bfc里的元素,反过来,里面的也不会影响外面的

计算bfc高度的时候,浮动元素也会参与计算创建bfc

以下为触发BFC的4个条件

float属性不为none(脱离文档流)

position为absolute或fixed

display为inline-block,table-cell,table-caption,flex,inline-flex

overflow不为visble

根元素demo:

1
2
3
4
5
6
7
8
9
10
11
<section class="top">
<h1></h1>
这块margin-bottom:30px;
</section>
<!-- 给下面这个块添加一个父元素,在父元素上创建bfc -->
<div style="overflow:hidden">
<section class="bottom">
<h1></h1>
这块margin-top:50px;
</section>
</div>

附:
BFC全称Block formatting context,中文名 块级格式上下文,相关说明文章:
https://blog.csdn.net/TWFKXP/article/details/80574987

文档流及脱离文档流相关说明文章:
https://blog.csdn.net/thelostlamb/article/details/79581984

css reset和normalize.css有什么区别

  • 两者都是通过重置样式,保持浏览器样式的一致性
  • 前者几乎为所有标签添加了样式,后者保持了许多浏览器样式,保持尽可能一致
  • 后者修复了常见的桌面端和移动端的bug:包括H5元素的显示设置、预格式化文字的font-size问题、在IE9中SVG的溢出、许多出现在各浏览器和操作系统中的与表单相关的bug
  • 前者中含有大段的继承链
  • 后者模块化,文档较前者来说更丰富

附:
reset css意为重置默认样式,常用reset css汇总:
https://www.cnblogs.com/humin/p/3515547.html

Normalize.css是一个很小的css文件,为替代css reset,以适用于H5而准备的优质替代方案
详细的Normalize.css介绍:
http://www.cnblogs.com/zhaosijia----1234/p/9376262.html

css对不同浏览器内核兼容

-moz-:代表FireFox浏览器私有属性

-ms-:代表IE浏览器私有属性

-webkit-:代表safari、chrome浏览器私有属性

-o-:代表opera浏览器私有属性

居中方法

详见本博客对css居中十种方法详述的另一篇文章:
https://macrazds.cn/2018/11/12/csscentermethod/

css优先级确定

  • 每个选择器都有权值,权值越大越优先
  • 继承的样式优先级低于自身指定样式
  • !important优先级最高,js也无法修改
  • 权值相同时,会根据这些css样式的前后顺序来决定,处于最后面的css样式会被应用。顺序为 内联样式表(标签内部)> 嵌入样式表(当前文件中)> 外部样式表(外部文件中)

附:

css继承:指我们设置上级(父级)的CSS样式,上级(父级)及以下的子级(下级)都具有此属性。一般只有文字文本具有继承特性,如文字大小、文字加粗、文字颜色、字体等。

描述css的继承、特殊性及层叠的相关文章:
https://blog.csdn.net/qq_32863631/article/details/78964645

可继承及不可继承的css属性:
https://www.cnblogs.com/thislbq/p/5882105.html

如何清除浮动

发生高度塌陷的情况:浮动元素父元素高度自适应(即父元素不写高度时,子元素写了浮动后,父元素会发生高度塌陷)

  • clear清除浮动(添加空div法):在浮动元素下方添加控div,并给改元素写css样式:

    1
    2
    3
    4
    5
    .div{
    clear:both;
    height:0;
    overflow:hidden;
    }
  • 给浮动元素的父级元素设置高度

  • 父级元素同时浮动(需要给父级同级元素添加浮动)
  • 父级设置成inline-block,但会导致其margin: 0 auto居中方式失效
  • 给父级元素添加overflow: hidden 清除浮动方法
  • 万能清除法:after伪类清浮动(现主流方法,推荐),代码如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    .float_div:after{
    content:".";
    clear:both;
    display:block;
    height:0;
    overflow:hidden;
    visibility:hidden;
    }
    .float_div{
    zoom:1
    }

自适应布局

思路:

  • 左侧浮动或绝对定位,然后右侧margin撑开
  • 使用div包含,然后靠负margin形成bfc
  • 使用flex

画三角形

1
2
3
4
5
6
7
8
9
#item {
width: 0;
height: 0;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-top: 50px solid transparent;
border-bottom: 50px solid blue;
background: white;
}

link @import 导入 css

  • link是XHTML标签,除了加载css外,还可以定义RSS等其他事务;@import属于css范畴,只能加载css
  • link引用css时,在页面载入时同时加载;@import需要页面网页完全载入后加载
  • link无兼容问题;@import是在css2.1时提出的,低版本浏览器不支持
  • link支持使用Javascript控制DOM去改变样式,@import不支持

附:
RSS是什么?有什么用?看下面的介绍文章:
https://blog.csdn.net/zhao1949/article/details/52806123

animation

  • animation-name 规定需要绑定到选择器的keyframe名称
  • animation-duration 规定完成一次动画耗费的时间,以s或ms为单位
  • animation-timing-function 规定动画的速度曲线
  • animation-delay 规定在动画开始之前的延迟,以s或ms为单位
  • animation-iteration-count 规定动画的播放次数
  • animation-direction 规定是否应该轮流反向播放动画

附:
速度曲线有哪些?
http://www.w3school.com.cn/cssref/pr_animation-timing-function.asp

长宽比方案

  • 使用padding方式结合calc实现

    1
    2
    3
    .aspectration[data-ratio="16:9"] {
    padding-top: calc(100% * 9 / 16);
    }
  • 长宽一项设置百分比另一项aspect-ratio实现(需要借助插件实现

    1
    2
    3
    4
    .aspectration[data-ratio="16:9"] {
    width: 100%;
    height: aspect-ratio(16/9);
    }

附:
更多实现方案:
http://ju.outofmemory.cn/entry/321224

话说我没找到aspect-ratio()这个插件,都是只查到了媒体查询相关的内容,所以还是用第一种方法吧哈哈哈!

display相关

  • block:div等容器类型
  • inline:img span等行内类型
  • table系列:将样式变成table
  • flex:重点把握,非常强大
  • grid:同上
  • inline-block:可设置宽度,两者间有一点间隙
  • inherit:继承父级

响应式布局

给大家附上一个教程:
https://ninghao.net/video/1004

Javascript相关

[“1”,”2”,”3”].map(parseInt)

  • 首先,map函数接受两个参数,一个是回调函数,另一个是回调函数的this指向值

  • 其中回调函数接受三个参数:currentValue,index,array

  • 题目中,map只传入了一个回调函数parseInt

  • 其次,parseInt只接受两个参数:string,radix(基数),基于本题可理解为key和index

  • 综上,本题即问

1
2
3
4
5
parseInt('1',0);
parseInt('2',1);
parseInt('3',2);

parseInt(string,radix);
  • string必填,指要被解析的字符串

  • radix可选,表示要解析的数字的进制基数,该值于2~36之间

  • 如果省略radix或其值为0,则数字将以10进制为基础来解析。如果它以”0x”或”0X”开头,则以16进制为基础

附:
回调函数的作用是返回每一个数组元素对应的映射值,即关联的值。具体描述可见:
https://www.cnblogs.com/xuan52rock/p/4460949.html

[[3,2,1].reduce(Math.pow),[].reduce(Math.pow)]

arr.reduce(callback[,initialValue])

  • reduce接受两个参数,一个回调函数,一个初始值

  • 回调函数接受四个参数:previousValue,currentValue,currentIndex,array

  • 需要注意的是 If the array is empty and no initialValue was provided, TypeError would be thrown

  • 所以第二个表达式会报异常,第一个表达式等价于

    Math.pow(3,2)=>9;
    Math.pow(9,1)=>9;

附:
reduce()函数的作用,相当于一个累加器。即从第一个和第二个数组元素开始通过回调函数处理,而回调函数处理的结果将与第三个数组元素作同样的回调函数处理,以此类推直到最后一个数组元素处理完毕。
相关文章详述可见:
https://www.jb51.net/article/98848.htm

数组的赋值

首先先看一下js代码,我们用迭代器对数组的每一个元素进行判断

1
2
3
4
5
var arr=[0,1,2];
arr[10]=10;
arr.filter(function(x){
return x===undefined;
});

然后我们对这几行代码进行测试和分析:

首先推测是这样的:

0 in arr; => true

… true

3 in arr; => false

… false

10 in arr; => true

而输出结果是这样的:

false

false

false

false

可见,第3~9个元素是没有初始化的,这些索引并不存在于数组之中,而在array的函数调用的时候是会跳过这些坑的,因此只输出了四个false,其他的true并不会出现,是因为直接跳过了

[typeof null, null instanceof Object]

  • typeof 返回一个标识类型的字符串
    instanceof 运算符用来检测constructor.prototype是否存在于参数object的原型链上

  • 以下为相应输出

type result
Undefined “undefined”
Null “Object”
Boolean “boolean”
Number “number”
String “string”
Symbol “symbol”
Host object “Implementation-dependent”
Function “function”
Object “object”

js数据类型

js的数据类型共有7种:

  • number
  • string
  • boolean
  • undefined
  • null
  • symbol(ES6新增,文章后有会此新类型解释。概要:Symbol用于生成一个全局唯一的值)
  • Object(包括Object,Array,Function)

promise用法

  • 特性:Promise对象的错误具有冒泡性质,会一直向后传递,直到被捕获,即错误总会被下一个catch语句捕获

  • 定义:

    1
    2
    3
    4
    5
    6
    7
    var promise = new Promise(function(resolve,reject){
    if(/*异步操作成功*/){
    resolve(value);
    }else {
    reject(error);
    }
    });
  • 使用:

    1
    2
    3
    4
    5
    promise.then(function(value){
    //success
    },function(error){
    //failure
    });
  • 以上等价于

    1
    2
    3
    4
    5
    promise.then(function(){
    //success
    }).catch(function(){
    //failure
    });

附:

值得注意的是,如果promise中不调用resolve,将不会执行then的回调函数,相关资料:
https://segmentfault.com/q/1010000010058928

另外再附上一道我之前的笔试题(大概差不多是这样

先看代码

promise执行顺序

请写出这一段代码中,数字1~5的输出顺序

答案在右边,用鼠标选中刮一下就出来了:1 3 5 4 2

ES6 promise Ajax

  • 定义:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    const myHttpClient = url => {
    return new Promise((resolve,reject) => {
    let client = new XMLHttpRequest();
    client.open('GET',url);
    client.onreadystatechange = handler;
    client.responseType = 'json';
    client.setRequestHeader("Accept","application/json");
    client.send();
    function handler(){
    if(this.readyState !== 4){
    return;
    }
    if(this.status === 200){
    resolve(this.response);
    } else {
    reject(new Error(this.statusText));
    }
    }
    })
    }
  • 使用:

    1
    2
    3
    4
    5
    6
    //baidu换成自己的域名
    myHttpClient('https://www.baidu.com').then(res => {
    console.log(res);
    }).catch(error => {
    console.log(error);
    });

立即执行函数,及其目的

常见两种方式:


1
2
3
4
5
6
7
(function(){
//...
})()

(function(x){
console.log(x);
}(12345))


1
2
3
4
5
6
(function(){
//...
})
(function(x){
console.log(x);
}(12345))

作用:

不破坏污染全局的命名空间,若需要使用,将其变量传入,如:

1
2
3
(function(window){
//...
}(window))

async/await 异步语法

async/await是ES6的异步新语法

旧版的promise示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
const makeRequest = () => {
return getJSON().then(data => {
if(data.needAnotherRequest){
return makeAnotherRequest(data).then(moreData => {
console.log(moreData)
return moreData
})
} else {
console.log(data)
return data
}
})
}

ES6的async/await示例:

1
2
3
4
5
6
7
8
9
10
11
const makeRequest = async () => {
const data = await getJSON()
if(data.needAnotherRequest){
const moreData = await makeAnotherRequest(data)
console.log(moreData)
return moreData
} else {
console.log(data)
return data
}
}

  • 函数前面多了一个async关键字

  • await关键字只可用于async定义的函数内

  • async函数会隐式地返回一个promise

  • 该promise的resolve值就是函数return的值

  • 示例中resolve值就是字符串”done”

卧槽,这个真的大有感触啊!!之前在用原生小程序开发工具写小程序的时候,用的node.js后端,用的ES5,可怕,疯狂写promise,撸码撸出血了!!!

深浅拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const a = {
aa: 1,
bb: 2,
cc: 3,
dd: {
ee: 5,
},
ff: {
gg: 6,
}
};
//深复制,包含子对象
//完全不会改变a的原内容
let d = JSON.parse(JSON.stringify(a));
//拷贝一层,但不包含子对象
//修改c的首层时,不会改变a;但改变c的子对象时,同时会改变a的子对象
let c = {...a};
//浅拷贝
//修改b时,同时会改变原本的a
let b = a;
b.bb = 22;
c.cc = 33;
c.dd.ee = 55;
d.ff.gg = 66;
console.log(a);
console.log(b);
console.log(c);
console.log(d);

数组去重

  • 思路1:

定义一个新数组,并存放原数组的第一个元素,然后将元素一一和新数组的元素对比,若不同则存放在新数组中

  • 思路2:

先将原数组排序,在与相邻的进行比较,如果不同则存入新数组

  • 思路3:

利用对象属性存在的特性,如果没有该属性则存入新数组

附:
判断属性是否存在的方法:
https://www.cnblogs.com/kongxianghai/archive/2013/04/12/3015803.html

  • 思路4(最常用):

使用ES6 set

1
2
let arr = [1,2,3,3,5,7,2,6,8];
console.log([...new Set(arr)]);

数组合并去重排序

1
2
3
4
5
6
let arr1 = [1,25,2,26,1234,6,213];
let arr2 = [2, 6, 2134, 6, 31, 623];
let c = [...new Set([...arr1, ...arr2])].sort((a,b) => {
//从小到大排序
return a - b;
});

正则实现trim()功能

1
2
3
4
5
function myTrim(str){
let reg = /^\+|\s+$/g
return str.replace(reg,"");
}
console.log(myTrim(' asdf '));

附:trim()用于去除字符串的多余空格

JS原型

  • 每个对象都有 __proto__ 属性,但只有函数对象才有 prototype 属性

  • 个人粗略理解与python的类方法静态方法实例方法差不多 (这是原文作者说的额,不是我

之后有时间我再详细写一篇原型的博文,到时候会把地址更新贴在这里(当然如果记得贴的话,哈哈哈哈,反正写是一定会写的,因为我自己也不理解这个原型,所以要边学边写边理解

ES6 class

ES6的class并非一个新特性,说白了就是一个语法糖,它并不像java或者C++的类,实际上它主要是提供一个更方便的语法来创建老式的构造函数,其实最终还是基于原型链的方式

附:

相关详述的博文:
https://blog.csdn.net/tujiaw/article/details/79336399

JS如何实现继承

  • 使用原型链继承:

优点:

  1. 继承了父类的模板
  2. 继承了父类的原型对象

缺点:

  1. 父类实例传参,而非子类实例化传参,不符合常规语言写法
  • 使用call的方式

优点:

  1. 方便了子类实例传参

缺点:

  1. 不继承父类的原型链

附:

更多继承方法:
https://blog.csdn.net/caijixin/article/details/78295676

其他继承方法简单易懂的描述:
https://blog.csdn.net/js_admin/article/details/71012367

手写jQuery插件

1
2
3
4
5
6
7
8
9
10
(function ($) {
$fn.myPlugins = function (options) {
//参数赋值
option = $.extend(defaults, options); //对象合并
this.each(function(){
//执行代码逻辑
});
};
})(jQuery);
$(selector).myPlugins({参数});

附:

手写jQuery插件详细说明文章:
https://www.jb51.net/article/60073.htm

each()函数的作用是对jQuery匹配的元素的值,逐一对其用each中作为参数的函数进行处理

each()函数详解:

https://www.cnblogs.com/wsl2011/p/3543835.html

call apply

  • 作用:

两者作用相同,在函数调用时,改变函数的执行上下文,即this的值

  • 区别:

参数不同。call采用不定长的参数列表,而apply使用一个参数数组

  • 语法:
1
2
3
4
5
6
7
8
9
/*apply()方法*/
function.apply(thisObj[, argArray])
/*调用示例*/
B.apply(A, arguments);

/*call()方法*/
function.call(thisObj[, arg1[, arg2[, [,...argN]]]]);
/*调用示例*/
B.call(A, args1,args2);

附:

更加详述的文章:
https://www.cnblogs.com/lengyuehuahun/p/5643625.html

性能优化

性能优化图

for循环中的setTimeout

注意点:

要为每次循环中setTimeout中使用到的变量,在setTimeout前做好副本,再将副本用在setTimeout中,而非直接用原变量

附:

关于此问题具体详述:

https://www.cnblogs.com/xjnotxj/p/7452698.html

sort函数

  • V8引擎的sort函数值提供了两种排序法:InsertionSort(插入排序),及QuickSort(快速排序)

  • InsertionSort:用于元素数量小于10的数组

  • QuickSort:用于元素数量大于10的数组

navigator对象

  • 包含的方法如图:

navigator对象包含的方法

jQuery绑定方式

  • click(重复绑定会被后绑定的覆盖
  • bind(重复绑定会被后绑定的覆盖
  • on(jQuery>=1.7)
  • live
  • delegate

事件流向定义

  • 冒泡:子节点一层层往上冒泡到根节点

  • 捕获:方向顺序与冒泡相反

  • addEventListener方法的最后一个参数true表示捕获,反之为冒泡

  • 阻止冒泡不会同时停止父节点的捕获

原生操作class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//判断有无
function hasClass(ele, cls){
return ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
}

//添加
function addClass(ele, cls){
if(!this.hasClass(ele, cls)){
ele.className += " " + cls;
}
}

//删除
function removeClass(ele, cls){
if(hasClass(ele, cls)){
let reg = new RegExp("(\\s|^)" + cls + "(\\s|$)");
ele.className = ele.className.replace(reg, " ");
}
}

html5中加入了classList对象,及对class处理的一系列操作,兼容至IE10

DOM相关

DOM事件模型

DOM事件模型分脚本模型、内联模型(同类一个,后重复定义者覆盖)、动态绑定(同类多个,不会覆盖)

demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<body>
<!--行内绑定:脚本模型-->
<button onclick="javascript:alert('Hello')">Hello1</button>

<!--内联模型-->
<button onclick="showHello()">Hello2</button>

<!--动态绑定-->
<button id="btn3">Hello3</button>
</body>

<script>
/*DOM0:同一个元素,同类事件只能添加一个,如果添加多个,后面添加的会覆盖前面添加的*/
function showHello(){
alert("Hello");
}
var btn3 = document.getElementById("btn3");
btn3.onclick = function(){
alert("Hello");
}

/*DOM2:可以给同一个元素添加多个同类事件*/
btn3.addEventListener("click",function(){
alert("hello1");
})
btn3.addEventListener("click",function(){
alert("hello2");
})
if(btn3.attachEvent){
/*IE*/
btn3.attachEvent("onclick",function(){
alert("IE Hello1");
})
} else {
/*W3C*/
btn3.addEventListener("click",function(){
alert("W3C Hello");
})
}
</script>

  • 冒泡解释:

从最里逐层往外到外层的阶段

  • 捕获解释:

当点击一个元素触发事件时,事件会先从元素的最外成父元素逐层进入到触发的元素,从触发元素逐层返回到最外层父元素,从最外层逐层进入的阶段

移动端触摸事件

①touchstart:当手指触碰到屏幕时触发

②touchmove:当手指在屏幕上滑动时触发

③touchend:当手指离开屏幕时触发

④touchcancel:当系统停止跟踪触摸时触发(该事件很少会用到,一般不做深入研究)

电话接入或弹出信息等其他事件传入的event事件参数说明:

  1. touches:表示当前跟踪的触摸操作的touch对象的数组

  2. targetTouches:特定于事件目标的Touch对象的数组

  3. changeTouches:表示自上次触摸以来发生了什么改变的Touch对象的数组

每个touch对象包含的属性

  1. clientX:触摸目标在视口中的x坐标

  2. clientY:触摸目标在视口中的y坐标

  3. identifier:标识触摸的唯一ID

  4. pageX:触摸目标在页面中的x坐标

  5. pageY:触摸目标在页面中的y坐标

  6. screenX:触摸目标在屏幕中的x坐标

  7. screenY:触摸目标在屏幕中的y坐标

  8. target:触摸的DOM节点目标

事件委托

  • 参考定义:

事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件

  • 好处:

给重复的节点添加相同操作,减少dom交互,提高性能

  • 实现思路:

给父组件添加事件,通过事件冒泡,排查元素是否为指定元素,并进行系列操作

HTTP相关

常见状态码

  • 2开头(请求成功)表示处理了请求的状态代码

200:成功,服务器已成功处理了请求。通常,这表示服务器提供了请求的网页。

201:已创建,请求成功并且服务器创建了新的资源

202:已接受,服务器已接受请求,但尚未处理

203:非授权信息,服务器已成功处理了请求,但返回的信息可能来自另一来源

204:无内容,服务器成功处理了请求,但没有返回任何内容

205:重置内容,服务器成功处理了请求,但没有返回任何内容

206:部分内容,服务器成功处理了部分GET请求

  • 3开头(请求被重定向)表示要完成请求,需要进一步操作。通常,这些状态码用来重定向

300:多种选择,针对请求,服务器可执行多种操作。服务器可根据请求者(user agent)选择一项操作,或提供操作列表供请求者选择

301:永久移动,请求的网页已永久移动到新位置。服务器返回此响应(对GET或HEAD请求的响应)时,会自动将请求者转到新位置

302:临时移动,服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求

303:查看其它位置,请求者应当对不同的位置使用单独的GET请求来检索响应时,服务器返回此代码

304:未修改,自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容

305:使用代理,请求者只能使用代理访问请求的网页。如果服务器返回此响应,则表示请求者应使用代理

307:临时重定向,服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置进行以后的请求

  • 4开头(请求错误)这些状态码表示请求可能出错,妨碍了服务器的处理

400:错误请求,服务器不理解请求的语法

401:未授权,请求要求身份验证。对于需要登录的网页,服务器可能返回此响应

403:禁止,服务器拒绝请求

404:未找到,服务器找不到请求的网页

405:方法禁用,禁用请求中指定的方法

406:不接受,无法使用请求的内容特性响应请求的网页

407:需要代理授权,此状态码与401类似,但指定请求者应当授权使用代理

408:请求超时,服务器等候请求时发生超时

409:冲突,服务器在完成请求时发生冲突。服务器必须在响应中包含有关冲突的信息

410:已删除,如果请求的资源已永久删除,服务器就会返回此响应

411:需要有效长度,服务器不接受不含有效内容长度表头字段的请求

412:未满足前提条件,服务器未满足请求者在请求中设置的其中一个前提条件

413:请求实体过大,服务器无法处理请求,因为请求实体过大,超出服务器的处理能力

414:请求的URI过长,请求的URI(通常为网址)过长,服务器无法处理
415:不支持的媒体类型,请求的格式不受请求页面的支持

416:请求范围不符合要求,如果页面无法提供请求的范围,则服务器会返回此状态码

417:未满足期望值,服务器为满足“期望”请求表头字段的要求

  • 5开头(服务器错误)这些状态码表示服务器在尝试处理请求时发生内部错误。这些错误可能是服务器本身的错误,而不是请求出错

500:服务器内部错误,服务器遇到错误,无法完成请求

501:尚未实施,服务器不具备完成请求的功能。例如,服务器无法识别请求方法时,可能会返回此代码

502:错误网关,服务器作为网关或代理,从上游服务器收到无效响应

503:服务不可用,服务器目前无法使用(由于超载或应急维护)。通常只是暂时的状态

504:网关超时,服务器作为网关或代理,但是没有及时从上游服务器收到请求

505:HTTP版本不受支持,服务器不支持请求中所用的HTTP协议版本

缓存

  • Expires在http1.0中使用,与服务器时间有误差,在1.1中由Cache-Control替代

  • cdn

附:

一篇有意思的,以故事形式对cdn进行讲解的博文,个人觉得写得挺好的,理解起来也很生动:

https://blog.csdn.net/lu_embedded/article/details/80519898

Cache-Control 与 Etag 的区别

Cache-Control与Etag的区别

附:

对Cache-Control及Etag的详细介绍文章:

https://www.cnblogs.com/rushme/p/6867645.html

Cookie,sessionStorage及localStorage三种缓存方式的异同

  • 共同点:
  1. 都是保存在浏览器端

  2. 同源

  • 区别:
  1. 存放位置不同。Cookie数据始终在同源的httpp请求中携带,即Cookie在浏览器和服务器间会来回传递;而sessionStorage及localStorage不会自动把数据发给服务器,仅在本地保存

  2. 存储数据的最大容量不同。Cookie数据大小不得超过4K(适合保存小数据);sessionStorage及localStorage容量较大

  3. 三者的数据有效期不同。Cookie只在设置的Cookie过期时间之前一直有效,即使窗口或浏览器被关闭也不会提前过期;sessionStorage仅在当前浏览器窗口关闭前有效;localStorage则始终有效,窗口或浏览器关闭也会一直保存,需手动清除

  4. 作用域不同。Cookie和localStorage可在所有同源窗口中共享;sessionStorage不能在不同浏览器窗口中共享

附:

所谓同源,就是指域名、协议、端口相同。

GET 和 POST 请求的区别

GET和POST的区别

请求行,请求头,请求体详解

请求行,请求头,请求体详解

1,2,3请求行,4请求体,5请求体

跨域、JSONP、CROS、postMessage

  • 跨域:当前发起请求的域,与改请求指向的资源所在的域不一样。这里的域指的是这样的一个概念:我们认为若协议 + 域名 + 端口号均相同,那么就是同域。如下表:

跨域示例

  • JSONP实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//①原生
var script = document.createElement('script');
script.type = 'text/javascript';
//传参并指定回调执行函数为onBack
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=onBack';
document.head.appendChild(script);
//回调执行函数
function onBack(res){
alert(JSON.stringify(res));
}

//②jQuery
$.ajax({
url: 'http://www.domain2.com:8080/login',
type: 'get',
dataType: 'jsonp',
jsonpCallback: "onBack",
data: {}
});

//③Vue
this.$http.jsonp('http://www.domain2.com:8080/login',{
params: {},
jsonp: 'onBack'
}).then((res) => {
console.log(res);
});

//相对应的后端实现(这里使用的是Node.js,其他服务器语言也可)
const querystring = require('querystring');
const http = require('http');
const server = http.createServer();
server.on('request',function(req,res){
var params = qs.parse(req.url.split('?')[1]);
var fn = params.callback;
//jsonp返回设置
res.writeHead(200,{
'Content-Type': 'test/javascript'
});
res.write(fn + '(' + JSON.stringify(params) + ')');

res.end();
});
server.listen('8080');

JSONP的缺点是只能实现get请求

  • CORS实现:

CORS:跨域资源共享Cross-Origin Resource Sharing(CROS),通常服务器设置,若带cookie请求,则前后端都需要设置 后端常见设置:

response.setHeader(“Access-Control-Allow-Origin”,”www.domain1.com"); //若有端口需补全(协议+域名+端口),以允许那些外援请求

response.setHeader(“Access-Control-Allow-Credentials”,”true”); //是否需要验证

前端示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//①原生
var xhr = new XMLHttpRequest(); //IE8/9需要用window.XDomainRequest兼容
xhr.withCredentials = true;
// open(requestMethod,url,async,username,password) 第三个参数表示是否将当前请求设为异步,true为异步(即不会等待请求完成),false为同步(会等待请求完成,相当于await),作用于send()之后
xhr.open('post','http://www.domain2.com:8080/login',true);
//setRequestHeader(name,value),用于指定一个HTTP请求的头部
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
//send(body),用于发送请求,可以指定请求体body,即需要传送的参数或数据
xhr.send('user=admin');

//②jQuery
$.ajax({
xhrFields: {
//前端设置是否带cookie
withCredentials: true
},
//让请求头中包含跨域的额外信息,但不会包含cookie
crossDomain: true,
//...
})

关于XMLHttpRequest的withCredentials属性说明:

https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/withCredentials

XMLHttpRequest的详述:

http://www.w3school.com.cn/xmldom/dom_http.asp

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!--父窗口a.html-->
<!--注意此处iframe的src是domain2,即b.html-->
<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>
var iframe = document.getElementById('iframe');
iframe.onload = function(){
var data = {
name = "aym"
};
//向domain2传送跨域数据
iframe.contentWindow.postMessage(JSON.stringify(data),'http://www.domain2.com');
}

//接受domain2返回数据
window.addEventListener('message',function(e){
alert('data from domain2 ---> ' + e.data);
},false);
</script>

<!--子窗口b.html(与a.html不同源-->
<script>
window.addEventListener('message'.function(e){
alert('data from domain1 ---> ' + e.data);

var data = JSON.parse(e.data);
if(data){
data.number = 16;
//处理后再重新发送给domain1
window.parent.postMessage(JSON.stringify(data),'http://www.domain1.com');
}
},false);
</script>

关于addEventListener的事件有哪些,及其说明:

https://blog.csdn.net/vincentblog/article/details/50629091

OSI模型

物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。其中TCP和UCP属于传输层;http属于应用层

http2.0 原理及特性

  • HTTP2.0的基本单位为二进制帧

  • HTTP2.0中各帧拥有不同优先级

  • HTTP2.0采用多路复用(1次TCP连接,基于流,即所有消息的每个帧可乱序发送,而不再是HTTP1.0的只有一次消息完成后才能再发第二次消息)

  • HTTP2.0压缩消息头

  • HTTP2.0服务端推送

  • HTTP2.0只适用于HTTPS的场景

附:

更加详细的介绍:

https://blog.csdn.net/zhuyiquan/article/details/69257126?locationNum=4&fps=1

Vue相关

生命周期顺序

Vue生命周期

组件通信

  • 父传子 props

  • 父用子 ref

  • 子调用父 $emit

  • 无关系 Bus

附:

关于Vue事件总线Bus的文章:

https://blog.csdn.net/Super_LD/article/details/80699676

Vuex

Vuex:组件通信库,可以避免子组件无法改变props的弊端等mutations同步操作,用于改变状态,官方不推荐异步action执行多个mutations,官方推荐异步操作mapState、mapGetters、mapActions

mapState使用示例:(mapGetters、mapActions使用相似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<el-dialog :visible.sync="show"></el-dialog>
</template>

<script>
import {mapState} from 'vuex';
export default {
computed:{
//这里的三点叫:扩展运算符
...mapState({
show: state => state.dialog.show
}),
}
}
</script>

附:

更多关于Vuex的内容,可参见官方文档:

https://vuex.vuejs.org/zh/guide/

VueRouter 路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//定义路由数据
var routes = [
{
path: "one",
component: '导入的组件1'
},
{
path: "two",
component: '导入的组件2'
}
];

//定义路由组件
var router = new VueRouter({
routes
});

//定义路由
new Vue({
el: "#box", //挂在目标元素,即在项目根目录下的index.html的目标元素
router
});

附:

关于new Vue()实例的更多参数说明:

https://www.jianshu.com/p/cf2611ed1b1f

Vue双向绑定

  • 原理:利用了Object.defineProperty()这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的

  • 缺点:双向数据流是自动管理状态的,但是在实际应用中会有很多不得不手动处理状态变化的逻辑,使得程序复杂度上升,难以调试

computed watch methods

用法及区别:

  • 前两者自动追踪数据,执行相关函数,最后一个则是手动调用

  • computed是计算属性,用法与data一致

  • watch类似事件监听,当指定对象(变量)发生变化时,会自动执行对应逻辑事件

  • methods与js中普通的执行方法类似,需手动调用

  • computed通常指有get属性

  • 当数据变化的同时需要进行异步操作或比较大的开销时,使用watch为最佳选择

  • watch的对象必须有前置声明(已定义的对象/变量)

网络安全相关

XSS CSRF

  • 定义:XSS,跨站脚本攻击,恶意的注入html代码,其他用户访问时,会被执行

  • 特点:能注入恶意的HTML/Javascript代码到用户浏览的网页上,从而达到Cookie资料窃取、会话劫持、钓鱼欺骗等攻击

  • 防御手段:

  1. 浏览器禁止页面的JS访问带有HttpOnly属性的Cookie

  2. 两端进行输入格式检查

  3. 通过编码转义的方式进行输出检查

  • 定义:CSRF,攻击跨站请求伪造

  • 特点:重要操作的所有参数都是可以被攻击者猜测到的。攻击者预测出URL的所有参数与参数值,才能成功构造一个伪造的请求

  • 防御手段:

  1. token验证机制,比如请求数据字段中添加一个token,响应请求时校验其有效性(实践中常用)

  2. 用户操作限制,比如验证码(繁琐,用户体验差)

  3. 请求来源限制,比如限制HTTP Referer才能完成操作(防御效果相比较差)

Webpack相关

打包体积优化思路:

  1. 提取第三方库或通过引用外部文件的方式引入第三方库

  2. 代码压缩插件UglifyJsPlugin

  3. 服务器启用gzip压缩

  4. 按需加载资源文件require.ensure

  5. 优化devtool中的source-map

  6. 剥离css文件,单独打包

  7. 去除不必要插件,通常就是开发环境与生产环境用同一套配置文件导致

打包效率优化

  1. 开发环境采用增量构建,启动热更新

  2. 开发环境不做无意义的工作,如提取css计算文件hash等

  3. 配置devtool

  4. 选择合适的loader

  5. 个别loader开启cache,如babel-loader

  6. 第三方库采用引入方式

  7. 提取公共代码

  8. 优化构建时的搜索路径,指明需要构建的目录及不需要构建的目录

  9. 模块化引入需要的部分

Loader

  • 定义:Loader就是一个node模块,它输出了一个函数。当某种资源需要用这个loader转换时,这个函数会被调用,这个函数可以通过提供给它的this上下文访问loader API

编写一个Loader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//reverse-txt-loader
//定义:
module.exports = funciton(src){
//src是原文件内容(abcde),下面对内容进行处理,这里的处理是反转内容
var result = src.split('').reverse().join('');
//返回Javascript源码,必须是String或Buffer
return `module.exports = '${result}'`;
}

//使用:
{
test: /\.txt$/,
use: [{
'./path/reverse-txt-loader'
}]
},

plugins(插件)

适用范围更广,通常只需要requires(),然后添加到plugins数组中,且需要new一个实例

其他

URL到界面显示发生了什么

  • DNS解析:首先在本地缓存查找,再一层层寻找,将常见的地址解析成唯一对应的ip地址,基本顺序为 本地域名服务器 -> 根域名服务器 -> com顶级域名服务器 以此类推,最终找到目标,并缓存下来,如www.google.com记录存为 . -> .com -> google.com -> www.google.com

  • TCP连接:三次握手,只要没收到确认信息就需要重新发送,具体过程如下:

  1. 主机向服务器发送一个建立连接的请求(你好,我想认识你)

  2. 服务器接收到请求后,发送同意连接的信号(好的,很高兴认识你)

  3. 主机接收到统一连接的信号后,再次向服务器发送确认信号(我也很高兴认识你),于是主机和服务器便建立了连接

  • 发送HTTP请求:浏览器会分析这个URL,并设置好请求报文发出。请求报文中包含请求行、请求头、空行、请求主体。https默认请求端口443,http默认请求端口80,。

  • 浏览器解析渲染页面:

  1. 通过HTML解析器解析HTML文档,构建一个DOM Tree,同时通过CSS解析器解析HTML中存在的CSS,构建Style Rules,两者结合形成一个Attachment

  2. 通过Attachment构建出一个呈现树(Render Tree)

  3. Render Tree构建完毕,进入布局阶段(layout/reflow),将会为每个阶段分配一个应出现在屏幕上的确切坐标

  4. 最后将全部的节点遍历绘制出来后,一个页面就展现出来了。遇到script会停下来执行,所以通常把script放在底部

  • 连接结束

附:

常见http请求如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST / HTTP1.1
Host:www.wrox.com
User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
Content-Type:application/x-www-form-urlencoded
Content-Length:40
Connection: Keep-Alive

name=Professional%20Ajax&publisher=Wiley
第一部分:请求行,第一行说明是post请求,以及http1.1版本。
第二部分:请求头部,第二行至第六行。
第三部分:空行,第七行的空行。
第四部分:请求数据,第八行。
4. 服务器处理请求并返回HTTP报文
后端处理返回http报文如下
`
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
HTTP/1.1 200 OK
Date: Fri, 22 May 2009 06:07:21 GMT
Content-Type: text/html; charset=UTF-8

<html>
<head></head>
<body>
<!--body goes here-->
</body>
</html>
第一行为状态行,(HTTP/1.1)表明HTTP版本为1.1版本,状态码为200,状态消息为(ok)
第二行和第三行为消息报头,
Date:生成响应的日期和时间;Content-Type:指定了MIME类型的HTML(text/html),编码类型是UTF-8
第三部分:空行,消息报头后面的空行是必须的
第四部分:响应正文,服务器返回给客户端的文本信息。
空行后面的html部分为响应正文。

组件封装

  • 目的:为了重用,提高开发效率及代码质量

  • 封装关键:低耦合,单一职责,可复用性,可维护性

  • 常用操作步骤:

  1. 分析布局

  2. 初步开发

  3. 化繁为简

  4. 组件抽象

Javascript异步加载

  • 定义:动态生成script标签

  • 实现:添加h5的async或defer属性(前者乱序不适合依赖性加载

  • 区别:async是“下载完就执行”,defer是“渲染完再执行”

css与javascript动画差异

  • css性能好

  • css代码逻辑相对简单

  • js动画更具控制性

  • js兼容性更好

  • js可实现的动画较丰富

  • js可添加事件

负载均衡

  • 定义:多台服务器共同协作,不让其中一台或几台服务器超额工作,发挥服务器的最大作用

  • 实施方法:

  1. http重定向负载均衡:调度者根据策略选择服务器,以302响应请求,缺点是仅第一次有效,后续操作都将维持在该服务器

  2. dns负载均衡:解析域名时,访问多个ip服务器中的一个(可监控性较弱)

  3. 反向代理负载均衡:访问统一的服务器,由服务器进行调度访问实际的某个服务器,对统一的那台服务器要求较大,性能受到服务器群的数量影响

CDN

内容分发网络,基本思路是:尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定

附:

一篇有意思的,以故事形式对cdn进行讲解的博文,个人觉得写得挺好的,理解起来也很生动:

https://blog.csdn.net/lu_embedded/article/details/80519898

内存泄漏

  • 定义:程序中已动态分配的堆内存,由于某种原因,程序未释放或无法释放引发的各种问题

  • 结果:变慢、崩溃、延迟大等

  • 原因:

  1. 全局变量

  2. dom清空时,还存在引用

  3. IE中使用闭包

  4. 定时器未清理

  5. 子元素存在引起的内存泄漏

  • 避免策略:
  1. 减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收

  2. 注意程序逻辑,避免“死循环”之类的情况

  3. 避免创建过多的对象,原则:不用了的东西要及时归还

  4. 减少层级过多的引用

babel原理

ES6、7代码输入 -> Babylon进行解析 -> 得到AST(抽象语法树) -> plugin用babel-traverse对AST树进行遍历转译 -> 得到新的AST树 -> 用babel0generator通过AST树生成ES5代码

js自定义事件

  • 三要素:
  1. document.createEvent()

  2. event.initEvent()

  3. element.dispatchEvent()

  • 实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//说明:en:自定义事件名称,fn:事件处理函数,addEvent:为DOM元素添加自定义事件,triggerEvent:触发自定义事件
window.onload = function(){
var demo = document.getElementById("demo");
demo.addEvent("test",function(){console.log("handler1")});
demo.addEvent("test",function(){console.log(handler2)});
demo.onclick = function(){
//触发test事件函数
this.triggerEvent("test");
}
}
Element.prototype.addEvent = function(en,fn){
this.pools = this.pools || {};
//这里的this.pools || {},后面的{}称为兜底,以防止当this.pools的内容获取不到时,以至于赋值目标被赋undefined。这一是一个较好的变量赋值习惯
if(en in this.pools){
this.pools[en].push(fun);
}else{
this.pools[en] = [];
this.pools[en].push(fn);
}
}
Element.protetype.triggerEvent = function(en){
if(en in this.pools){
var fns = this.pools[en];
for(var i=0,i1=fns.length;i>i1;i++){
fns[i]();
}
}else{
return;
}
}

ES6模块 CommonJS AMD CMD

  • CommonJS的规范中,每个JavaScript文件就是一个独立的模块上下文(module context),在这个上下文中默认创建的属性都是私有的。也就是说,在一个文件定义的变量(还包括函数和类),都是私有的,对其他文件是不可见的

  • CommonJS是同步加载模块,在浏览器中会出现堵塞情况,所以不适用

  • AMD异步,需要定义回调define方式

  • ES6一个模块就是一个独立的文件,该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量

  • ES6还可以导出类、方法,自动适用严格模式

前后端路由的差别

  • 后端每次路由请求都是重新访问服务器

  • 前端路由实际上只是JS根据URL来操作DOM元素,根据每个页面需要的去向服务端请求数据,返回数据后,与模板进行组合