1.HTML
1. 行级元
- 水平分布 多个占一行
- 不可以设置宽高
<span>、<a>、<b>、<img>、<br>、<button>、<strong>、<textarea>、<select>
2. 块级元素
- 垂直分布
- 自己占一行
- 可以设置宽高
<div>、<ul>、<li>、<p>、<fieldset>、<form>、<h1>、<h2>、<h3>、<hr>、<iframe>、<ol>、<pre>、<table>、<tr>、<td>
3. 行级块元素
- 多个占一行
- 可以设置宽高
img button
4. HTML语义化
- 自带标签含有特定含义
h1-h6标题 p段落 img图片 - h5中新增:
header fotter nav
- 他人阅读阅读代码时能够根据标签猜出你的用意,有利于程序员阅读,便于团队开发和维护
- 浏览器读取方便
- 有利于搜索引擎优化,索索引擎会根据标签来搜索(重点搜索h1)
- 有一些标签有默认样式,如果浏览器禁止CSS样式还可以起到突出样式的效果
5. h5新特性
- 新的语义化标签,比如header、footer、nav、article等
- 标签有更清晰的语义,便于开发者阅读,浏览器读取方便,利于搜索引擎优化.)
- 不支持新标签怎么办
document.creatElenent(header);动态创建
- 新增表单控件: input type="email/number/range。。。"
- 新的选择器:querySelector('#aa')和querySelectorAll('.aa')
- JSON.parse()和JSON.stringify()方法
- 历史管理:history.pushState()和window.onpopstate事件
- 本地存储:localStorage和sessionStorage(可能会问和cookie)
- Canvas画布: var cvs = docuement.getElementById('canvas1'); var cxt = cvs.getContext('2d');
2. CSS
1. css选择器
- id选择器
- class选择器
- 标签选择器
- 子代选择器
div > p - 后代选择器
div p - 伪类选择器
:hover - 伪元素选择器
::after - 分组选择器
div,p - 属性选择器
div[id] - 紧邻兄弟元素
div + p - 后边所有兄弟元素
div~p
- css优先级
- !important
- 内联 style
1000 - id
100 - class
10 - 标签
1
2. display
- none 此元素不会被显示。
- block 此元素将显示为块级元素。
- inline 默认。此元素会被显示为行级元素。
- inline-block 行内块元素,和其他元素在一行,也可以设置宽和高
- box弹性盒模型。父元素设置display:box子元素设置box-flex:1
3. POSITION
absolute绝对定位
- 定位后空间释放
- 相对于最近已定位的祖先元素(无祖先 - 相对于浏览器)
relative相对定位
- 定位后空间不释放
- 相对于自己的初始位置
fixed固定定位
- 定位后空间释放
- 相对于浏览器的可视窗口
static默认的定位sticky粘性定位
- 吸顶效果
4. 浮动
float:left right
- 浮动元素脱离文档流 空间释放
- 浮动高度塌陷 子元素浮动会导致父元素塌陷
- 清除浮动
clear : none | left | right | both
5. css盒模型
content+padding+border+margin
- 标准盒模型
width:200 => content=200
- 怪异盒模型
- ie6以及ie6以下浏览器 不写doctype 会表现怪异
box-sizing = border-boxwidth:200 => width=border+padding+content
- 转化
- `box-sizing:content-box(标准盒模型)默认
box-sizing:border-box(怪异盒模型)
6. 外边距合并
- 相同方向的
margin合并为较大的一个 - 相邻的
margin合并为较大的一个 - 解决
- 父元素
overflow:hidden / overflow: auto; - 父元素加边框
- 父元素或子元素 浮动或定位
- 父子元素任一个元素设置为行内块元素
dispaly:inline-block;
7. BFC(box formatting context)
- 块级格式化上下文
- 独立的渲染区域,就是页面上的一个隔离的独立容器,容器里的子元素不会影响到外面的元素
1. 触发BFC条件
- 根元素
html float不为noneposition:absolute/fixeddisplay:inline-block / table-cell / flex / inline-flexoverflow不为visible
2. 布局规则(了解)
- 布局会在垂直方向,一个接一个地放置
- box垂直方向距离有margin决定,。属于同一个BFC的两个相邻Box的margin会发生重叠
- 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
- BFC的区域不会与float box重叠。
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
- 计算BFC的高度时,浮动元素也参与计算
3. BFC特性
- BFC 会阻⽌止外边距折叠
- BFC 可以包含浮动的元素
- BFC 可以阻⽌止元素被浮动元素覆盖
8. CSS兼容性
- 透明度问题,标准浏览器(0-1)opacity:0.2,IE (0-100);filter: alpha(opacity=20);
- IE6不支持display:inline-block
- IE6之间的浏览器不支持min-height,解决:加一s个_height:200px;
- IE6只支持 a标签的:hover,不支持其他标签的:hovers
- 图片浮动会有间距;display:inline-block;
9. 取CSS:
oDiv.style//内联读不到oDiv.currentStyle.width//IEwindow.getComputedStyle(oDiv,null).width//标准
10. 让图片不显示的三种办法:
display:none;不占位置,事件能绑定opacity:0;占位,事件能绑上visibility:hidden;占位,事件绑定不上
11. 超出内容省略号
overflow:hiddentext-overflow:ellipsis省略号;clip裁切white-space:nowrap;换行
12. CSS预处理
- SASS是对CSS3(层叠样式表)的语法的一种扩充。 Sass 是一款强化CSS 的辅助工具,它在CSS语法的基础上增加了变量(variables)、嵌套(nested rules)、混合 (mixins)、导入(inline imports)等高级功能,这些拓展令 CSS 更加强大与优雅。
- 使用Sass 以及Sass的样式库(如Compass)有助于更好地组织管理样式文件,以及更高效 地开发项目。 更结构化的语法(语法可以进行嵌套)。 #### 13. Sass和Scss的区别
- 两者其实是一种东西,都是称之为Sass,不同之处是文件扩展名不同,Sass是以严格的缩进式语法规则来书写,不带大括号{}和分号;,用“缩进”代替“花括号”表示属性属于某个选择器,用“换行”代替“分号”分隔属性,而Scss的语法书写 和CSS的语法书写方式非常类似
3. JS
1. 数据类型
- 基本数据类型:string number boolean null undefined
- undefined:定义了没赋值,函数的参数没有传值,访问对象中没有的属性,访问 超过数组长度的值
- null:指代是对空对象的引用(对象的占位符)
- obj:引用数据类型(是保存在堆内存中的对象)
- 基本数据类型和引用数据类型
- 基本类型值指的是那些保存在栈内存中的简单数据段,即这种值完全保存在内存 中的一个位置。
- 引用类型值则是指那些保存在堆内存中的对象,意思是变量中保存的实际上只 是一个指针,这个指针指向内存中的另一个位置,该位置保存对象。
2. js垃圾回收:
- 目前JS的垃圾回收机制无非就是两种:
- 标记清除(make-and-sweep)
- 引用计数(reference counting)
- 标记清除:标记清除简单的来说就是给各个变量名打上 YES or NO的标签以供JS引擎进行处理(当然打什么标签自己理解即可)。
- 在和执行上下文类似的的环境中当变量名称进入环境的时候,那么变量会被打上 YES。一般来说是绝对不会释放被打上YES,标签的变量内存的,一旦变量在出了该环境时,变会被打上 NO标签(和作用域貌似有点像),JS引擎会在一定时间间隔或者设置的时间来进行扫描,对NO标签的进行剔除以释放其内存。
- 引用计数(查了很多资料,还是无法找到其真正的计算方式) 一般来说,引用计数的含义是跟踪记录每个值被引用的次数。
- 当声明一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数便是1,如果同一个值又被赋给另一个变量,则该值的引用次数加1,相反,如果包含对这个值引用的变量又取得了另一个值,则这个值的引用次数减1。当这个值的引用次数为0时,说明没有办法访问到它了,因而可以将其占用的内存空间回
3. js里的作用域是什么样子的?
- 大多数语言里边都是块作作用域,以{}进行限定,js里边不是.js里边叫函数作用域,就是一个变量在全函数里有效.比如有个变量p1在函数最后一行定义,第一行也有效,但是值是undefined.
- JS中作用域只有两种:
- window全局作用域、
- 函数执行形成的私有作用域;
4. JS对象分为“内部对象”、“宿主对象”和“自定义对象”三种。
- 内部对象
- js中的内部对象包括Array、Boolean、Date、Function、Global、Math、Number、Object、RegExp、String以及各种错误类对象,包括Error、EvalError、RangeError、ReferenceError、SyntaxError和TypeError。
- 其中Global和Math这两个对象又被称为“内置对象”,这两个对象在脚本程序初始化时被创建,不必实例化这两个对象。
- 宿主对象
- 浏览器对象:如Window和Document等等。navigator对象表示浏览器的信息,最常用的属性包括:screen;location对象表示当前页面的URL信息。
- 例如,一个完整的URL:
- 自定义对象
5. js一个有三种方法创建对象,
- 对象直接量
var obj2 = {
name: "ys",
age: 12
};
-
new创建对象
- 系统内置对象var obj2 = new Array();
- 自定义对象var obj1 = new Object();
-
Object.create()创建
var obj1 = Object.create({
name: "ys",
age: 12
});
6. js定义类的方法
- 主要有构造函数原型和对象创建两种方法。
- 构造函数方法定义类
function Person(){
this.name = 'michaelqin';
}
Person.prototype.sayName = function(){
alert(this.name);
}
var person = new Person();
person.sayName();
- 对象创建方法定义类
var Person = {
name: 'michaelqin',
sayName: function(){ alert(this.name); }
};
var person = Object.create(Person);
person.sayName();
4. 类
1. 构造函数
- 属性写在构造函数 方法写在原型(prototype)
function Person(name,age){
this.name = name,
this.age = age
// this.say = function(){
// console.log(this.name+'12345');
// }
}
Person.prototype.sex = "女";
Person.prototype.say = function(){
console.log(this.name+'12345');
}
var p1 = new Person("zz",21);
console.log(p1.sex);
p1.say();
2. 原型 prototype
- prototype属性,是一个指针,指向他的原型对象
- 原型中方法被实例化对象所共享
- prototype下有constructio属性指向他的构造函数
3. 原型链
- 当从一个对象那里调取属性或方法时,如果对象自身不存在这样的属性或方法,就会去自己关联的prototype对象那里寻找,如果prototype没有,就会去prototype关联的前辈prototype那里寻找,如果再没有则继续查找prototype.prototype引用的对象,以此类推,直到为underfined从而形成所谓的原型链
5. 继承
继承:子类继承父类中的属性和方法
多态:当前方法的多种形态->后台语言中:多态包含重载和重写
“JS中不存在重载”,方法名一样的话,后面的会把前面的覆盖掉,最后只保留一个
"JS中有一个操作类似重载但是不是重载":我们可以根据传递参数的不一样的,实现不同的功能,属于函数的多态性;
1. 原型链继承
- 让新实例的原型等于父类的实例。
- 实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。
- 新实例不会继承父类实例的属性!
- 缺点
- 新实例无法向父类构造函数传参。
- 继承单一。
- 所有新实例都会共享父类实例的属性。原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改
2. 借用构造函数继承
- 使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类
- 用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
- 只继承了父类构造函数的属性,没有继承父类原型的属性。
- 解决了原型链继承缺点1.2.3。
- 可以继承多个构造函数属性(call多个)。
- 在子实例中可向父实例传参。
- 缺点:
- 只能继承父类构造函数的属性。
- 无法实现构造函数的复用。(每次用每次都要重新调用)
- 每个新实例都有父类构造函数的副本,臃肿。
3. 实例继承
- 为父类实例添加新特性,作为子类实例返回
4. 组合继承(组合原型链继承和借用构造函数继承)(常用)
- 结合了两种模式的优点,传参和复用
- 可以继承父类原型上的属性,可以传参,可复用。
- 每个新实例引入的构造函数属性是私有的。
- 缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
5. 原型式继承
- 用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
- 类似于复制一个对象,用函数来包装。
- 缺点
- 所有实例都会继承原型上的属性。
- 无法实现复用。(新实例属性都是后面添加的)
6. 寄生式继承
- 就是给原型式继承外面套了个壳子。
- 优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。
- 缺点:没用到原型,无法复用。
7. 寄生组合式继承(常用)
- 修复了组合继承的问题
- 寄生:在函数内返回对象然后调用
- 组合:
- 函数的原型等于另一个实例。
- 在函数中用apply或者call引入另一个构造函数,可传参
6. this
- 函数中 对当前对象的引用
- this指向window
- 定时器
- 在定时器中指向window
- 其实普通的函数和定时器都是window下的方法,所以都指向window
- 在一个对象中的方法中this批向当前对象(new了)
- 绑事件是事件源(真正触发的)
- 改变this
-
call( ) 方法 改变指针 第一个参数是一个要改变指针的对象,后面的参数是方法需要的参数
-
apply( ) 方法 改变指针 第一个参数是一个要改变指针的对象第二个参数时一个数组,数组里是方法的参数
-
bind( ) 方法 改变指针 第一个参数是一个要改变指针的对象,后面的参数是方法需要的参数
-
call 和 apply 会自动调用方法 bind需要手动调用方法
-
f1.call(oDiv,22,33);
f1.apply(obj,[1,2]);
f1.bind(oDiv,22,33)();
7. 事件
1. 事件
| 事件 | 解说 |
|---|---|
| event.preventDefault | 阻止默认事件(return false) |
| e.target | 事件源 触发当前事件的源头(与this不一定相等 事件冒泡) |
| event.onclick | 鼠标点击时触发此事件 |
| event.ondblclick | 鼠标双击时触发此事件 |
| onmousedown | 按下鼠标时触发此事件 |
| onmouseup | 鼠标按下后松开鼠标时触发此事件 |
| onmouseover | 当鼠标移动到某对象范围的上方时触发此事件 |
| onmousemove | 鼠标移动时触发此事件 |
| onmouseout | 当鼠标离开某对象范围时触发此事件 |
| onkeypress | 当键盘上的某个键被按下并且释放时触发此事件. |
| onkeydown | 当键盘上某个按键被按下时触发此事件 |
| onkeyup | 当键盘上某个按键被按放开时触发此事件 |
| addEventListener('事件',function(){},false) | 监听事件 可以给元素绑定多个相同事件 (false事件冒泡,true事件捕获) |
2. 绑定事件
- 绑定事件
oDiv.onclick = function(){}
- 监听事件
- 可以给元素绑定多个相同事件 (false事件冒泡,true事件捕获)
addEventListener('click',function(){},false)
3. 事件对象属性(鼠标)
| 属性名 | 值类型 | 读/写 | 描述 |
|---|---|---|---|
| clientX | Integer | R | 事件发生时,鼠标在客户端区域的X坐标,客户端区域是指页面可视区域 |
| clientY | Integer | R | 事件发生时,鼠标在客户端区域的Y坐标 |
| screenX | Integer | R(IE) R/W(W3C) | 相对于屏幕的鼠标X坐标 |
| screenY | Integer | R(IE) R/W(W3C) | 相对于屏幕的鼠标Y坐标 |
4. 事件冒泡
- 事件传播从里向外 . 子元素太多
- 后插入元素的事件绑定问题
- 不是所有的事件都能冒泡,例如:blur、focus、load、unload\mouseleave,mouseEnter
5. 事件捕获
- 事件传播从外向里
addEventListener('事件',function(){},false)监听事件- 可以给元素绑定多个相同事件,最后参数false事件冒泡,true事件捕获
6. 事件委托
- 后生成元素的事件绑定问题
- 利用事件冒泡
- 动态添加的元素,无法在已进入页面时绑定事件,把事件绑定在已存在的父元素上
1. 代理/委托:
- 利用事件冒泡。把子元素的事件绑定给父元素。
$companyList.on('click', 'li', function() {});
2. 事件委托的局限性:有些事件没有冒泡行为,focus,blur没有
3. 为什先捕获后冒泡;历史问题,网景公司提出捕获,ie提出冒泡;
4. 取消事件冒泡(事件传播)
- 标准浏览器:e.stopPropagation;
- IE:window.event.cancelBubble=true;(为了做兼容,如果在前面写明e=e||window.event;IE里面就是e.cancelBubble=true;)
7. target:
- e.target(标准浏览器)||e.srcElement(IE)
- e.target获得真正触发的目标元素。current
- target返回给谁绑定的事件就返回谁。(在有事件冒泡的情况下)
8. 阻止默认
1. 阻止事件默认行为:e.preventDefault(); IE:e.returnValue = false ;
2. 阻止鼠标右键的默认行为
.oncontextmenu{
return false;阻止默认行为的
preventDefault()
}
8. 闭包
- (解决作用域的问题)(闭包的实质是一个函数,是一个用于返回局部变量值的函数)
- 内部函数引用了外部函数的局部变量(包括外部函数的形参),这使得外部函数调完毕后,该局部变量将不会被释放
- 所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁
- 外部函数有内部函数
- 内部函数会使用外部函数里的局部变量
1. 作用:
- 希望一个变量长期驻扎在内存中
- 私有成员的存在
//ul里面有很多li,点击li显示自己索引),循环会马上执行完.不能保存变量
for(var i = 0;i<5;i++){
(function(idx){
XX.onclick = function(){
alter(idx);
}
})(i);>
}
- 原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中不会在调用结束后,被垃圾回收机制
2. 在什么场合下用
- 保护变量;用自运行的匿名函数来实现;
- 协调异步代码;自运行的匿名函数来实现,并且传参进去(异步代码需要用到原来的变量,通过作为函数的参数传进去;)
- 避免全局变量的污染
- 私有成员的存在
3. 闭包的问题:
- 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决办法是,在退出函数之前,将不使用的局部变量全部删除。
- IE中在使用完闭包后,将导致引用常驻内存中而不被释放,需要将其手动释放
3. 优点:
-
闭包内的变量不会被垃圾回收机制处理掉,一直存在内存中
-
可以拿到索引值(for循环页面一加载就完成到max)
-
避免全局变量的污染
9. 函数节流
throttle- 限制一个函数在一定时间内只能执行一次
1. 使用场景
- 懒加载、滚动加载、加载更多或监听滚动条位置;
- 百度搜索框,搜索联想功能;
- 防止高频点击提交,防止表单重复提交;
- 时间戳
function throttle(fn,wait){
var pre = Date.now();
return function(){
var context = this;
var args = arguments;
var now = Date.now();
if( now - pre >= wait){
fn.apply(context,args);
pre = Date.now();
}
}
}
function handle(){
console.log(Math.random());
}
window.addEventListener("mousemove",throttle(handle,1000));
- 定时器
function throttle(fn,wait){
var timer = null;
return function(){
var context = this;
var args = arguments;
if(!timer){
timer = setTimeout(function(){
fn.apply(context,args);
timer = null;
},wait)
}
}
}
function handle(){
console.log(Math.random());
}
window.addEventListener("mousemove",throttle(handle,1000));
10. 函数防抖
- 就是指触发事件后,在规定时间内内函数只能执行一次,如果触发事件后在规定时间内内又触发了事件,则会重新计算函数延执行时间
function debounce(fn,wait){
var timer = null;
return function(){
if(timer !== null){
//清掉上一次计时器
clearTimeout(timer);
}
timer = setTimeout(function(){
fn.apply(this);
}.bind(),wait);
}
}
var oBtn = document.getElementById('btn');
oBtn.onclick = debounce(function(){
console.log(Date.now())
},300);
11. JS任务队列
1. JS单线程
- 同步任务 在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务
- 异步任务(定时器) 只有任务队列通知主线程,某个异步任务可以执行了,这个任务才会进入主线程执行
2. 事件循环
- 所有同步任务在主线程执行,形成一个执行栈,主线程有一个任务队列,执行栈所有任务执行完成系统读取任务队列,调出一个任务,继续执行
3. 宏任务 微任务
- 宏任务
- 整体代码script
- setTimeout setInterval
- 宏任务队列可以有多个
- 微任务
- new Promise.then(回调)
- process.nextTick
- 微任务队列只有一个
- 执行规则
- 上一个宏任务队列执行完毕后,如果有微任务队列就会执行微任务队列中的所有微任务
- 当宏任务队列中的任务执行完毕后,查看是否有微任务,在执行宏任务

4. js的异步怎么实现的回调函数
- javascript的异步机制。执行同步任务 -> 检查任务队列中是否有任务 -> [有如果则执行] -> 检查任务队列中是否有任务 -> [有如果则执行] -> ......
- 可见主线程在执行完同步任务之后,会无限循环地去检查任务队列中是否有新的“任务”,如果有则执行。而这些任务包括我们在异步任务中定义的回调函数,也包括用户交互事件的回调函数。通过事件循环,Javascript不仅很好的处理了异步任务,也很好的完成了与用户交互事件的处理。因为在完成异步任务的回调函数之后,任务队列中的任务都是由事件所产生的,因此我们也把上述的循环过程叫做事件循环。
- 事件监听
- 发布订阅模式
- Promise
- Generator (ES6)
- async (ES7)
12. Ajax
- 客户端与服务器端异步的通信的技术
- 是一种异步请求数据的web开发技术,对于改善用户的体验和页面性能很有帮助它扮演的角色相当于通信桥梁,使得浏览器可以发出HTTP请求与接收HTTP响应
- GET - 从指定的资源请求数据
- POST - 向指定的资源提交要处理的数据
1. ajax请求过程
- 创建 XMLHttpRequest 对象
var xmlhttp;
if (window.XMLHttpRequest){
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else{
// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
- 向服务器发送请求
- GET
//true代表是否是异步
xmlhttp.open("GET","test1.txt",true);
xmlhttp.send();
- POST
xmlhttp.open("POST","demo_post.asp",true);
xmlhttp.send();
- 如果需要像 HTML 表单那样 POST 数据,用setRequestHeader()设置请求头。然后在 send() 方法中规定您希望发送的数据
//请求方式 url(不能写参数) 是否异步
xmlhttp.open("POST","ajax_test.asp",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
//参数
xmlhttp.send("fname=Bill&lname=Gates");
- 服务器响应
- 执行回调,在回调函数中进行相应的dom操作
xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState==4&&xmlhttp.status==200){
//就可以执行相应的dom操作
//返回数据xmlhttp.responseText
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
2. GET和POST区别
- get使用较多,一般获取数据使用get,请求数据量小,传递数据受url限制(2048),可以缓存,post不可以,get请求的记录会留在历史记录中,post请求不会留在历史记,录get放在地址栏中不安全,post封装在包体里相对安全,get后退不会有影响,post后退会重新进行提交,get请求只URL编码,post支持多种编码方式
3. readyState有5种值
0: 请求未初始化
1: 服务器连接已建立
2: 请求已接收
3: 请求处理中
4: 请求已完成,且响应已就绪
4. staus状态码
200请求成功;
500:未知服务器错误
503:服务器超负荷请求;比如一个1000人可以访问,多余一千人访问就会出现503
400:请求参数错误;
401:请求权限不够
404:找不到,地址不存在;
504:服务器请求响应超时
301:永久重定向(永久转移) 访问老地址(老域名)永久指向新地址(新域名)这就是301永久转移
302:临时重定向(临时转移) 服务器临时转移地址,缓解服务器压力;
304:读取的缓存数据; 我们不经常改变的文件比如文件中css,js我们存在缓存中,页面再次刷新请求服务多次,我们不怎么改变的文件走缓存
307:临时重定向
302 会将 POST 请求转为 GET,而 303 是规范强制规定将 POST 转为 GET请求,请求地址为 header 头中的 Location,307则不一样,规范要求浏览器继续向 Location 的地址 POST 内容
5. ajax的优点:
- 无刷新更新数据。
- 异步与服务器通信。
- 前端和后端负载平衡。(减轻服务器的负担,AJAX的原则是“按需取数据”,可以最大程度的减少冗余请求和响应对服务器造成的负担)
- 基于标准被广泛支持。
- 界面与应用分离。
6. AJAX的缺点:
- AJAX干掉了Back和History功能,即对浏览器机制的破坏。
- AJAX的安全问题。
- 违背URL和资源定位的初衷。
- 客户端过肥,太多客户端代码造成开发上的成本。
13. 跨域
- 跨域:从一个域上加载的脚本不允许访问另外一个域的文档属性
1. 同源
- 同源:URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相 同,则表示他们同源。就是一个宇
- 同源策略:同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。同源策略确实能规避一些危险
- 跨端口号也是跨域
- 同源策略限制以下
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM 和 Js对象无法获得
- AJAX 请求不能发送
2. JSONP
- 通过动态创建script,再请求一个带参网址实现跨域通信
- 实现原理是利用script、img标签的src属性可以跨域加载别的域中的文件来实现的
<script>
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
script.src ='http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
//添加到body
document.body.appendChild(script);
// 回调执行函数
function handleCallback(res) {
alert(JSON.stringify(res));
}
</script>
// 服务端返回如下(返回时即执行全局函数):
handleCallback({"status": true, "user": "admin"})
2. document.domain + iframe跨域
- 仅限主域相同,子域不同的跨域应用场景
- iframe加载进来一个页面
- 两个页面都通过js强制设置document.domain为基础主域,就实现了同域
- 调用上一级(多层为最顶层)页面
window.top.fumction()
- 父窗口:(www.domain.com/a.html)
<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>
document.domain = 'domain.com';
var user = 'admin';
</script>
- 子窗口:(child.domain.com/b.html)
<script>
document.domain = 'domain.com';
// 获取父窗口中变量
alert('get js data from parent ---> ' + window.parent.user);
</script>
-
数据传到后台,后台实现数据传输
-
服务器代理
- 服务器端程序是不存在跨域问题
- 浏览器跨域访问js、css、img等常规静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在nginx的静态资源服务器中加入以下配置。
location / {
//添加允许访问的源
add_header Access-Control-Allow-Origin http://www.domain1.com;
}
3. iframe 的用法与注意事项
- 要确保在iframe加载完成后再进行操作,如果iframe还未加载完成就开始调用里面的方法或变量,会产生错误。
- 尽量在不要在父页面中调用子页面中的页面元素或函数,所有涉及的交互操作尽量放在子页面中来完成。
- 判断iframe是否加载完成有两种方法:
- iframe上用onload事件
- 用document.readyState=="complete"来判断
14. jQuery
$('#div1').css();$()函数,返回值是jq对象
1. 模拟JQ原理
- jq最核心的是
返回一个新的jq对象,同时在
函数中返回的jq对象..
<div id="div1"></div>
<script>
function $(str){
return new Jquery(str);
}
function Jquery(str){
//查找所有符合对象放入数组
this.eles = [];
//返回第一个字符
var sel = str.charAt(0);
var name = str.substr(1);
if(sel == '#'){
this.eles.push(document.getElementById(name));
}else if(sel == '.'){
//this.eles.concat(document.getElementById(name));
this.eles = [...document.getElementById(name)];
}
console.log(this.eles);
}
$('#div1');
</script>
2. JQ实现css属性
Jquery.prototype.css = function(arg1,arg2){
//设置css属性
if(typeof arg1 == "string" && typeof arg12 == "string"){
this.eles.map(function(ele,index){
ele.style[arg1] = arg2;
})
}else if(typeof arg1 == "object" && arg2 == undefined){
this.eles.map(function(ele,index){
for(key in arg1){
//将每一个元素的arg1[key]属性设置成
ele.style[key] = arg1[key];
}
})
}
}
$("#div1").css({
background:"red",
height:"100px"
});
3. 链式
Jquery.prototype.on = function(evenName,handle){
this.eles.map(function(ele,index){
ele.addEventListener(evenName,handle)
})
}
$("#div1").css({
background:"red",
height:"100px"
}).on('click',function(){
console.log('haha');
});
4. jq常见优化方案
- 缓存jq对象,如:var
('#div1');
- 在原生的js没有什么兼容性的情况下,可以尽量使用原生的js,因为jq的效率比较低
- 在使用$选择器的时候应该指定上下文,提高搜索速度
- 合理的使用事件委托
5. JQuery的特点
- 强大的DOM选择器(CSS1-3 + XPath)
- 解决兼容性问题
- 有现成的组件
- 可扩展性强。(自己封装jq插件)
- 事件、样式、动画支持。
- Ajax操作支持。
- 跨浏览器兼容。
6. jq中的事件绑定
- on()这个是现在标准和推荐的方法 // on函数的第二个参数用来指定一个选择器,当使用这个选择器的时候,就可以实现事件委托
- 以前还有直接: click(function(){});
- live:专门是用来给后生成的元素绑定的(用js动态生成的元素)
- one 只执行一次
- delegate 事件代理
- bind:就是通用的事件的绑定方法
7. 你常用JQ方法有哪些,给我简单介绍一下
- 选择器、:eq(),:has(),p:nth-child(2)(是p元素,且是父元素的第二个子元素)p:nth-of-type(2)(父元素的第二个p元素) nth-child()(1开始),其余都是0开始
- 属性CSS、 1) .prop与.attr区别: 对于HTML元素本身就带有的固有属性,在处理时,使用prop方法。 对于HTML元素我们自己自定义的DOM属性,在处理时,使用attr方法。 2).innerHeight/innerWeight(包括padding不包括border) outerHeight()outerHeight(true)(包括border,如果true的话加margin) 3).offset相对于文档.position相对于最近已定位的父元素
- dom操作、 .remove() 将元素移出DOM。 当我们想将元素自身移除时我们用 .remove(),同时也会移除元素内部的一切,包括绑定的事件及与该元素相关的jQuery数据。要删除的元素不删除数据和事件的情况下,使用.detach()来代替。。 当需要移走一个元素,不久又将该元素插入DOM时用.detach()
- 遍历、.eq()/.siblings()
- 事件、.end连续 . 操作
- 效果 .hide()/.toggle()
15. CSS3
#div1{
/*过渡:属性 执行时间 方式 延迟时间*/
tranaition:width 2s ease 2s;
}
- 规定动画
keyframes关键字
#div1{
<!--animation:动画名 指定时间完成 完成方式(ease ease-in ease-out ease-in-out linear) 延迟时间 动画播放次数 结束帧(forwards结束位置)-->
animation:myfirst 2s ease 2s 2;
}
@keyframes myfirst
{
from {background: red;}
to {background: yellow;}
}
@-webkit-keyframes myfirst /* Safari 与 Chrome */
{
from {background: red;}
to {background: yellow;}
}
0. 常用属性
- clear:清除浮动
- 当使用float布局时,其元素不占常规流,若需要清除浮动,可在其他元素上设置clear属性
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="utf-8" />
<title>清除浮动小案例</title>
<style>
.float-item {
float: right;
background: #ff3e3e;
color: #fff;
padding: 7px;
}
.clear-item {
clear: right;
}
</style>
</head>
<body>
<div class="float-container">
<div class="float-item">浮动对象</div>
<div class="clear-item">清除浮动的对象</div>
</div>
</body>
</html>
- @keyframes media 媒体查询 box-shadow
1. 弹性盒模型
flex
- Flex是Flexible Box的缩写,意为弹性布局
- 设为Flex布局后子元素的float、clear、vertical-align属性将失效。
div{
<!--给父元素设置-->
display:flex;
}
flex-grow
- 占父元素剩余空间比例
- 设置在子元素
flex-direction
容器内元素的排列方向(默认横向排列)
flex-direction:row;沿水平主轴让元素从左向右排列flex-direction:column;让元素沿垂直主轴从上到下垂直排列flex-direction:row-reverse;沿水平主轴让元素从右向左排列
lex-wrap
容器内元素的换行(默认不换行)
flex-wrap: nowrap;(默认)元素不换行flex-wrap: wrap;元素换行
justify-content
元素在主轴(页面)上的排列
justify-content : center;元素在主轴(页面)上居中排列justify-content : flex-start;元素在主轴(页面)上由左或者上开始排列justify-content : flex-end;元素在主轴(页面)上由右或者下开始排列justify-content :space-between;元素在主轴(页面)上左右两端或者上下两端开始排列justify-content :space-around;两元素间距相等 距父容器距离相等 6.align-items元素在主轴(页面)当前行的横轴(纵轴)方向上的对齐方式align-items : flex-start;弹性盒子元素的侧轴(纵轴)起始位置的边界紧靠住该行的侧轴起始边界(靠上对齐)。align-items : flex-end;弹性盒子元素的侧轴(纵轴)起始位置的边界紧靠住该行的侧轴结束边界。(靠下对齐)align-items : center;弹性盒子元素在该行的侧轴(纵轴)上居中放置。(居中对齐)align-items : baseline;如弹性盒子元素的行内轴与侧轴为同一条,则该值与flex-start等效。其它情况下,该值将参与基线对齐。(靠上对齐)
2. 行列布局 (定位、浮动、flex)
- 左侧固定中间自适应
- 定位
<style>
#baba{
width: 100%;
height: 500px;
background: #653232;
position: relative;
}
.left{
width: 200px;
height: 500px;
background: #445544;
position: absolute;
top: 0;
left: 0;
}
.right{
height: 500px;
margin-left: 200px;
background: #ff0036;
}
</style>
<body>
<div id="baba">
<div class="left">z</div>
<div class="right">z</div>
</div>
</body>
- flex
<style>
*{
margin: 0;
padding: 0;
}
#box{
width: 100%;
height: 500px;
display: flex;
}
#box>div:nth-child(1){
width: 200px;
height: 400px;
background-color: brown;
}
#box>div:nth-child(2){
height: 400px;
background-color: violet;
flex-grow: 1;
}
</style>
<body>
<div id="box">
<div></div>
<div></div>
</div>
</body>
效果图:

- 浮动
<style>
.container{
width: 100%;
height: 500px;
background: #000000;
}
.left{
width: 100px;
height: 500px;
background: #ffffff;
float: left;
}
.right{
width: 100px;
height: 500px;
background: #ff0036;
float: right;
}
.center{
margin: 0 100px;
height: 500px;
background: #559966;
}
</style>
<body>
<div class="container">
<div class="left">我是左边</div>
<div class="right">我是中间</div>
<div class="center">我是右边</div>
</div>
</body>
- flex
<style>
*{
margin: 0;
padding: 0;
}
#box{
width: 100%;
height: 500px;
display: flex;
}
#box>div:nth-child(1){
background-color: aqua;
flex: 0 0 200px;
}
#box>div:nth-child(2){
background-color: black;
flex: auto;
}
#box>div:nth-child(3){
background-color: blue;
flex: 0 0 200px;
}
</style>
<body>
<div id="box">
<div>我是左边</div>
<div>我是中间</div>
<div>我是右边</div>
</div>
</body>
效果图:

- 定位
<style>
*{
margin: 0;
padding: 0;
}
.top{
height: 50px;
width: 100%;
background: #654826;
position: absolute;
top: 0;
}
.buttom{
height: 50px;
width: 100%;
background: #872387;
position: absolute;
bottom: 0;
}
.center{
background: #821248;
width: 100%;
position: absolute;
top: 50px;
bottom: 50px;
height: auto;
}
</style>
<body>
<div class="top"></div>
<div class="center"></div>
<div class="buttom"></div>
</body>
- flex
<style>
*{
margin: 0;
padding: 0;
}
html,
body
{
width: 100%;
height: 100%;
}
#box{
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
#box>div:nth-child(1){
background-color: aqua;
height: 50px;
}
#box>div:nth-child(2){
background-color: black;
flex-grow: 1;
}
#box>div:nth-child(3){
background-color: blue;
height: 50px;
}
</style>
<body>
<div id="box">
<div></div>
<div></div>
<div></div>
</div>
</body>
效果图:

16. 组件
1. 注意事项(开发规范)
防止变量污染:使用闭包(函数立即调用/函数立即调用/类的思想)
命名:尽量不使用ID,Class加_
公共的方法给window(window.xx=xx)
回调:arguments.callee指向原函数
依赖关系复杂: require.js(模拟包)
2. 组件的思想
- 组合性
- 组件之前应该是可以组合的。我们知道前端页面的展示都是一些HTML DOM的组合,而组件在最终形态上也可以理解为一个个的HTML片段。那么组成一个完整的界面展示,肯定是要依赖不同组件之间的组合,嵌套以及通
- 重用性
- 任何一个组件应该都是一个可以独立的个体,可以使其应用在不同的场景中。
- 可维护性
- 任何一个组件应该都具有一套自己的完整的稳定的功能,仅包含自身的,与其它组件无关的逻辑,使其更加的容易理解,使其更加的容易理解,同时大大减少发生bug的几率。
17. 移动端兼容问题
0. 移动端适配问题
- 响应式布局@media(根据窗口 布局变化)
- 弹性盒模型
- 等比缩放布局
1. 设计稿2倍图 实现绝对1px的边框(0.5px)安卓系统 ios7以下不⽀持0.5px
- 缩放、写1px的阴影
<!--css-->
<style>
*{
padding: 0;
margin: 0;
}
div{
width: 2rem;
height: 2rem;
position: relative;
}
button{
width: .5rem;
height: .3rem;
position: absolute;
z-index: 2;
}
div::before{
content: '';
display: block;
width: 200%;
height: 200%;
top: 0;
left: 0;
border: 1px solid #eeeeee;
-webkit-transform: scale(0.5);
transform: scale(0.5);
transform-origin: 0,0
position: absolute;
z-index: 1;
}
</style>
<!--html-->
<body>
<div>
<button>点击</button>
</div>
</body>
<!--js-->
<script>
var Obtn = document.getElementsByTagName("button")[0];
Obtn.onclick = function(){
alert("hello world");
}
</script>
2. 点透事件
3. 低版本安卓⼿机不⽀持背景⾊渐变, 在单独写⼀个背景⾊
background-color:#ff7e33;
background-image:linear-gradient(45deg,#ff5303,#ff9143);
4. 低版本手机 尤其是4.+系统的不支持es6写法
vconsole会报错script error ,但无法查出具体错误 需要加垫片babel-polyfill
5.点击输⼊框拉起键盘 输⼊完成后 会发现⻚⾯⾼度⽆法被撑开
(安卓手机会出现) 重新获取⻚⾯高度并赋值
6. 图片上传,不同⼿机的input file展现形式不同
ios系统⼀般会出现拍照和相册两个选项,安卓手机拍照、相册选择有时只出现⼀ 项,有时根据系统不同会展示其他项,12306的webview不⽀持input file 会出现闪退的情况
7.ios 11系统input光标错位(系统本身原因)
8.页面滑动吸顶或吸底效果,手机qq的webview里无法拉动
需要阻止页面的默认动作
9.ios系统的input框会有⼀个隐形 需要去掉
-webkit-appearance: none;
10.有的⼿机input placeholder⽆法垂直居中
可以设置input高度小⼀点 然后上下加padding
网上的解决方式line-height:normal
11.ios系统⾳频⽆法⾃动播放,需监听⽤户有操作之后⼿动触发
18. ES6
1. 新特性
- 类的支持,模块化,箭头操作符,let/const块作用域,字符串模板,解构,参数默认值/不定参数/拓展参数,for-of遍历,generato r器, Map/Set, Promise
- Let(定义变量)const(定义常量)块级作用域(只对let const有效) arrow(箭 头函数) class map set 数组解构 对象解构 扩展运算符 数组对象字符串新加了一些函数 promise generator
- let
- let没有变量提升(在当前作用域顶部定义变量但未赋值) let不能重复命名
- Let只在块级作用域有效(作用域外面不好使,一个{}就是一个作用域,for{}也是一个块作用域)
- let有临时失效区(暂时性死区)当前作用域下不允许同名变量
- const
- 不存在变量提升
- 不允许重复声明
- 暂时性死区
- 块计作用域
- 常量声明 地址不可更改 值可 使用freeze
2. 箭头函数
- 函数体内的this对象,this指向父作用域this,就是定义时所在的对象,而不是使用时所在的对象。
- 不可以当作构造函数,不可以使用new命令,否则会抛出一个错误。
- 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用rest 参数代替。
- 如果你想在一个新的函数内部用到当前的this,那就用箭头函数来做.而如果新的函数里要用自己的this,那就不要用箭头函数
3. 解构
解构 :从数组和对象中提取值,对变量进行赋值
- 数组的解构
- 按照顺序依次赋值
var [a,b,c] = [1,2,3];
- 对象的解构
- 按照key赋值
let {name,age} = {name:'xm',age:4};
console.log(name,age);
//取别名
let {name:x,age} = {name:'xm',age:4};
console.log(x,age);
- 字符串的解构
- 把字符串中每一个字符提取出来分别进行赋值
const [a,b,c,d,e] = 'hello';
console.log(a); //h
console.log(b); //e
console.log(c); //l
console.log(d); //l
console.log(e); //o
let { length : len} = 'yahooa';
console.log(len); //5
- 解构用途
- 深拷贝
let x = 2;
let y = 3;
[y,x]=[x,y];
console.log(x);//3
console.log(y);//2
4. 扩展运算符(...)
- 数组
- 数组合并
- 数组复制(深拷贝)
JSON.stringify( )JSON.parsedeepClone()- 解构运算符
concat( )silce( )只是对数组的第一层进行深拷贝
let array = [1,2,3]
var a1 = [...array]; // 复制一个数组 可以实现数组的深拷贝
console.log(a1); //[1,2,3]
let a2 = [...array,'a','b'] //作为数组的一部分
console.log(a2);//[1,2,3,'a','b']
let a3 = array;
console.log(a3) //[1,2,3]
array[0] = 4;
console.log(a3) //[4,2,3]
console.log(a1); //[1,2,3]
let a4 = [4,5,6]
let a5 = [...array,...a4] // 数组的合并
console.log(a5)//123456
console.log(array)//123
console.log(a4)//456
let a6 = [1,2,3]
let a7 = [4,5,6]
console.log(a6.concat(a7))//123456
console.log(a6)//123
console.log(a7)//456
- 对象
- 合并对象
- 不同的属性会合并,相同的属性 后面的会把钱前面的覆盖
- 对象深拷贝
deepClone( )- 扩展运算符
let p1 = {
name: 'xm',
age: '4'
}
let p2 = {...p1}
p1.age = 2;//p2不会改变
let p1 = {
name: 'xm',
age: '4'
}
let p2 = {
weight: '8kg',
age: '2'
}
let p3 ={...p2,...p1} // 对象的合并
- 类数组转数组
- 扩展运算符
Array.from( )
let aLi = document.querySelectorAll('li'); //NodeList
console.log(aLi);
let b = [];
for(let c = 0; c<aLi.length; c++){
b[c] = aLi[c]
}
console.log(b)
let aList = [...aLi]; // 可以将类数组转换成数组
console.log(aList);
aList.push('wxc');
console.log(aList);
let b1 = document.getElementsByTagName('li'); //HTMLCollection
console.log(b1)
// rest 剩余的
function fun(x,...rest){
console.log(x);
console.log(rest);
}
fun(1,2,3,4)
console.log('----------')
function fun1(){
// arguments.callee 当前方法
console.log(11111)
// arguments.callee() 递归调用
}
fun1(1,2,3,4)
5. rest
function fun(x...rest){
console.log(x);//1
console.log(rest);//234
}
fun(1,2,3,4);
6. 函数的扩展
fun.length获取没有设置默认值的形参个数fun.name获取方法名- 箭头函数
=>
- this指向父作用域this
- 不可以使用
arguments获取参数,可以使用rest获取参数 - 函数中只有一行代码 { } 可以省略
// 箭头函数中不可以使用arguments获取参数,可以使用rest获取参数
var fun3 = (...rest) => {
console.log(rest);
rest[0];
}
fun3(1,2,3)
arguments
- 一个数组
- 方法不设形参时 用arguments接受传的参数
- arguments.callee 当前正在执行的函数(本身),递归
function fun([x,y,z=4]){ // 设置默认值
//只有是undefined的时候才会使用默认值
console.log(x,y,z)
}
7. 模板字符串
- 使用 `` 包裹字符串
- 拼接 `` 括起来后 用${ }拼接
`Hello ${name}, how are you ${time}?`
8. 字符串方法
Number.includs( )检索字符串 返回true/falseNumber.startsWith( )返回布尔值 表示参数字符串是否在原字符串的头部Number.endsWith( )返回布尔值 表示参数字符串是否在原字符串的尾部padStart()用于头部补全,padEnd( )用于尾部补全
- 如果省略第二个参数,默认使用空格补全长度
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(0, 'ab') // 'x'
repeat(n)
- 返回一个新字符串,表示将原字符串重复n次
'x'.repeat(3) // "xxx"
9. 数值的扩展
Number.isFinite( )
- 用来检查一个数值是否为有限finite
- 如果参数类型不是数值,Number.isFinite返回false。
Number.isNaN( )
- 用来检查一个值是否为NaN。
- 如果参数类型不是NaN,Number.isNaN返回false。
Number.isInteger( )
- 用来判断一个数值是否为整数
Number.parseInt( )和Number.parseFloat( )
- 转为整数/浮点数
10. Math对象扩展
Math.trunc( )
- Math.trunc方法用于去除一个数的小数部分,返回整数部分。
Math.sign( )
-
判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。
- 正数 返回 +1
- 负数 返回 -1
- 0 返回 0
- -0 返回-0
- 其他 返回 NaN
11. 数组扩展
Array.from( )
- 将对象转为真正的数组(类数组的对象/对象)
Array.of( )
- 将值转换为数组
array.copyWithin( )
- 在当前数组内部,将指定位置的成员复制到其他位置(覆盖原有成员),然后返回当前数组,会修改当前数组
Array.prototype.copyWithin(target, start = 0, end = this.length)
- target(必需):从该位置开始替换数据。如果为负值,表示倒数。
- start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示从末尾开始计算。
- end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示从末尾开始计算。
// 将3号位复制到0号位
[1, 2, 3, 4, 5].copyWithin(0, 3, 4)
// [4, 2, 3, 4, 5]
// -2相当于3号位,-1相当于4号位
[1, 2, 3, 4, 5].copyWithin(0, -2, -1)
// [4, 2, 3, 4, 5]
// 将3号位复制到0号位
[].copyWithin.call({length: 5, 3: 1}, 0, 3)
// {0: 1, 3: 1, length: 5}
// 将2号位到数组结束,复制到0号位
let i32a = new Int32Array([1, 2, 3, 4, 5]);
i32a.copyWithin(0, 2);
// Int32Array [3, 4, 5, 4, 5]
// 对于没有部署 TypedArray 的 copyWithin 方法的平台
// 需要采用下面的写法
[].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
// Int32Array [4, 2, 3, 4, 5]
array.find( )
- 用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。
//找出数组中第一个小于 0 的成员。
[1, 4, -5, 10].find((n) => n < 0)
// -5
[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10
array.findIndex( )
- 返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2
array.fill( )
- 使用给定值,填充一个数组。
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]
- fill方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
for...of
- 循环输出数组每一项值
- keys()是对键名的遍历
- values()是对键值的遍历
- entries()是对键值对的遍历
array.includes( )
Array.prototype.includes方法返回一个布尔值,表示某个数组是否包含给定的值
array.forEach( )
- 遍历数组
array.filter( )
- 返回所有符合条件的内容的数组
[1, 5, 10, 15].filter(function(value, index, arr) {
return value > 9;
}) // 10 15
12. 对象的扩展
- 属性的简洁表示法
let name = 'xc';
let age = '18';
let obj = {
name,//属性简写
age,
eating(){//方法简写
console.log('meat');
}
}
- 属性名表达式
- JavaScript 定义对象的属性,有两种方法
// 方法一
obj.foo = true;
// 方法二
obj['a' + 'bc'] = 123;
let lastWord = 'last word';
const a = {
'first word': 'hello',
[lastWord]: 'world'
};
a['first word'] // "hello"
a[lastWord] // "world"
a['last word'] // "world"
Object.is( )判断严格相等
+0 === -0 //true
Object.is('-0',+0) //false
NaN === NaN //false
Object.is('NaN',NaN) //true
assign( )
- 方法用于对象的合并
- 如果只有一个参数,
Object.assign会直接返回该参数。 - 如果该参数不是对象,则会先转成对象,然后返回。
const target = { a: 1, b: 1 };
const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
//target {a:1, b:2, c:3}
//如果只有一个参数,Object.assign会直接返回该参数。
const obj = {a: 1};
Object.assign(obj) === obj // true
//如果该参数不是对象,则会先转成对象,然后返回。
typeof Object.assign(2) // "object"
Object.keysObject.valuesObject.entries
- 作为遍历一个对象的补充手段,供
for...of循环使用 - 返回数组
let {keys, values, entries} = Object;//对象解构赋值
let obj = { a: 1, b: 2, c: 3 };
for (let key of keys(obj)) {
console.log(key); // 'a', 'b', 'c'
}
for (let value of values(obj)) {
console.log(value); // 1, 2, 3
}
for (let [key, value] of entries(obj)) {
console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}
'name' in object
- 对象是否具有属性
- 返回布尔值
19.异步
1. Promise
- Promise是异步编程的一种解决方案,将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数(俗称回调地狱)
- 解决函数的回调嵌套问题
- 一个promise可能有三种状态:等待(pending)、已完成(fulfilled)、 已拒绝(rejected)
- 一个promise的状态只可能从“等待”转到“完成”态或者“拒绝”态,不能逆向转换,同时“完成”态和“拒绝”态不能相互转换
- promise必须实现then方法(可以说,then就是promise的核心),而且then必须返回一个promise,同一个promise的then可以调用多次,并且回调的执行顺序跟它们被定义时的顺序一致
- then方法接受两个参数,第一个参数是成功时的回调,在promise由“等待”态转换到“完成”态时调用,另一个是失败时的回调,在promise由“等待”态转换到“拒绝”态时调用。同时,then可以接受另一个promise传入,也接受一个“类then”的对象或方法,即thenable对象。
- resolve 成功回调
- reject 失败回调(只有promise对象)
Promise.prototype.then()
- 为 Promise 实例添加状态改变时的回调函数
Promise.prototype.catch()
- 用于指定发生错误时的回调函数
const promise = new Promise(function(resolve, reject) {
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
//方法一
const promise = new Promise(function(resolve, reject) {
setTimeout(function(){
reject();
},2000)
}).then(function(){//成功
//code
}).catch(function(){//失败
//code
});
//方法二
const promise = new Promise(function(resolve, reject) {
setTimeout(function(){
reject();
},2000)
}).then(function(){//成功
//code
},function(){//失败
//code
});
Promise.prototype.finally()
- finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。
Promise.all
- 用于将多个 Promise 实例,包装成一个新的 Promise 实例。
- 接受一个数组作为参数,p1、p2、p3都是Promise实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。
let p1 = new Promise(function(resolve,reject){
setTimeout(() => {
resolve();
},1000)
}).then(function(){
console.log(1111);
})
let p2 = new Promise(function(resolve,reject){
setTimeout(() => {
resolve();
},2000)
}).then(function(){
console.log(2222);
})
let p3 = new Promise(function(resolve,reject){
setTimeout(() => {
resolve();
},3000)
}).then(function(){
console.log(33333);
})
Promise.all([p1,p2,p3]).then(function(result){
console.log(result)
})
// 生成一个Promise对象的数组
const promises = [2, 3, 5, 7, 11, 13].map(function (id) {
return getJSON('/post/' + id + ".json");
});
Promise.all(promises).then(function (posts) {
// ...
}).catch(function(reason){
// ...
});
Promise.race
- 同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
- 只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
Promise.all([p1,p2,p3]).then(function(){
console.log('okokok');
})
2. genrator
- ES6提供的解决异步编程的方案之一
- 特点:
- function与函数名之间有一个星号
- 是一个状态机,内部用yield表达式来定义不同的状态
- generator函数返回的是指针对象,而不会执行函数内部逻辑
- 调用next方法函数内部逻辑开始执行,遇到yield表达式停止,返回
{value:yield后的表达式结果/无返回值undefined, done: false/true} - 再次调用next方法会从上一次停止时的yield处开始,直到后
- yield语句返回结果通常为
undefined,当调用next方法时传参内容会作为"启动时"yield语句的返回值。
function* test(){
console.log('开始');
yield '第一个yield';
console.log(12345);
}
var test = test();
console.log(test.next());
test.next();//若此行注释,代码执行到yield结束
3. defer和async
- 都能实现异步加载、延迟加载js - defer下载完之后等着,等dom结构渲染完(页面解析完毕)都加载完再执行,理论上可以保证文件加载顺序
- async下载完之后立即执行,不能保证文件加载顺序
//async
function foo(){
await 异步操作;
await 异步操作;
}
- 特点:
- 不需要像Generator去调用next方法,遇到await等待,当前的异步操作完成就往下执行
- 返回的总是Promise对象,可以用then方法进行下一步操作
- async取代Generator函数的星号*,await取代Generator的yield
- 语意上更为明确,使用简单
20. VUE
1. VUE
- Vue是以数据为驱动的,Vue自身将DOM和数据进行绑定,一旦创建绑定,DOM和数据将保持同步,每当数据发生变化,DOM会跟着变 化。
- ViewModel是Vue的核心,它是Vue的一个实例。Vue实例时作用域某个HTML元素上的,这个HTML元素可以是body,也可以是某个id所指 代的元素。 DOM Listeners和Data Bindings是实现双向绑定的关键。DOM Listeners监听页面所有View层DOM元素的变化,当发生变化,Model 层的数据随之变化;Data Bindings监听Model层的数据,当数据发生 变化,View层的DOM元素随之变化。
- Vue.js特点
- 简洁:页面由HTML模板+Json数据+Vue实例组成
- 数据驱动:自动计算属性和追踪依赖的模板表达式
- 组件化:用可复用、解耦的组件来构造页面 轻量:代码量小,不依赖其他库
- 快速:精确有效批量DOM更新
- 模板友好:可通过npm,bower等多种方式安装,很容易融入
2. VUE常用指令
v-for循环v-textv-html识别标签v-on绑定事件v-model双向数据绑定v-bind绑定属性v-ifhtml结构没有
v-ifv-else-ifv-else必须紧接着写
v-show:false->display:none
v-show的元素始终会被渲染并保留在 DOM 中v-if不满足条件 不生成html解构v-show改变元素的 CSS 属性display。
21. VUE生命周期
1. 生命周期
- 从Vue实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期
2. 创建期间的生命周期函数
1. beforeCreat
- 实例刚在内存中被创建出来,此时,还没有初始化好 el data methods 属性(undefind)
2. created
- 实例已经在内存中创建,此时 data 和 methods 已经创建好,el(undefind),此时还没有开始 编译模板
3. beforeMount
- 此时已经完成了模板的编译,元素已经挂载上,但是内容还没有填充进去
4. mounted
- 此时,已经将编译好的模板,挂载到了页面指定的容器中显示
3. 运行期间的生命周期函数
1. beforeUpdate
- 状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点,虚拟dom更新,真实dom不更新
2. updated
- 实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!
3. beforeDestroy
- 实例销毁之前调用。在这一步,实例仍然完全可用
4. destroyed
- Vue 实例销毁后调用。调用后,Vue实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
- 生命周期
22. VUE父子组件间传值
- 子组件可以使用 $emit 触发父组件的自定义事件。
1. 方法一
<div id="app">
<popcommon :title="logtitle" v-show="loginStatus" @hide="close"></popcommon>//父组件绑定close方法
</div>
<template id="common">
<div id="content">
//$emit('父组件方法',传递的参数)
<span @click="$emit('hide')">X</span>//触发父组件的自定义
</div>
</template>
<script>
new Vue({
el: '#app',
components:{
'popcommon':{
template:'#common',
props:['title']
}
},
methods:{
close(){
this.reinStatus = false,
this.loginStatus = false
}
}
})
</script>
2. 方法二
<div id="app">
<popcommon :title="logtitle" v-show="loginStatus" :closefun="close"></popcommon>
<!--父组件绑定属性-->
</div>
<template id="common">
<div id="content">
<button @click="closefun()">{{title}}</button>
<!--子组件绑定事件-->
</div>
</template>
<script>
new Vue({
el: '#app',
components:{
'popcommon':{
template:'#common',
props:['title','closefun']//父组件接收
}
},
methods:{
close(){
this.reinStatus = false,
this.loginStatus = false
}
}
})
</script>
3. 父组件可以使用 props 把数据传给子组件。
//父级
new Vue({
el:"#app",
data:{
aaa:111,
bbb:222
},
methods:{
dosometing:function(msg){
console.log(msg)
}
}
})
//组件:
Vue.component('child',{
props:['aaa'],
template:'<input type='text'>',
childfun:function(){
this.change1(1111)
}
});
//调用子组件
<child :change="dosometing" :aaa='111' :bbb='222'></child>
4. 插槽
- 不同插槽可以有自己的name
- 父组件slot属性 对应着 子组件里的slot的name
<div id="app">
<tpl>
<!-- 父组件slot属性 对应着 子组件里的slot的name -->
<div>
<span>jajaja</span>
<button>0000</button>
</div>
<!--指定slot2插入在此-->
<button slot="slot2">aaa</button>
</tpl>
</div>
<template id="temp">
<div>
<slot></slot>
<br>
名字: <input type="text">
<br>
<slot name="slot2"></slot>
</div>
</template>
<script>
new Vue({
el: '#app',
data: {
},
components: {
'tpl': {
template: '#temp'
}
}
})
</script>
23. computed
- 计算属性将被混入到Vue 实例中。
- 所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。
- 计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算
- 计算属性中一个改变就动态改变计算computed结果
24. watch
- 一个对象,键是需要观察的表达式,值是对应回调函数
- 每次只能检测一个
watch{
//a变化 回调function
a: function(newVal, oldVal){ }
}
25. vuex
- vuex状态管理
- state访问状态对象
- mutations修改状态(只能在mutations改)
- getters计算过滤操作 (计算属性)
- actions异步修改状态(修改 -> mutations)
26. VUE双向数据绑定
- 实现mvvm的双向绑定,就必须要实现以下 :
- 实现一个数据监听器Observer,通过Object.defineProperty()来实现对属性的劫持,能够对数据对象的所有属性进行监听, 如有变动可拿到新值并通知订阅者
- 实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
- 实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函 数,从而更新视图
- mvvm入口函数,整合以上三者

27. REACT
1. react定义组件用什么方法
var Messagebox = React.createClass
<!-- 组件名称首字母必须大写 !-->
2. 什么是jsx
- 在js里面写html代码(要用browser的包去解析,script中type写type/babel)
- 好处:可以提高代码可读性,语义清晰,对react元素进行抽喜爱那个在js中写html语法
3. reactjs angular有什么区别
- angular,是完整的MVVM框架
- react就是veiw;
4. state和props有什么区别?
- state的值会改变,改变的话就会重新触发渲染,刷render props不会被改变的,是父子组件传值的
- state 将组件看成是一个状态机,一开始有一个初始状态,然后跟用户互动,导致状态变化.从而触发重新渲染 getInitialState初始值;
5. 组件之间如何传值?
- 父给子(props) 子给父(,父组件把方法传过去,事件回调 )
- 兄弟之间传值(引入插件,消息订阅)pusub 6\ref:取到真实dom
6. 双向绑定
- 引入react-with-addons.js实现数据双项数据绑定,在前面引入 mixins:[],
7. 什么叫做虚拟dom:
- 用JS对象表示DOM结构,当数据发生改变时.跟原来的dom树进行对比.通过在这个虚 拟DOM上实现了一个diff算法找出小变更,再把这些变更写入实际的DOM中。
8. 虚拟dom具体如何实现?
- 1>如何比较两个两棵DOM树 我们很少跨级别的修改DOM节点,通常是修改节点的属性、调整子节点的顺序、添加子节点等。因此,我们只需要对同级别节点进行比较,避免了diff算法的复杂性。
- 对同级别节点进行比较的常用方法是深度优先遍历// 深度优先遍历:也就深入的遍历,沿着每一个分支直到走到后,然后才返回来遍 历剩余的节点 function diff(oldTree, newTree) { //节点的遍历顺序 var index = 0; //在遍历过程中记录节点的差异 var patches = {}; //深度优先遍历两棵树 dfsWalk(oldTree, newTree, index, patches); return patches; }
- 2>如何记录节点之间的差异 由于我们对DOM树采取的是同级比较,因此节点之间的差异可以归结为4种类型: 修改节点属性, 用PROPS表示 修改节点文本内容, 用TEXT表示 替换原有节点, 用REPLACE表示 调整子节点,包括移动、删除等,用REORDER表示 而当旧节点的属性被修改时:{type:PROPS,props: newProps}在深度优先遍历的过程中,每个节点都有一个编号,如果对应的节点有变化,只 需要把相应变化的类别记录下来即可。
- 比如对上文图中的两颗虚拟DOM树,可以用如下数据结构记录它们之间的变化:
9. react组件
- 组件特点:可组合(Composeable)、可重用(Reusable)、可维护(Maintainable)
- 优点:提高代码复用率、降低测试难度、降低代码复杂度
- 函数式
- 无状态
const Welcome = () => {
return <h1>hello world</h1>
}
ReactDOM.render(
<Welcome></Welcome>,
document.getElementById('app')
)
- class定义一个组件
- 有状态
- 有生命周期
class Com extends React.Component{
render(){
return(
<h1>hello world</h1>
)
}
}
ReactDOM.render(
<Com></Com>,
document.getElementById('app')
)
//state
class InputTpl extends React.Component{
constructor(params){
super(params)
this.state = {
count:1
}
}
}
28. REACT父子组件传值
- 函数式只能接受参数+展示
- class可接收参数并修改
- props父传值不能改变,state可以实现交互
- 函数传参
const Com = (props) => {
return (
<div>
<span>{props.name}</span>//指向父元素传递内容
</div>
)
}
ReactDOM.render(
<Com name="1234567"></Com>,
document.getElementById('app')
)
- class传参
class Com extends React.Component{
render(){
return(
<h1>{this.props.name}</h1>//this指向实例化对象
)
}
}
ReactDOM.render(
<Com name="1234567"></Com>,
document.getElementById('app')
)
- 组件中slot
class Com extends React.Component{
render(){
return(
<h1>{this.props.name}</h1>
{this.props.children}
)
}
}
ReactDOM.render(
<Com name="1234567">
<p>1234</p>
</Com>,
document.getElementById('app')
)
29. REACT属性
1. state
- state是组件对象最重要的属性,值是对象(可以包含多个数据),用于改变组件内通状态的值(动态的)
- 初始化状态
class InputTpl extends React.Component{
constructor(params){
super(params)
this.state = {
count:1
}
}
}
- 读取某个状态值
this.state.count
- 更新状态->组件界面更新
- 组件更新使用setState
- 不可直接修改,深拷贝后赋值
add(value){
let todo = [...this.state.todo]
todo.push({
name:value,
isA:false,
id:new Date().getTime()
})
this.setState({
todo,
list:todo
})
}
- this
- 自定义函数内部无法拿到this,需要在构造函数中bind
constructor(params){
super(params)
this.change = this.change.bind(this)
}
2. refs
- 组件内的标签都可以定义ref属性来标识自己
- ref
<input type="text" ref={(input) => this.myInput = input}/>
- 得到对应的真实DOM元素
console.log(this.myInput.value)
- refs
<input type="text" ref="name"/>
- 得到对应的真实DOM元素
console.log(this.refs.name.value)
官方推荐方法一
3. props
- props用于组件通信进行传值
4. props VS state vs ref
- props,来自外部属性,是不可变的,是一个对象,而state可以根据与用户交互来改变
- props用于组件通信进行传值
- state来自内部状态,用于改变组件内容状态的值(动态的)
- ref用于表示组件内某个元素,用于得到对应的真实DOM元素
30. REACT双向数据绑定
- 使用event.target事件对象来更新react中的数据状态
- 给输入框添加onChange事件(js驼峰式)
<input type="text" onChange={this.handleChange} /> <p>{this.state.username}</p> handleChange = (event) => { this.setState({ username: event.target.value }) } // 初始化数据 this.state = { form: { invite: '', nickname: '', username: '', password: '' }, } // 给输入框绑定事件 <input type="text" onChange={this.handleChange.bind(this, 'invite')}/> <input type="text" onChange={this.handleChange.bind(this, 'nickname')}/> <input type="text" onChange={this.handleChange.bind(this, 'username')}/> <input type="text" onChange={this.handleChange.bind(this, 'password')}/> // 编写事件方法 handleChange = (key, event) => { let form = this.state.form for (let item in this.state.form) { if (item === key) { form[item] = event.target.value this.setState({form: form}) } } }
31. REACT生命周期
- initialization 组件初始化
- 获取数据
- constructor()
- componetWillMount 组件即将渲染
- render 组件渲染
- componetDidMoun 组件渲染完成
- componentWillReceiveProps(nextProps)
- props是否改变(父组件传值改变时)
- props引起的组件更新过程
- shouldComponentUpdate(nextProps, nextState) 组件是否更新
- componentWillUpdate(nextProps, nextState) 组建即将更新
- render 组件更新
- componentDidUpdate(prevProps, prevState) 组件更新完成
- componentWillUnmount 即将卸载

32. Redux
- store保存数据的地方
- Action本质上是 JavaScript普通对象
- tore收到Action以后,必须给出一个新的State
- reducer 就是一个纯函数,接收旧的 state和action,返回新的 state。

33. vNode
1. 虚拟DOM
- 虚拟DOM是放在JS和HTML中间的一个层。
- 它可以通过新旧DOM的对比,来获取对比之后的差异对象,然后有针对性的把差异部分真正地渲染到页面上
- 从而减少实际DOM操作,最终达到性能优化的目的
2. Diff算法
- 判断要更新的区域,对比哪部分需要更新.减少更新的次数
34. 对比REACT和VUE
- react和vue都是做组件化的,整体的功能都类似,但是他们的设计思路是有很多不同的
- react整体是函数式的思想,把组件设计成纯组件,状态和逻辑通过参数传入,所以在react中,是单向数据流,推崇结合immutable来实现数据不可变。
- 而vue的思想是响应式的,也就是基于是数据可变的,通过对每一个属性建立Watcher来监听,当属性变化的时候,响应式的更新对应的虚拟dom。
- 相同点
- 组件化开发
- 虚拟DOM提高程序的运行效率
- 都支持props进行父子组件间通信
- 都支持数据驱动视图,不直接操作DOM
- 不同
- 数据绑定
- VUE双向数据绑定
- REACT单向数据流
- 组件写法
- react jsx写法
- VUE推荐html,css,js写在一个文件,通过webpack+vue-loader处理
- state
- react中state不可变,使用setState更新
- vue中state对象不是必须的,一般用data属性
- 虚拟dom
- vue跟踪每一个组建的依赖关系,不需要重新渲染整个组件树
- react每当应用的状态被改变时,全部组件重新渲染,react中需要shouldComponentUpdate生命周期函数进行控制
- REACT严格上只针对MVC的view层,VUE是MVVM模型
- 数据绑定
35. MVC MVVM
1. Mvvm定义
- MVVM是Model-View-ViewModel的简写。
- 即模型-视图-视图模型
- 【模型】指的是后端传递的数据。
- 【视图】指的是所看到的页面。
- 【视图模型】mvvm模式的核心,它是连接view和model的桥梁。它有两个方向:一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM事件监听。这两个方向都实现的,我们称之为数据的双向绑定。
- 总结:在MVVM的框架下视图和模型是不能直接通信的。它们通ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。
- 并且MVVM中的View 和 ViewModel可以互相通信。
2. MVC的定义
- MVC概念
- MVC是Model-View-Controller的简写。
- 即模型-视图-控制器。
- M和V指的意思和MVVM中的M和V意思一样。C即Controller指的是页面业务逻辑。使用MVC的目的就是将M和V的代码分离。
- MVC优点:
- MVC使得模型类不加修改即可重复使用
- MVC可以使视图可重复使用的而无需修改。
- MVC单向通信
- ‘MVC是单向通信。也就是View跟Model,必须通过Controller来承上启下。MVC和MVVM的区别并不是VM完全取代了C,ViewModel存在目的在于抽离Controller中展示的业务逻辑,而不是替代Controller,其它视图操作业务等还是应该放在Controller中实现。
- 也就是说MVVM实现的是业务逻辑组件的重用。由于mvc出现的时间比较早,前端并不那么成熟,很多业务逻辑也是在后端实现,所以前端并没有真正意义上的MVC模式
3. MVVM MVC MVP区别
- MVVM:将“数据模型数据双向绑定”的思想作为核心,因此在View和Model之间没 有联系,通过ViewModel进行交互,而且Model和ViewModel之间的交互是双向的, 因此视图的数据的变化会同时修改数据源,而数据源数据的变化也会立即反应到 View上。
- MVC是比较直观的架构模式,用户操作->View(负责接收用户的输入操作)-> Controller(业务逻辑处理)->Model(数据持久化)->View(将结果反馈给 View)。
- MVP:MVP是把MVC中的Controller换成了Presenter(呈现),目的就是为了完全切断View跟Model之间的联系,由Presenter充当桥梁,做到View-Model之间通信的 完全隔离。
36. 前端性能优化
- 减少HTTP请求:比如css精灵,懒加载
- 懒加载:先把img的src指向一个小图片,图片真实的地址存储在img一个自定义的属性里
<img src="lazy-load.png" data-src="xxx" />等到此图片出现在视野范围内了,获取img元素,把data-src里的值赋给src
- 压缩图片和使用图片Spirit技
- 请减少对DOM的操作
- CDN加速(最近的节点上)(内容分发网络)(就是将一些常用的文件,比如jq类库放在速度更快的服务器上,比如百度的cdn,提高加载速度)
- require、vue框架
- 尽量使用css3动画(css3会开启GPU加速)requestAnimationFrame,加快动画速度,
- 尽可能重绘(通过设置style属性改变结点样式的话,每设置一次都会导致一次重排)
- 合理使用标签、选择器(减少)
- 控制Cookie大小和污染(设置合理的过期时间)
- 压缩css js文件
- 使用icon-font来替换一些图标,减少图片的数量
- 减少dom操作,减少重排和重绘
37. css优化,提高性能
- 首推的是合并css文件,如果页面加载10个css文件,每个文件1k,那么也要比只加载一个100k的css文件慢。
- 减少css嵌套,最好不要套三层以上。
- 不要在ID选择器前面进行嵌套,ID本来就是唯一的而且人家权值那么大,嵌套完全是浪费性能。
- 建立公共样式类,把相同样式提取出来作为公共类使用,比如我们常用的清除浮动等。
- 减少通配符*或者类似[hidden="true"]这类选择器的使用,挨个查找所有...这性能能好吗?当然重置样式这些必须 的东西是不能少的。
- 巧妙运用css的继承机制,如果父节点定义了,子节点就无需定义。
- 拆分出公共css文件,对于比较大的项目我们可以将大部分页面的公共结构的样式提取出来放到单独css文件里,这样一次下载后就放到缓存里,当然这种做法会增加请求,具体做法应以实际情况而定。
- 不用css表达式,表达式只是让你的代码显得更加炫酷,但是他对性能的浪费可能是超乎你的想象的。
- 少用css rest,可能你会觉得重置样式是规范,但是其实其中有很多的操作是不必要不友好的,有需求有兴趣的 朋友可以选择normolize.css
- cssSprite(雪碧图),合成所有icon图片,用宽高加上bacgroud-position的背景图方式显现出我们要的icon图,这是一种 十分实用的技巧,极大减少了http请求。
- 当然我们还需要一些善后工作,CSS压缩(这里提供一个在线压缩 YUI Compressor ,当然你会用其他工具来压缩是十 分好的),
- GZIP压缩,Gzip是一种流行的文件压缩算法,详细做法可以谷歌或者百度。
38. repaint(重绘)和 reflow(重排)
1. 概念
- Repaint就是在一个元素的外观被改变,但没有改变布局(宽高)的情况下发生,如改变visibility、outline、背景色等等。
- Reflow就是DOM的变化影响到了元素的几何属性(宽和高),浏览器会重新计算元素的几何属性,如:改变窗囗大小、改变文字大小、内容的改变、浏览器窗口变化,style属性的改变等等。
2. 简述重绘和重排的关系
- 重绘不会引起重排,但重排一定会引起重绘,一个元素的重排通常会带来一系列的反应,甚至触发整个文档的重排和重绘,性能代价是高昂的。
3. 什么情况下会触发重排?
- 页面渲染初始化时;(这个无法避免)
- 浏览器窗口改变尺寸;
- 元素尺寸改变时;
- 元素位置改变时;
- 元素内容改变时;
- 添加或删除可见的DOM 元素时。
4. 重排优化有如下五种方法
- 将多次改变样式属性的操作合并成一次操作,减少DOM访问。
- 如果要批量添加DOM,可以先让元素脱离文档流,操作完后再带入文档流,这样只会触发一次重排。(fragment元素的应用)
- 将需要多次重排的元素,position属性设为absolute或fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位。
- 由于display属性为none的元素不在渲染树中,对隐藏的元素操作不会引发其他元素的重排。如果要对一个元素进行复杂的操作时,可以先隐藏它,操作完成后再显示。这样只在隐藏和显示时触发两次重排。
- 在内存中多次操作节点,完成后再添加到文档中去。例如要异步获取表格数据,渲染到页面。可以先取得数据后在内存中构建整个表格的html片段,再一次性添加到文档中去,而不是循环添加每一行
39. 预解释:
- var和function关键字的在预解释的时候操作还是不一样的
- var -> 在预解释的时候只是提前的声明了这个变量,只有当代码执行的时候才会完成赋值操作
- function -> 在预解释的时候会提前的把声明加定义都完成了(在代码执行的时候遇到定义的代码直接的跳过)
- 预解释只发生在当前的作用域下
- 例如:开始只对window下的进行预解释,只有函数执行的时候才会对函数中的进行预解释;
[重要]刚开始只对window下的进行预解释,fn函数中目前存储的都是字符串,所以var total没啥实际的意义,所以不进行预解释 -> "预解释是发生在当前作用域下的"
40. svn和git
1. svn和git的区别:
- Git是分布式的,SVN是集中式的,好处是跟其他同事不会有太多的冲突,自己写的代码放在自己电脑上,一段时间后再提交、合并,可离线提交,
- SVN在Commit前,我们都建议是先Update一下,跟本地的代码编译没问题,并确保开发的功能正常后再提交。Git可能这种情况会少些
2. git命令
git help <command> # 显示command的help
git show # 显示某次提交的内容 git show $id
git co -- <file> # 抛弃工作区修改
git co . # 抛弃工作区修改
git add <file> # 将工作文件修改提交到本地暂存区
git add . # 将所有修改过的工作文件提交暂存区
git rm <file> # 从版本库中删除文件
git rm <file> --cached # 从版本库中删除文件,但不删除文件
git reset <file> # 从暂存区恢复到工作文件
git reset -- . # 从暂存区恢复到工作文件
git reset --hard # 恢复最近一次提交过的状态,即放弃上次提交后的所有本次修改
git ci --amend # 修改最后一次提交记录
git revert <$id> # 恢复某次提交的状态,恢复动作本身也创建次提交对象
git revert HEAD # 恢复最后一次提交的状态
41. NODE
- error-first
1. require把文件转化为模块;
- 加载系统模块,加载自定义模块,加载第三方模块.
- var fs - require('fs');加载系统模块,和第三方不用写路径,自定义要写路径
- 系统模块,第三方模块,自定义路径存放在node-module
2. 如何安装,
npm install 包名 当前路径下的node_module npm install -g 包名 安装在系统路径下的node_module
3. module.exports exports的区别
exports = module.exports = {};
- 也就是说module是模块本身,而exports是module的一个属性,它的默认值是一个空对象{} 而他两者指向同一个对象
- 因此在exports上暴露的方法和变量接口,另外模块使用require引入后,返回给调用的其实是 module.exports
- 要注意的问题是暴露属性/方法,使用exports是没有问题的原因是 exports和module.exports指向同一个对象(exports添加新属性,就是给 module.exports添加新属性),上面两行代码都是exports为一起指向的 那个对象添加属性,使用require后返回module.exports也会被更改。
- 当然,直接使用module.exports暴露属性/方法也是可以的。但是不可以直接给exports赋值,因为这样 exports就指向了和module.exports不同的内存require后报错,是因为require返回的是 module.exports,而此时module.exports仍指向了空对象;
- 因此暴露一个类,要使用module.exports: var obj = function(){};module.exports = obj; 如果用 exports的话出现问题
4. 反向代理:
- 以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络的服务器;
- 并将服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器
5. stub 是什么? 举个例子?
- stub是用来模拟组件/模块行为的东西,它在测试阶段为函数调用提供内部响应。
- 你可以用Stub去模拟一个方法,从而避免调用真实的方法,
- 使用Stub你还可以返回虚构的结果
6. 用node监听80端口:
- Node应用的前方再增加一层反向代理
http.creatSever(function(req,res){}
).listen(80)
exress部署,反向代理ngix解决80端口的问题 自动翻译成3000端口
7. 什么是事件循环
- Node采用的是单线程的处理机制(所有的I/O请求都采用非阻塞的工作方式),至少从Node.js开发者的角度是这样的。
- 而在底层,Node.js借助libuv来作为抽象封装层,从而屏蔽不同操作系统的差异,Node可以借助livuv来来实现多线程。下图表示了Node和libuv的关系。
8. 使用NPM有哪些好处?
- 通过NPM,你可以安装和管理项目的依赖,并且能够指明依赖项的具体版本号。 对于Node应用开发而言,你可以通过package.json文件来管理项目信息,配置脚本, 以及指明项目依赖的具体版本。
9. 什么是node?
- Node.js是一套用来编写高性能网络服务器的JavaScript工具包
- 实际上它是对GoogleV8引擎(应用于Google Chrome浏览器)进行了封装。V8引擎执行Javascript的速度非常快,性能非常好。
- Node.js是单线程的。它通过事件轮询(event loop)来实现并行操作
10. node核心内置类库(事件,流,文件,网络等)
- 为什么要用node?
- 几个特点:简单强大,轻量可扩展.
- 简单体现在node使用的是javascript,json来进行编码,人人都会;
- 强大体现在非阻塞IO,可以适应分块传输数据,较慢的网络环境,尤其擅长高并发访问;
- 轻量体现在node本身既是代码,又是服务器,前后端使用统一语言;可扩展体现在可以轻松应对多实例,多服务器架构,同时有海量的第三方应用组件.
- node的构架是什么样子的?
- 主要分为三层,应用app >> V8及node内置架构 >> 操作系统. - V8是node运行的环境,可以理解为node虚拟机.node内置架构又可分为三层: 核心模块(javascript实现) >> c++绑定 >> libuv + CAes + http.
- node有哪些核心模块?
- EventEmitter, Stream, FS, Net和全局对象
- node全局对象
- process, console, Buffer和exports
- process有哪些常用方法?
- process.stdin
- process.stdout
- process.stderr
- process.on
- process.env
- process.argv
- process.arch
- rocess.platform
- process.exit
- console有哪些常用方法?
- console.log/console.info,
- console.error/console.warning,
- console.time/console.timeEnd,
- console.trace, console.table
- node有哪些定时功能?
- setTimeout/clearTimeout,
- setInterval/clearInterval,
- setImmediate/clearImmediate, process.nextTick
- node中的事件循环是什么样子的?
- event loop其实就是一个事件队列,先加入先执行,执行完一次队列,再次循环遍历看有没有新事件加入队列.但是请务必注意,这一个事件队列的循环,一次只执行一个事件,然后下一次循环再执行一个事件.
- 这是由于javascript的单线程机制导致的,如果一次循环多个事件,就可能会阻塞其它代码的执行.异步执行的叫IO events, setImmediate是在当前队列立即执行,setTimout/setInterval是把执行定时到到后面的队列,process.nextTick是在当前执行完,下次遍历前执行
- 所以总体顺序是: IO events >> setImmediate >> setTimeout/setInterval(注册事件) >> process.nextTick.
- node中的Buffer如何应用?
- Buffer是用来处理二进制数据的,比如图片,mp3,数据库文件等.Buffer支持各种编码解码,二进制字符串互转.
11. EventEmitter
- 什么是EventEmitter?
- EventEmitter是node中一个实现观察者模式的类,主要功能是监听和发射消息,用于处理多模块交互问题.
- 如何实现一个EventEmitter?
- 主要分三步:定义一个子类,调用构造函数,继承EventEmitter
- EventEmitter有哪些典型应用?
- 模块间传递消息
- 回调函数内外传递消息
- 处理流数据,因为流是在EventEmitter基础上实现的.
- 观察者模式发射触发机制相关应用
- 怎么捕获EventEmitter的错误事件?
- 监听error事件即可.如果有多个EventEmitter,也可以用domain来统一处理错误事件.
- EventEmitter中的newListenser事件有什么用处?
- newListener可以用来做事件机制的反射,特殊应用,事件管理等.当任何on事件添加到EventEmitter时,就会触发newListener事件,基于这种模式,我们可以做很多自定义处理.
12. Stream
- 什么是Stream?
- 参考答案: stream是基于事件EventEmitter的数据管理模式.由各种不同的抽象接口组成,主要包括可写,可读,可读写,可转换等几种类型.
- Stream有什么好处?
- 参考答案: 非阻塞式数据处理提升效率,片断处理节省内存,管道处理方便可扩展等.
- Stream有哪些典型应用?
- 参考答案: 文件,网络,数据转换,音频视频等.
- 怎么捕获Stream的错误事件?
- 参考答案: 监听error事件,方法同EventEmitter.
- 有哪些常用Stream,分别什么时候使用?
- 参考答案: Readable为可被读流,在作为输入数据源时使用;Writable为可被写流,在作为输出源时使用;Duplex为可读写流,它作为输出源接受被写入,同时又作为输入源被后面的流读出.Transform机制和Duplex一样,都是双向流,区别时Transfrom只需要实现一个函数_transfrom(chunk, encoding, callback);而Duplex需要分别实现_read(size)函数和_write(chunk, encoding, callback)函数.
- 实现一个Writable Stream?
- 参考答案: 三步走:1)构造函数call Writable 2) 继承Writable 3)
13. 实现_write(chunk, encoding, callback)函数
- process.stdin.pipe(new MyWritable());
- stdin作为输入源,MyWritable作为输出源
14. 文件系统
- 内置的fs模块架构是什么样子的?
- 参考答案: fs模块主要由下面几部分组成:
- POSIX文件Wrapper,对应于操作系统的原生文件操作
- 文件流 fs.createReadStream和fs.createWriteStream
- 同步文件读写,fs.readFileSync和fs.writeFileSync
- 异步文件读写, fs.readFile和fs.writeFile
- 读写一个文件有多少种方法?
- 参考答案: 总体来说有四种: 1) POSIX式低层读写 2) 流式读写 3) 同步文件读写 4) 异步文件读写
- 怎么读取json配置文件?
- 参考答案: 主要有两种方式,第一种是利用node内置的require('data.json')机制,直接得到js对象; 第二种是读入文件入内容,然后用JSON.parse(content)转换成js对象.二者的区别是require机制情况下,如果多个模块都加载了同一个json文件,那么其中一个改变了js对象,其它跟着改变,这是由node模块的缓存机制造成的,只有一个js模块对象; 第二种方式则可以随意改变加载后的js变量,而且各模块互不影响,因为他们都是独立的,是多个js对象.
- fs.watch和fs.watchFile有什么区别,怎么应用?
- 参考答案: 二者主要用来监听文件变动.fs.watch利用操作系统原生机制来监听,可能不适用网络文件系统; fs.watchFile则是定期检查文件状态变更,适用于网络文件系统,但是相比fs.watch有些慢,因为不是实时机制.
15. 网络
- node的网络模块架构是什么样子的?
- 参考答案: node全面支持各种网络服务器和客户端,包括tcp, http/https, tcp, udp, dns, tls/ssl等.
- node是怎样支持https,tls的?
- 参考答案: 主要实现以下几个步骤即可: 1) openssl生成公钥私钥 2) 服务器或客户端使用https替代http 3) 服务器或客户端加载公钥私钥证书
- 实现一个简单的http服务器?
16. child-process
- 为什么需要child-process?
- 参考答案: node是异步非阻塞的,这对高并发非常有效.可是我们还有其它一些常用需求,比如和操作系统shell命令交互,调用可执行文件,创建子进程进行阻塞式访问或高CPU计算等,child-process就是为满足这些需求而生的.child-process顾名思义,就是把node阻塞的工作交给子进程去做.
- exec,execFile,spawn和fork都是做什么用的?
- 参考答案: exec可以用操作系统原生的方式执行各种命令,如管道 cat ab.txt | grep hello; execFile是执行一个文件; spawn是流式和操作系统进行交互; fork是两个node程序(javascript)之间时行交互.
- 实现一个简单的命令行交互程序?
-
参考答案: 那就用spawn吧. 代码演示 var cp = require('child_process');
var child = cp.spawn('echo', ['你好', "钩子"]); // 执行命令 child.stdout.pipe(process.stdout); // child.stdout是输入流,process.stdout是输出流 // 这句的意思是将子进程的输出作为当前程序的输入流,然后重定向到当前程序的标准输出,即控制台
- 两个node程序之间怎样交互?
-
参考答案: 用fork嘛,上面讲过了.原理是子程序用process.on, process.send,父程序里用child.on,child.send进行交互.
fork-parent.js var cp = require('child_process'); var child = cp.fork('./fork-child.js'); child.on('message', function(msg){ console.log('老爸从儿子接受到数据:', msg); }); child.send('我是你爸爸,送关怀来了!');fork-child.js process.on('message', function(msg){ console.log("儿子从老爸接收到的数据:", msg); process.send("我不要关怀,我要银民币!"); });
- 怎样让一个js文件变得像linux命令一样可执行?
- 参考答案: 1) 在myCommand.js文件头部加入 #!/usr/bin/env node 2) chmod命令把js文件改为可执行即可 3) 进入文件目录,命令行输入myComand就是相当于node myComand.js了
- child-process和process的stdin,stdout,stderror是一样的吗?
- 参考答案: 概念都是一样的,输入,输出,错误,都是流.区别是在父程序眼里,子程序的stdout是输入流,stdin是输出流.
17. node高级话题(异步,部署,性能调优,异常调试等)
- node中的异步和同步怎么理解
- 参考答案: node是单线程的,异步是通过一次次的循环事件队列来实现的.同步则是说阻塞式的IO,这在高并发环境会是一个很大的性能问题,所以同步一般只在基础框架的启动时使用,用来加载配置文件,初始化程序什么的.
- 有哪些方法可以进行异步流程的控制?
- 参考答案: 1) 多层嵌套回调 2) 为每一个回调写单独的函数,函数里边再回调 3) 用第三方框架比方async, q, promise等
- 怎样绑定node程序到80端口?
- 参考答案: 多种方式 1) sudo 2) apache/nginx代理 3) 用操作系统的firewall iptables进行端口重定向
- 有哪些方法可以让node程序遇到错误后自动重启?
- 参考答案: 1) runit 2) forever 3) nohup npm start &
- 怎样充分利用多个CPU?
- 参考答案: 一个CPU运行一个node实例
- 怎样调节node执行单元的内存大小?
- 参考答案: 用--max-old-space-size 和 --max-new-space-size 来设置 v8 使用内存的上限
- 程序总是崩溃,怎样找出问题在哪里?
- 参考答案: 1) node --prof 查看哪些函数调用次数多 2) memwatch和heapdump获得内存快照进行对比,查找内存溢出
- 有哪些常用方法可以防止程序崩溃?
- 参考答案: 1) try-catch-finally 2) EventEmitter/Stream error事件处理 3) domain统一控制 4) jshint静态检查 5) jasmine/mocha进行单元测试
- 怎样调试node程序?
- 参考答案: node --debug app.js 和node-inspector
18. 常用知名第三方类库(Async, Express等)
- async都有哪些常用方法,分别是怎么用?
-
参考答案: async是一个js类库,它的目的是解决js中异常流程难以控制的问题.async不仅适用在node.js里,浏览器中也可以使用.
- async.parallel并行执行完多个函数后,调用结束函数
async.parallel([ function(){ ... }, function(){ ... } ], callback); - async.series串行执行完多个函数后,调用结束函数
async.series([ function(){ ... }, function(){ ... } ]); - async.waterfall依次执行多个函数,后一个函数以前面函数的结果作为输入参数
async.waterfall([ function(callback) { callback(null, 'one', 'two'); }, function(arg1, arg2, callback) { // arg1 now equals 'one' and arg2 now equals 'two' callback(null, 'three'); }, function(arg1, callback) { // arg1 now equals 'three' callback(null, 'done'); } ], function (err, result) { // result now equals 'done' }); - async.map异步执行多个数组,返回结果数组
async.map(['file1','file2','file3'], fs.stat, function(err, results){ // results is now an array of stats for each file }); - async.filter异步过滤多个数组,返回结果数组
async.filter(['file1','file2','file3'], fs.exists, function(results){ // results now equals an array of the existing files });
- async.parallel并行执行完多个函数后,调用结束函数
- express项目的目录大致是什么样子的
- 参考答案: app.js, package.json, bin/www, public, routes, views.
- express常用函数
- 参考答案: express.Router路由组件,app.get路由定向,app.configure配置,app.set设定参数,app.use使用中间件
- express中如何获取路由的参数
- 参考答案: /users/:name使用req.params.name来获取; req.body.username则是获得表单传入参数username; express路由支持常用通配符 ?, +, *, and ()
- express response有哪些常用方法
- 参考答案: res.download() 弹出文件下载 res.end() 结束response res.json() 返回json res.jsonp() 返回jsonp res.redirect() 重定向请求 res.render() 渲染模板 res.send() 返回多种形式数据 res.sendFile 返回文件 res.sendStatus() 返回状态
19. 其它相关后端常用技术(MongoDB, Redis, Apache, Nginx等)
- mongodb有哪些常用优化措施
- 参考答案: 类似传统数据库,索引和分区.
- mongoose是什么?有支持哪些特性?
- 参考答案: mongoose是mongodb的文档映射模型.主要由Schema, Model和Instance三个方面组成.Schema就是定义数据类型,Model就是把Schema和js类绑定到一起,Instance就是一个对象实例.常见mongoose操作有,save, update, find. findOne, findById, static方法等.
- redis支持哪些功能
- 参考答案: set/get, mset/hset/hmset/hmget/hgetall/hkeys, sadd/smembers, publish/subscribe, expire
- redis最简单的应用
var redis = require("redis"),
client = redis.createClient();
client.set("foo_rand000000000000", "some fantastic value");
client.get("foo_rand000000000000", function (err, reply) {
console.log(reply.toString());
});
client.end();
- apache,nginx有什么区别?
- 参考答案: 二者都是代理服务器,功能类似.apache应用简单,相当广泛.nginx在分布式,静态转发方面比较有优势.
41. http有没有设置缓存?
- http中具有缓存功能的是浏览器缓存,以及缓存代理服务器。
- http缓存:明确的要知道GET请求可以被缓存,POST不能被缓存,所以要想在客户端做HTTP的缓存一定要注意使用GET请求!
- 浏览器缓存是把页面信息保存到用户本地硬盘里,页面缓存状态是由http header决定的
- 代理服务器缓存的是指:当Web请求抵达缓存时,如果本地有“已缓存的”副本,就可以从本地存储设备而不是从原始服务器中提取这个文档。
42. 强引用带来的问题
- 内存泄漏
- 缓存
43. 在浏览器地址栏里输入一个地址,按回车发生了什么?
- 简单回答就是解析域名,建⽴立连接,三次握⼿手,发送请求,服务器器接到请求, 返回资源
- 浏览器会发送一个get请求,该请求会被转发到DNS服务器,由DNS服务器解析域名,然后再转发到相应的IP地址对应的服务器。
- 在服务器端由Apache这样的Web Server来接收请求,并进行相应的处理,然后响应结果给客户端浏览器。
- 浏览器接收响应的结果,并进行相应的语法检查,如果有错误,可能会提示错误,如果没有错误,就进行渲染。
- 渲染的时候先生成DOM树,然后根据CSS和JS规则生成渲染树(渲染树中的结构往往比DOM树要少,因为有些DOM树中有些元素如果隐藏的话,不会出现在渲染树中),最后再渲染出来
44. 浏览器是怎么把html文档解析成DOM结构的
- 渲染引擎会解析HTML文档并把标签转换成内容树中的DOM节点。
- 它会解析style元素和外部文件中的样式数据。
- 样式数据和HTML中的显示控制将共同用来创建另一棵树——渲染树。然后再布局,webkit叫渲染树/Geko叫帧树
45. nodejs怎么用req,res收发包,怎么接收怎么发出的
- node提供了http这个核心模块(不用安装哦,直接require就可以了),用于创建http server服务,使用下面代码,轻松在本机的3000端口创建一个http服务器
- 我们首先用http.createServer函数创建了一个服务器对象,然后调用了response.writeHead方法:该方法的第一个参数表示HTTP的响应状态(200)表示一切正常;第二个参数是“Content-Type”,表示我响应给客户端的内容类型。然再后我们调用了response.write方法,写入我们需要传递给客户端的内容。最后一步我们调用了response.end,表示此次请求已处理完成。
- listen(port)此函数有两个参数,第一个参数表示我们需要监听的端口,第二个参数是回调函数(其实是listening事件),当监听开启后立刻触发。
var http=require("http");
http.createServer(function(req,res){
res.writeHead(200,{
"content-type":"text/plain"
});
res.write("hello world");
res.end();
}).listen(3000);
$~ node http_demo.js
- 下列代码是通过直接创建一个http.Server对象,然后为其添加request事件监听,其实也就说createServer方法其实本质上也是为http.Server对象添加了一个request事件监听,这似乎更好理解了,那让我们看看http的重要属性
- createServer方法中的参数函数中的两个参数req和res则是分别代表了请求对象和响应对象。其中req是http.IncomingMessage的实例,res是http.ServerResponse的实例。
- http.IncomingMessage是HTTP请求的信息,是后端开发者最关注的内容,一般由http.Server的request事件发送,并作为第一个参数传递,包含三个事件
- data:当请求体数据到来时,该事件被触发,该事件提供一个参数chunk,表示接受的数据,如果该事件没有被监听,则请求体会被抛弃,该事件可能会被调用多次(这与nodejs是异步的有关系)
- end:当请求体数据传输完毕时,该事件会被触发,此后不会再有数据
- close:用户当前请求结束时,该事件被触发,不同于end,如果用户强制终止了传输,也是用close
var http=require("http");
var server=new http.Server();
server.on("request",function(req,res){
res.writeHead(200,{
"content-type":"text/plain"
});
res.write("hello nodejs");
res.end();
});
server.listen(3000);
- Request 对象- request 对象表示 HTTP请求,包含了请求查询字符串,参数,内容,HTTP 头部等属性。常见属性有:
req.app:当callback为外部文件时,用req.app访问express的实例
req.baseUrl:获取路由当前安装的URL路径
req.body / req.cookies:获得「请求主体」/ Cookies
req.fresh / req.stale:判断请求是否还「新鲜」
req.hostname / req.ip:获取主机名和IP地址
req.originalUrl:获取原始请求URL
req.params:获取路由的parameters
req.path:获取请求路径
req.protocol:获取协议类型
req.query:获取URL的查询参数串
req.route:获取当前匹配的路由
req.subdomains:获取子域名
req.accpets():检查请求的Accept头的请求类型
req.acceptsCharsets / req.acceptsEncodings / req.acceptsLanguages
req.get():获取指定的HTTP请求头
req.is():判断请求头Content-Type的MIME类型
- Response 对象- response 对象表示 HTTP响应,即在接收到请求时向客户端发送的 HTTP 响应数据。常见属性有:
res.app:同req.app一样
res.append():追加指定HTTP头
res.set()在res.append()后将重置之前设置的头
res.cookie(name,value [,option]):设置Cookie
opition: domain / expires / httpOnly / maxAge / path / secure / signed
res.clearCookie():清除Cookie
res.download():传送指定路径的文件
res.get():返回指定的HTTP头
res.json():传送JSON响应
res.jsonp():传送JSONP响应
res.location():只设置响应的Location HTTP头,不设置状态码或者close response
res.redirect():设置响应的Location HTTP头,并且设置状态码302
res.send():传送HTTP响应
res.sendFile(path [,options] [,fn]):传送指定路径的文件 -会自动根据文件extension设定Content-Type
res.set():设置HTTP头,传入object可以一次设置多个头
res.status():设置HTTP状态码
res.type():设置Content-Type的MIME类型
46. 什么叫前后端分离
- 一般认为,后端是跟数据库跟服务器打交道的,前端是跟浏览器打交道的。
- 核心思想是前端html页面通过ajax调用后端的api接口并使用json数据进行交互。
- 前端只负责展现样式,后端只负责数据;
- 实现前后端分离有两种方式:
- 框架
- node.js写中间层;让控制器层也让前端写,降低冲突
47. 模块化和组件区别:
- 都是解决代码重用,组件是单独的,没有关联,模块化是有关联的。
48. 移动端,点透 tap事件
1. 原因
- zepto的tap事件是通过兼听绑定在document上的touch事件来完成tap事件的模拟的,并且tap事件是冒泡到document上触发的!!!
- 而在冒泡到document之前,用户手的接触屏幕(touchstart)和离开屏幕(touchend)是会触发click事件的,因为click事件有延迟触发(这就是为什么移动端不用click而用tap的原因)(大概是300ms,为了实现safari的双击事件的设计)
- 所以在执行完tap事件之后,弹出来的选择组件马上就隐藏了,此时click事件还在延迟的300ms之中,当300ms到来的时候,click到的其实不是完成而是隐藏之后的下方的元素,如果正下方的元素绑定的有click事件此时便会触发
-
touchstart->touchend->click。亦即click的触发是有延迟的,这个时间大概在300ms左右。
.on('touchstart',function(){ e.preventDefault(); }) -
引入fastclick.js,因为fastclick源码不依赖其他库所以你可以在原生的js前直接加上
-
监听touchend事件来替代tap,或者touchstart,并阻止默认行为
$("#close").on("touchend",function(e){ $("#alertBox").hide(); e.preventDefault(); }); -
延迟一定的时间(300ms+)来处理事件
-
使用CSS3的pointer-events : true 和 pointer-events : none交替使用对下层元素设置,阻止触发click事件。
49. rem\em
- EM是相对于其父元素来设置字体大小的
- Rem是相对于根元素
- px是固定单位,其实Px也不是绝对固定的,也算是相对的,比如在普通屏幕和视网膜屏上,1px就不一样
1. rem的原理:
(1)本质其实就是等比缩放
(2)clientWidth/UI图宽度 这个是缩放比
(3)dom快高*clientWidth/UI图宽度 这个就是dom的实际宽高
- 可以发现,如果子元素设置rem单位的属性,通过更改html元素的字体大小,就可以让子元素实际大小发生变化
2. px、em、rem区别以及优缺点
-
px特点:
- IE无法调整那些使用px作为单位的字体大小;
- 国外的大部分网站能够调整的原因在于其使用了em或rem作为字体单位;
- Firefox能够调整px和em,rem,但是96%以上的中国网民使用IE浏览器(或内核)。
- px像素(Pixel)。相对长度单位。像素px是相对于显示器屏幕分辨率而言的。(引自CSS2.0手册)
-
em特点:
- em的值并不是固定的;
- em会继承父级元素的字体大小。
- em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。(引自CSS2.0手册) 3.rem特点
- rem是CSS3新增的一个相对单位(root em,根em),这个单位引起了广泛关注。
- 这个单位与em有什么区别呢?
- 区别在于使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。
- 这个单位可谓集相对大小和绝对大小的优点于一身,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。
- 目前,除了IE8及更早版本外,所有浏览器均已支持rem。对于不支持它的浏览器,应对方法也很简单,就是多写一个绝对单位的声明。这些浏览器会忽略用rem设定的字体大小。
50. input右侧输入
<input style="text-align:right" /><input type="text" dir="rtl" />
51. 你对ES6的个人看法?
- 各大主流浏览器现在已经支持大部分新特性了,后端的Node.js更是可以直接使用ES6的绝大多数语法。
52. 你是如何避免回调地狱的?
- 模块化 把回调函数分割成独立的函数
- 使用控制流的库,比如async
- generators结合Promise
- async/await
53. 本地存储(cookie session local)
1. cookie和session区别
1、存储大小:cookie——4k,session——5M
2、存储位置:cookie——客户端,session——服务端
3、cookie——跟着前端请求发送到后台,session——不会跟着前端请求发送到后台
4、用户验证这种场合一般会用 session,记录用户名用cookie
5、session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是说,如果浏览器禁用了 cookie ,同时
session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 session_id)
2. sessionStorage和localStorage区别(5M)
1、数据有效期不同:sessionStorage——当前浏览器窗口关闭前有效。
localStorage——始终有效,窗口或浏览器关闭也一直保存
cookie——只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
2、作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;
localStorage在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。
sessionStorage.name/sessionStorage.getItem('age');remove掉,sessionStorage.removeItem('age');
localStorage.setItem('age',30);localStorage.clear();才能删掉
cookie在浏览器和服务器间来回传递。而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
3. session cookie local区别:
1\cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。
2\存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
3\数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
4\作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。
4. Session实现原理
1、创建Session的时候,服务器将生成一个唯一的sessionid然后用它生成一个关闭浏览器就会失效的cookie。
2、然后再将一个与这个sessionid关联的数据项加入散列表。
例如这样一段代码:Session["UserName"]=23;
假设sessionid为123那么散列表中会追加一行
sessionid username
123 23
3、当浏览器端提交到服务器时,会通过sessionid=123去散列表中寻找属于该用户的Session信息。
5. cookie,session一般存什么?
Cookie用于保存客户浏览器请求服务器页面的请求信息,程序员也可以用它存放非敏感性的用户信息
Session用于保存每个用户的专用信息
6. cookie的参数
name 名称。
value 值。
expire 有效期。
path 服务器路径。(可选)
domain 域名。(可选)
secure 规定是否通过安全的 HTTPS 连接来传输 cookie。(可选)
HttpOnly 加以限制,使 Cookie 不能被 Javascript 脚本访问
7. Set-Cookie 字段的属性:(服务器管理状态使用到的字段,用于响应首部)
属性 | 说明
NAME=VALUE | 赋予 Cookie 的名称和其值(必须项)
expires=DATE | Cookie 的有效期(若不明确指定则默认为浏览器关闭前为止)
path=PATH | 将服务器上的文件目录作为 Cookie 的适用对象(若不指定则默认为文档所在的目录)
domain=域名 | 作为 Cookie 适用对象的域名(若不指定则默认为创建 Cookie 的服务器的域名)
Secure | 告诉浏览器只有在HTTPS连接时才发送cookie
HttpOnly | 加以限制,使 Cookie 不能被 Javascript 脚本访问;用来防止跨站脚本攻击
8. 利用 Cookie 管理 Session
Session 管理及 Cookie 状态管理
步骤 1:客户端把用户 ID 和密码等登录信息放入报文的实体部分,通常是以 POST 方法把请求发送给服务器。
步骤 2:服务器会发放用以识别用户的 Session ID。通过验证从客户端发送过来的登录信息进行身份验证,然后把用户的认证状态与 Session ID 绑定后记录在服务器端。向客户端返回响应时,会在首部字段 Set-Cookie 内写入 Session ID。
步骤 3:客户端接收到从服务器端发来的 Session ID 后,会将其作为 Cookie 保存在本地。下次向服务器发送请求时,浏览器会自动发送 Cookie,所以 Session ID 也随之发送到服务器。服务器端可通过验证接收到的 Session ID 识别用户和其认证状态。
54. 图片预加载和懒加载
- 图片预加载
for(){
var img=new Image();
img.onload=function(){
计数 loadSuccess()
}
}
//img.src=ghjg
//注意顺序问题(ie6下不好使)
- 懒加载
- 先把img的src指向一个小图片,图片真实的地址存储在img一个自定义的属性 里,
<img src="lazy-load.png" data-src="xxx" />,等到此图片出现在视野范围内了,获取img元素,把data-src里的值赋给src。
55. 渐进增强 优雅降级
- 渐进增强:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高 级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
- 优雅降级(平稳退化):一开始就构建完整的功能,然后再针对低版本浏览器进 行兼容。
56. 常用设计模式
- 单例模式:单例模式的定义是产生一个类的唯一实例 判断这个对象是否存在,如果存在,就使用之前创建的。不存在就创建新的。
- 工厂: 简单工厂模式是由一个方法来决定到底要创建哪个类的实例, 而这些实例经常都 拥有相同的接口. 这种模式主要用在所实例化的类型在编译期并不能确定, 而是 在执行期决定的情况。
- 观察者模式: 观察者模式( 又叫发布者-订阅者模式 )应该是最常用的模式之一
57. http与前端优化的关系(还有其他前端的优化⽅方案)
- 减少HTTP请求,使用CSS精灵和懒加载
58. cookie可以被禁⽌止吗
- Cookies记录你的用户ID、密码、浏览过的网页、停留的时间等信息。
- 我们为什么要阻止它呢?一方面是出于安全因素,如果用户储存了这些信息,就会在本地文件夹生成相应的文件,有可能被有些盗号木马程序盗取这些信息;另一方面,如果你浏览了大量的网站,储存了过多的这些信息,有可能使你的IE浏览速度变慢。所以有时候我们需要阻止Cookie
59. 模块化开发(怎么理理解,⽤用到哪些模块化开发的⽅方案)
- 就是把一个相对独立的功能,单独形成一个文件,可输入指定依赖、输出指定的函数,供外界调用,其它都在内部隐藏实现细节。这样即可方便不同的项目重复使用,也不会对项目造成额外的影响。
- 前端使用模块化载发主要的作用是:
- 异步加载 js,避免浏览器假死
- 管理模块间依赖关系,便于模块的维护
- 有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。
- 但要使用模��的前提,是必然要形成可遵循的开发规范,使得开发者和使用者都有据可寻,否则你有你的写法,我有我的写法,大家没办法统一,也就不能很好的互用了。
- 目前通用的规范是,服务器端使用 CommonJS 规范,客户端使用 AMD/CMD 规范。
60. AMD
- AMD 即 Asynchronous Module Definition 的简称,表示“异步模块定义”的意思
- 由于在浏览器端,模块使用同步方式加载可能出现假死,那么我们采用异步加载的方式来实现模块加载,这就诞生了 AMD 的规范。
- AMD 采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖所加载模块的语句,都被定义在一个回调函数中,等到模块加载完毕后,回调函数才会执行。
- AMD 也采用 require() 来加载模块,语法结构为:
  require([module], callback);
- module 是数组参数,表示所加载模块的名称;callback是回调函数参数,所有模块加载完毕后执行该回调函数。如:
  require(["jquery"], function($){
   $("#box").text("test");
  });
61. CMD
- CMD 即 Common Module Definition 的简称,表示“通用模块定义”的意思。
- CMD 规范明确了模块的基本书写格式和基本交互规则,该规范是在国内发展出来的,由玉伯在推广 SeaJS 过程中规范产出的。 - SeaJS 实现了 CMD 规范。SeaJS 要解决的问题和 RequireJS一样,只不过在模块定义方式和模块加载(运行、解析)时机上有所不同。
62. AMD 与 CMD 的区别
- AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
- CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
- 二者主要区别如下:
-
对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。
-
CMD 推崇依赖就近,AMD 推崇依赖前置。
-
AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。当然还有一些其它细节上的区别,具体看规范的定义就好。
-
63. 请解释浏览器器是如何根据CSS选择器器选择对应元素的
- 浏览器解析css选择器的规则是从右向左的,这样会提高查找选择器所对应的元素的效率。
.mod-nav h3 span {
font-size: 16px;
}
- 它的读取顺序应该是:先找到所有的span,沿着span的父元素查找h3,中途找到了符合匹配规则的节点就加入结果集;如果直到根元素html都没有匹配,则不再遍历这条路径,从下一个span开始重复这个过程(如果有多个最右节点为span的话)。
- 在某条CSS规则下(比如.mod-nav h3 span),会形成一条符合规则的索引树,树由上至下的节点是规则中从右向左的一个个选择符匹配的节点。
64. 影响CSS渲染效率的因素有哪些?
1、尽量避免 *{}
- 有了*通配符。* 会遍历所有的标签;
- 建议的解决方法:
(1)不要去使用生僻的标签,因为这些标签在不同浏览器中解释出来的效果不一样;所以要尽可能的去使用那些常用的标签;
(2)不要使用*;而是把常用到的这些标签进行处理
2、滤镜的一些东西不要去用
- IE的一些滤镜在Firefox中不支持,往往写一些效果是还是使用CSS hack;滤镜是一个非常耗资源的的东西;特别是一些羽化、阴影和一个前透明的效果;
- 建议的解决方法:
(1)能不使用就不要使用,一方面兼容问题;很多效果只能在IE中使用;
(2)就本例而言,如果非要这样的效果,建议用背景图片作背景一个非常好的例子,就是在512大地震时,很多网站一夜之间全部变成了灰色,他们只用一行CSS代码:body{filter:gray;}但,你会看到这些网站非常的慢,打开后CPU也会飙升,不夸张地说,如果电脑配置差,干死也不为过。
3、一个页面上少用绝对定位
- 绝对定位(position:absolute)是网页布局中很常用到的,特别是做一些浮动效果时,也会让页面看起来非常的酷。但网页中如果使用过多的绝对定位,会让你的网页变得非常的慢,这一点Firefox表现比IE还要差。
- 建议的解决办法:
(1)尽可能少用,这个少用的值是多少,也没有一个非常好的值来说明;还要看绝对定位这个标签里边的内容多少;在这里只能说,这样写会有性能问题,少用。
(2)如果能用变通的实现同样的效果,就用变通的方法。
4、background背景图片平铺
- 有些网页的背景或页面中某块的背景通常要用到图片的平铺,平铺后就会有平铺次数的问题,如果是单次还好,如果是多次,就废了。
- 建议的方法:
(1)色彩少的图片要做成gif图片
(2)平铺的图片尽可能大一些,如果是色彩少的GIF图片,图片大写,实际大小也不会大多少;上面的两个例子就很好的证明,第一个图片非常少,第二个图较大些,但速度非常不一样
5、让属性尽可能多的去继承
- 尽可能让一些属性子可以继承父,而不是覆盖父;
6、CSS的路径别太深
- #zishu#info#tool#sidebar h2{font-size:12px;}
7、能简写一些就简写
- 这个对渲染速度没有影响;只是少几个字符
8、别放空的class或没有的class在HTML代码中
9、float的应用
- 这个东西如果使用不当,百分百有性能问题,而且还非常大,但实在不知道怎么样弄一个例子来,这里只能建议如果不是很明float是怎么工作的,还是少用为妙。
10、合理的布局
- 为什么这么说呢?合理的布局,可以改变CSS的写法以及渲染过程。
65. 伪数组的特性?
- 长相很像数组,但是将他的原型_proto_打开看看,它没有数组的splice,concat,pop等方法
- 特点:
- 具有length属性
- 按索引方式存储数组
- 不具有数组的方法
66. 常见的伪数组有哪些?
- function里的arguments
- 通过
getElementByTagName()document.childNodes()getElementByName()document.children()等方式获取的NodeList集合的对象都属于伪数组 - 特殊写法的对象
eg: var obj={}
obj[0]="一" obj[1]="二" obj[2]="三"
67. 可以直接调用数组方法么
//Arry.prototype.slice.call(伪数组)
//eg:
Array.prototype.slice.call(arguments) 将arguments转化为真正数组
68. 如何将一个div水平垂直居中?6种
- div绝对定位水平垂直居中【margin:auto实现绝对定位元素的居中】兼容性:,IE7及之前版本不支持
div{
width: 200px;
height: 200px;
background: green;
position:absolute;
left:0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
}
- div绝对定位水平垂直居中【margin 负间距】 这或许是当前最流行的使用方法。
div{
width:200px;
height: 200px;
background:green;
position: absolute;
left:50%;
top:50%;
margin-left:-100px;
margin-top:-100px;
}
- div绝对定位水平垂直居中【Transforms 变形】兼容性:IE8不支持
div{
width: 200px;
height: 200px;
background: green;
position:absolute;
left:50%; /* 定位父级的50% */
top:50%;
transform: translate(-50%,-50%); /*自己的50% */
}
- 弹性盒模型-css不定宽高水平垂直居中
.box{
height:600px;/去掉高度,只能垂直居中。
display:flex;
justify-content:center;
align-items:center;
/* aa只要三句话就可以实现不定宽高水平垂直居中。 */
}
.box>div{
background: green;
width: 200px;
height: 200px;
}
- 将父盒子设置为table-cell元素,可以使用text-align:center和vertical-align:middle实现水平、垂直居中。比较完美的解决方案是利用三层结构模拟父子结构
<p class="outerBox tableCell">
</p><p class="ok">
</p><p class="innerBox">tableCell</p>
<p></p>
<p></p>
/*
table-cell实现居中
将父盒子设置为table-cell元素,设置
text-align:center,vertical-align: middle;
子盒子设置为inline-block元素
*/
.tableCell{
display: table;
}
.tableCell .ok{
display: table-cell;
text-align: center;
vertical-align: middle;
}
.tableCell .innerBox{
display: inline-block;
}
- 对子盒子实现绝对定位,利用calc计算位置
<p class="outerBox calc">
</p><p class="innerBox">calc</p>
<p></p>
/*绝对定位,clac计算位置*/
.calc{
position: relative;
}
.calc .innerBox{
position: absolute;
left:-webkit-calc((500px - 200px)/2);
top:-webkit-calc((120px - 50px)/2);
left:-moz-calc((500px - 200px)/2);
top:-moz-calc((120px - 50px)/2);
left:calc((500px - 200px)/2);
top:calc((120px - 50px)/2);
}
#div1 {
position: absolute;
left: 50px;
width: calc(100% - 100px);
border: 1px solid black;
background-color: yellow;
padding: 5px;
text-align: center;
}
68. 封装,继承,多态
-
所谓封装:
- 也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
- 封装是面向对象的特征之一,是对象和类概念的主要特性。
- 简单的说,一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。
- 在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。
-
所谓继承:
- 是指可以让某个类型的对象获得另一个类型的对象的属性的方法。
- 它支持按级分类的概念。
- 继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
- 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
- 继承概念的实现方式有二类:实现继承与接口继承。
- 实现继承是指直接使用基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
-
所谓多态:
- 就是指一个类实例的相同方法在不同情形有不同表现形式。
- 多态机制使具有不同内部结构的对象可以共享相同的外部接口。
- 这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。
69. dependencies和devDependencies的区别?
- devDependencies:开发环境使用,用于本地环境开发时候。
- dependencies:生产环境使用,用户发布环境
- devDependencies是只会在开发环境下依赖的模块,生产环境不会被打入包内。通过NODE_ENV=developement或NODE_ENV=production指定开发还是生产环境。
- dependencies依赖的包不仅开发环境能使用,生产环境也能使用。其实这句话是重点,按照这个观念很容易决定安装模块时是使用--save还是--save-dev。