JS中的块级作用域
1.with 2.try.. catch 3.let, const
变量提升和函数提升
- 包括变量和函数在内的所有声明都会在任何代码被执行前首先
被处理 - 函数声明比变量声明优先提升\
- 只有声明会被提升,变量的赋值或者其他运行逻辑会留在本地
什么叫闭包?
闭包是能够访问另一个函数作用域中变量的函数,创建闭包:将函数作为函数的返回值;将函数作为参数传递。
使用场景:实现对象的数据私有化;代替一些全局变量;
什么叫原型、原型链?
每个函数都有一个prototype属性,这个属性就是原型。原型链就是对象之间的继承链,一个对象通过的prototype指向一个父对象,父对象的prototype又指向另一个对象,最终指向Object对象。这一个关系链就是原型链
如何优化网站性能?
1. Http请求
合并js,css文件,雪碧图减少http请求的数量,压缩文件,减少请求的大小;
资源文件按需加载;
合理使用缓存,sessionStorage,cookie,文件加上MD5戳;
数据懒加载,比如PC端可以分页,移动端可以上拉加载
2.HTML方面
合理化使用元素,减少不必要的元素
避免使用iframe,ifram很消耗资源
3.JS方面
js文件放在页面底部,因为渲染网页的顺序是由上至下,如果放在顶部会等待js加载,有可能会出现空白
避免在html中直接写js,而是独立一个js文件
减少DOM访问和修改。合并多次操作,修改元素的样式会导致重绘,添加删除DOM,修改DOM位置导致重排 (重新排列位置);
删除不需要的脚本,合理的设计结构,实现模块化增强复用性;
4.CSS方面
样式表放在开头,迅速渲染页面样式;
减少行内样式吗,单独css文件可以缓存
合理编写css,减少css层级
添加一些必要的loading提示
5.server方面
使用CDN
合理的数据查询语句,适当的缓存
HTTP状态码
1XX 信息状态码
- 100 Continue: 继续发送请求
2XX 成功状态码
200 OK: 请求成功
201 Created: 创建新资源请求已实现
202 Acceped 服务器已接收请求,但是还未处理
204 No Content 没有响应内容,跨域option就是204
3XX 重定向状态码
300 Muiltiple Choices 请求有多个资源
301 Moved Permanently 请求的URL已移除
304 Not Mofdified 资源未被修改
4XX 客户端错误状态码
400 Bad Request 发送了一个错误请求(参数确实或错误)
401 Unauthorized 未授权
403 Forbidden 请求被拒绝
404 Not Found 找不到资源
5XX 服务端错误状态码
500 internal Server Error 服务器发生错误
502 Bad Gateway 代理出错
Vue相关
a. vue和Angularjs的区别
AngularJS采用双向数据绑定,vue默认使用单向数据绑定
vue中也有双向数据绑定,angularjs是基于脏检查,而vue是基于getter和setter
AngularJS属于MVVM框架,而vue相当于view层
vue更容易上手,API完整有完整的生命周期;
b. vue和Jquery的区别
vue采用数据驱动,尽量避免DOM操作,Jquery使用核心是DOM操作 ;
Jquery本质上是封装了DOM操作的函数库,vue属于一个框架;
c. vue的原理
- 采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调
Object.defineProperty(person, 'name', {
set: function(newVal) {
temp['name'] = newVal;
console.log('为person设置新的姓名:' + newVal);
},
get: function() {
var _name = temp['name'] || '默认姓名';
console.log('获取person的姓名:' + _name);
return _name;
}
});// 当person复制或取值的时候回调用set,get,
d. vue生命周期
一共分为8个阶段:创建前/后,载入前/后,更新前/后,销毁前/后
created阶段数据已经准备好了,但是html还没有渲染完成
mounted html已经渲染完成
destory 解除事件监听和dom绑定,但是dom结构还在
e. vuex
- vuex作用:管理Vue组件的状态(当出现多个视图组件依赖同一个状态,来自不同视图的行为需要变更同一个状态。)
排序方式
- 冒泡排序
相邻元素两两比较
function bubbleSort(arr) {
var length = arr.length;
for(let i = 0; i < length; i++) {
for(let j = 0; j < length - 1; j++) {
if(arr[j + 1] < arr[j]) {
let tem = arr[j+ 1];
a[j+ 1] = a[j];
a[j] = tem;
}
}
}
return arr;
}
- 选择排序
选择最小的
function selectSort(arr) {
let length = arr.length;
let minIndex, temp;
for(let i = 0; i < length; i++) {
minIndex = i;
for(let j = i + 1; j < length; j++) {
if(arr[j] < arr[minIndex]) {
minIndex = j;
}
}
if(i != minIndex) {
temp = arr[minIndex];
arr[minIndex] = arr[i];
arr[i] = temp;
}
}
return arr;
}
3.插入排序
类似打牌,每选择一个元素就找适合它的位置
function insertSort(arr) {
let length = arr.length;
let newArr = [];
for(let i = 1; i < length; i++) {
let key = arr[i];
let j = i - 1;
while(arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
return arr;
}
清除浮动的方式
overflow:hidden
容器元素最后添加元素,使用clear:both
伪元素
.clearfix:after{
content:"";//设置内容为空
height:0;//高度为0
line-height:0;//行高为0
display:block;//将文本转为块级元素
visibility:hidden;//将元素隐藏
clear:both//清除浮动
}
.clearfix{
zoom:1;为了兼容IE
}
水平垂直居中的方式
- margin: auto; 必须知道高度
.item {
postion: absoulate;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
- margin 高宽一半; 必须知道高度和宽度
.item {
postion: absoulate;
top: 50%;
left: 50%;
height: 100px;
width: 100px;
margin-top: -50px;
margin-left: -50px;
}
- transform; 不需要知道高度和宽度
.item {
postion: absoulate;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
- flex; 兼容性问题
.item {
dispaly: flex;
justify-content:center;
align-items: center;
}
实现深度克隆
function deepClone(obj) {
var toString = Object.prototype.toString;
// null, undefined, {}, function
if(!obj || typeof obj !== 'object') {
return obj;
}
if(toString.call(obj) === '[object Date]') {
return new Date(obj.getTime());
}
if(toString.call(obj) === '[object RegExp]') {
var flags = [];
if(obj.global) {
flags.push('g');
}
if(obj.multiline) {
flags.push('m');
}
if(obj.ignoreCase) {
flags.push('i');
}
return new RegExp(obj.source, flags.join(''))
}
let temp = obj instanceof Array ? [] : {};
for(var i in obj) {
if(obj.hasOwnProperty(i)) {
temp[i] = deepClone(obj[i]);
}
}
return temp;
}// 优化, 可以尾部调用递归
数组去重
- 利用对象属性唯一
function unique(array) {
let obj = {};
let newArray = [];
for(let i = 0; i < array.length; i++) {
if(!obj[array[i]]) {
obj[array[i]] = true;
newArray.push(array[i]);
}
}
return newArray;
}
2.两层循环 splice
function unique2(arr) {
let length = arr.length;
for(var i = 0; i < length; i++) {
for(var j = i + 1; j < length; j++) {
if(arr[j] == arr[i]) {
arr.splice(j, 1);
length --;
j --;
}
}
}
return arr;
}
3.ES6 set 去重
function unique3(arr) {
return Array.from(new Set(arr));
// return (...new Set(arr)) 扩展运算符
}
内存泄露
- 不再用到的内存,没有及时释放就叫内存泄露
- 垃圾回收机制:标记清除(最常用),和引用计数
- 常见内存泄露情况:
- 意外的全局变量,比如未定义,直接变量提升(采用严格模式防止)
- 闭包过多,闭包中用到的变量不会被回收
- dom清空或删除时,事件未清除导致的内存泄漏,及时移除事件
- 循环引用(引用计数永远是1)
事件流阶段
捕获阶段、目标阶段、冒泡阶段
Promise
- Promise 好处
将异步接口以同步的流程表现出来 - Promise对象的两个特点:
- 对象的状态不受外界影响;
- 一旦状态改变,就
- Promise 的三个状态
pending,resolved,rejected
Promise状态改变只有两种可能:从pending到fulfilled,从pending到rejected - Promise 内部的错误不会影响到 Promise 外部的代码(Promise会吃掉错误)
- Promise.resolve 将现有对象转化为Promise对象
Promise.resolve('foo') // 等价于 new Promise(resolve => resolve('foo'))
Promise.resolve方法的参数分成四种情况。
(1) 参数是一个Promise对象
原封不动返回
(2) 参数是一个 thenable对象(有then属性方法)
会将对象转化为Promise对象,然后立即执行其中的then方法
let thenable = {
then: function(resolve, reject) {
resolve(222);
}
};
Promise.resolve(thenable)
.then(res => console.log(res));
(3) 参数没有then方法, 或者根本不是对象
会返回一个新的Promise对象,状态为resolved
const p = Promise.then('hello');
p.then(function(s) {
console.log(s);
}); // hello
(4) 不带任何参数时,直接返回一个resolved状态的Promise对象
因此可以使用Promise.then() 创建一个新的Promise对象
- 使用Promise封装ajax
let mineAjax = function(url, method, data) { let promise = new Promise(function(resolve, reject) { const handler = function() { if(this.readyState === 4 && this.status === 200) { resolve(this.responce); } else { reject(new Error(this.statusText)); } }; const client = new XMLHttpRequest();// new 一个 ajax对象 data = getQueryString(data);// 对象数据转'&'连接的字符串 if(method == 'post') { client.open(method, url); client.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');// post 要设置header if(data) { client.send(data); } else { client.send(); } } if(method == 'get') { url += data; client.open(method, url); client.send(); } client.onreadystatechange = handler; client.responseType = 'json'; }); return promise; } function getQueryString(query) { let result = []; for(let key in query) { result.push(`${key}=${query[key]}`); } if(result.length > 0) { return result.join('&'); } } mineAjax('testurl", 'post', {data: test}).then(function(res){ console.log(res); }, function(error) { console.log(error); });
- Promise.prototype.then
- then 是写在 promise原型上
- then方法返回的是一个新的Promise实例
- 链式写法,前一个then的返回值下一个then的参数
js写原生ajx
- new XMLHttpRequest;
- 使用open方法,设置请求方法(get/post)、url
- 设置发送数据,数据为(a=1&b=2)的格式
- 如果是post请求设置请求头 setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
- send, 如果有数据 send(data),没有send();
- 服务器响应事件,onreadystatechange,当readyState == 4 && status == 200的时候表示响应成功
- ajax readState
0 - (未初始化)还没有调用send()方法
1 - (载入)已调用send()方法,正在发送请求
2 - (载入完成)send()方法执行完成,已经接收到全部响应内容
3 - (交互)正在解析响应内容
4 - (完成)响应内容解析完成,可以在客户端调用了
设计模式
- 单体模式
概念: 单体是一个用来划分命名空间,并将一批属性和方法组织在一起的对象
应用: 将代码封装在一个对象中,只暴露一个入口
好处:- 可以用来划分命名空间,减少全局变量的数量;
- 使用单例模式可以使代码组织更为一致,便于阅读和维护
- 可以被实例化,且实例化一次
var Singleton = {
attribute: true,
method1: function() {},
method2: function() {}
};
- 工厂模式
概念: 用于创建对象实例,封装实例创建过程,只关心创建结果
应用:处理一些共享相同属性的组件,或者对象,比如提示框;AngularJS factory
缺点: 没有解决对象的识别问题,都是object
function animal(opts) {
var obj = new Object();
obj.name = opts.name;
obj.color = opts.color;
obj.getInfo = funtion() {
return name;
}
return obj;
}
var cat = animal({name: '波斯猫', color: '白色'});
- 构造函数模式
概念: 用于创建特定类型的对象
优点: 解决了工厂模式无法识别类型的问题(instanceof Animal == true)
缺点: 有些公共方法,需要重复定义
function Animal(name, color) {
this.name = name;
this.color = color;
this.getName = function() {
return this.name;
}
}
var cat = new Animal('猫', '白色');
cat.getInfo();
- 原型模式
概念: 将属性都放在原型上;
优点: 所有所有实例可以共享他的属性和方法
缺点: 共享属性和方法,导致一个实例更改属性或方法就会影响其他实例
function Animal() {}
Animal.name = '猫';
Animal.color = '白色';
var cart1 = new Animal();
var cart2 = new Animal();
- 混合模式(构造函数模式和原型模式结合)
概念:构造函数负责属性,原型模式负责公共方法或属性function Animal(name, color) { this.name = name; this.color = color; } Animal.prototype.getInfo = function() { return this.name + ' ' + this.color; }
- 创建对象的方式:
- 对象字面量和Object构造函数
- 工厂模式:抽象了对象的实现过程,但是无法知道对象的类型
- 构造函数模式:new 操作符,可以判断实例类型(即instanof可以判断),缺点无法使用公共属性
- 原型模式:将公共属性添加到prototype中;
- 组合使用构造函数模式和原型模式:构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。使用最广泛的一种方法
- 动态原型模式: 把初始化原型的过程也封装在构造函数中;
- 发布订阅者模式
概念: 一对多的映射关系,让多个观察者对象同时监听某一个主题对象,当该对象改变时,依赖于它的对象都将得到通知;
优点:支持简单的广播通信,对象改变会自动通知订阅过的对象
发布者和订阅者的耦合性降低
缺点:创建订阅者需要消耗一定的时间和内存
跨域
为什么跨域:XHR对象只能访问同一个域中的资源,为了防止某些恶意行为,但是有时候需要跨域访问
- 图像Ping
- 一个网页可以从任何网页中加载图像
- 常用于跟踪用户点击页面或动态广告曝光次数(1px图片)
- JSONP (JSON with padding)
- JSONP由回调函数和数据组成
- 因为script 可以不受限的从其他域获取资源;
- 有安全问题,确定JSONP是否请求失败不容易;
- CORS (cors origin resource sharing)
- 代理 nginx转发
TCP 三次握手
TCP核心思想:既要保证数据可靠传输,又要提高传输的效率,三次握手刚好可以满足
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
第一次握手:客户端发送syn包到服务器;
第二次握手:服务器确认客户端的sync包,同时发送一个sync + ack包到客户端
第三次握手:客户端收到服务器发的包,向服务器发送确认包ACK完成三次握手
TCP和UDP的区别
TCP面向有链接,能正确处理丢包, UDP面向无连接,不管对方有没有收到
HTTP
HTTP是建立在TCP协议基础上的,http是一种短连接,是一种无状态的连接
从输入URL到页面加载发生了什么
1.输入URL,
- 浏览器根据URL查找是否有缓存,并且判断缓存是否过期,如果没过期则从缓存中读取,如果过期则需要重新读取
- DNS查找域名的IP地址
- 先从浏览器缓存中找,在从操作系统缓存中找,再从路由器缓存中找
- 没有缓存,则进行DNS递归查找
- 同服务器建立TCP连接,然后发起http请求
- 服务器收到请求并解析,将请求转发到服务程序;
- 服务程序读取请求并作出响应;
- 服务器通过TCP连接发送回浏览器;
- 浏览器接收响应,检查状态码,作出响应;
- 解析HTML文档,构建DOM树结构,下载图片、视频、css、js资源等,构建CSSOM树
10.根据DOM树和CSSOM树构建渲染树, 执行js脚本 - 最后显示HTML
浏览器缓存机制
浏览器缓存就是把一个已经请求过的web资源(html,图片,js等)拷贝一份副本存储在浏览器中;
- 浏览器缓存的控制
- 使用HTML Meta标签
- 使用和缓存有关的http报文
<meta http-equiv="Pragma" content="no-cache">
项目相关
- Angularjs和Vue你觉得区别在哪里?
- 从使用上看,Vue使用更为方便,有完整的api包括生命周期,文档也个更为齐全
- Angularjs指令和组件没有区分开,都是用directive,而Vue是完全分开的
- Vue性能更好,Angularjs 的双向绑定是基于脏检查的 ,当 watcher 越来越多时会变得越来越慢,因为作用域内的每一次变化,所有 watcher 都要重新计算。则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter;
a. 脏值检查: 就是不关心你如何以及何时改变的数据,只关心在特定的检查阶段(UI事件,ajax事件, timeout 延迟事件),数据是否改变。
b. angularjs賍值检查的实现:
每一个绑定到UI上的数据 都拥有一个对应的$watch对象,这个对象会被push到watch list中, $watch包括两个函数属性
watch = {
name: '', // 当前watch的对象
getNewValue: function($scope) {// 得到新值
return newValue;
},
listener: function(newValue, oldValue) {// 当数据发生改变时候需要执行的操作
...
}
};
c. 手动出发脏检查,$apply进入angular上下文,$digest触发脏检查
gulp和webpack的区别
两者不应该拿来比较,
gulp属于前端流程优化工具,它可以自动刷新页面、压缩技术,css,编译less,自动化
而webpack是模块化方案,是一个前端资源加载/打包工具,从官网的图片就可以看出Webpack 可以将多种静态资源 js、css、less 转换成一个静态文件,减少了页面的请求
this
- this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。
- this取值情况分为4种情况:
- 构造函数,如果函数作为构造函数(new),那么this指向new出来的对象
- 函数作为对象的一个属性,并且作为对象的一个属性被调用的时候,this指向该对象(隐式绑定);
- 函数使用call或apply调用的时候,this的值就去传入对象的值;(显示绑定)
- 全局并且调用普通函数,this指向window(nodejs中指向global)
- 箭头函数根据外层作用域(函数或者全局)决定this
作用域
- 作用域在函数定义的时候就已经确定,而不是函数调用时确定
- 作用域中变量的值是在执行过程中产生和确定的
- 自由变量跨作用域取值要去创建函数的作用域找
执行上下文
执行上下文指的是以下三种数据的准备情况:
- 变量(包括函数表达式)的变量声明,默认赋值为undefined
- this的赋值;
- 函数声明的赋值
通俗的讲就是把将要用到的所有变量都实现声明和赋值
函数每被调用一次,都会产生一个新的执行上下文环境
处于活动状态的执行上下文环境只有一个,执行不同上下文的过程,是一个压栈出栈的过程——执行上下文栈
常用正则
- 去除空格
- 所有空格
replace(/\s*/g, ''); - 去除两头空格
replace(/^\s|\s$/g, ''); - 去除左边空格
replace(/^\s*/g, '') - 去除右边空格
replace(/\s*$/g, '')
- 数字
- 整数 /^\d+$/;
- 数字 /^\d*.?\d+$/
圣杯布局和双飞翼布局
- 圣杯布局
<div class="container">
<div class="middle"><h4>中间弹性区</h4></div>
<div class="left"><h4>左边栏</h4></div>
<div class="right"><h4>右边栏</h4></div>
</div>
<style>
.container {
height: 200px;
overflow: hidden;
padding: 0 200px;
}
.middle {
width: 100%;
height: 200px;
background-color: deeppink;
float: left;
}
.left {
width: 200px;
height: 200px;
background-color: blue;
float: left;
margin-left:-100%;
position: relative;
left: -200px;
}
.right {
width: 200px;
height: 200px;
background-color: darkorchid;
float: left;
margin-left:-200px;
position: relative;
right: -200px;
}
</style>
- 双飞翼布局
<div class="container2">
<div class="middle2"><div><h4>中间弹性区</h4></div></div>
<div class="left2"><h4>左边栏</h4></div>
<div class="right2"><h4>右边栏</h4></div>
</div>
.container2 {
height: 200px;
overflow: hidden;
margin-top: 20px;
}
.left2 {
width: 200px;
height: 200px;
background-color: green;
float: left;
margin-left: -100%;
}
.right2 {
width: 200px;
height: 200px;
background-color: red;
float: left;
margin-left: -200px;
}
.middle2 {
width: 100%;
height: 200px;
float: left;
background-color: orange;
}
.co {
margin: 0 200px;
}
清除浮动
1、clear清除浮动(添加空div法)
在浮动元素下方添加空div,并给该元素写css样式: {clear:both;height:0;overflow:hidden;}
2、方法:给浮动元素父级设置高度
3、父元素overflow:hidden
overflow: hidden;
*zoom: 1;
- after伪类
.clear:after{content:' ';display:block;clear:both;height:0;overflow:hidden;visibility:hidden;}
.clear{zoom:1;}