- js和jquery的区别
1. jQuery 是一个快速、简洁的js库 简单的理解就是一个js文件 里面是对js的原生代码进行了封装
jq的优点:
1. 轻量级 ,也就是几十kb ,不会影响页面加载速度
2. 链式编程、隐式迭代(隐式遍历)
3. 基本兼容了现在主流的浏览器
4. 样式、动画支持 简化了dom操作
5. 支持插件扩展,第三方的插件比较丰富
6. 免费、开源
- 闭包的原理以及应用场景
1.闭包原理:根据js的词法作用域,函数在被定义的时候,作用域已经确定,如果在函数内找不到某变量就会去父级函数去查找,像这样子函数访问父函数的变量或属性并且子函数在外部被调用就会产生闭包
2.闭包的应用场景: 1. 函数防抖和节流 2. 封装私有变量
3. 闭包会导致内存再泄露
4. JavaScript回收机制,当一个内存空间没有变量指向的时候就会被回收。那么闭包清除的方式就是将不需要的函数名赋值为 null
5. null 和 undefined 的区别
1. null 表示没有对象,即此处不应该有值
- 作为函数的参数,表示该函数的参数不是对象。
- 作为对象原型链的终点。
2. undefined 表示“缺少值”,就是此处应该有一个值,但是还没有定义。
- 变量被声明了,但没有赋值时,就等于undefined。
- 调用函数时,应该提供的参数没有提供,该参数就等于undefined。
- 对象没有赋值的属性,该属性的值为undefined。
- 函数没有返回值时,默认返回undefined
- 函数防抖和节流
1. 防抖:当事件被触发,延迟N秒才执行,如果这N秒内再次被触发则重新计时
- 防抖的使用场景:比如用户在输入框中连续输入一串字符,可以通过防抖策略只在输入完成之后,才执行查询
有效减少请求次数,节约请求资源
2. 节流:减少一段时间内事件被触发的频率
- 节流的应用场景:鼠标连续不断地触发某事件(如点击),使用节流只在单位时间内只触发一次
- 手写函数防抖和节流
// 1. 函数防抖
function debounce (fn,delay) {
let timer = null
// ...args获取所有传入的数据
return function (...args) {
if(timer) clearTimeout(timer) // 如果已经存在就清除重新计算
timer =setTimeout(()=> {
// setTimeout 的this指向的window所有要保存函数中的this
// apply 第二个参数需要一个数组使用args正好
fn.apply(this,args)
},delay)
}
}
// 2. 函数节流
function throttle (fn, delay) {
let flag =true
return function ( ...args) {
if(!flag) return
setTimeout(() => {
fn.apply(this,args)
flag=true
},delay)
}
}
- 异步的解决方案
1. callback
2. promise
3. async await 终极解决方法
- js模块化的解决方案
1. CommonJs是起源于服务器端模块化开发的规范 (Node.js)
定义模块:一个单独的文件就是一个模块,每一个模块都是一个作用域(在模块内部定义的变量,无法 被其他模块读取,除非定义为global对象的属性)
模块输出:模块只有一个出口module.exports对象需要将模块希望输出的内容放在该对象中
加载模块:加载模块的时候使用require方法该方法读取一个文件并执行
存在的问题:加载模块和操作模块提供的变量和方法是同步的,即操作模块提供的变量和方法必须得等到加载模块完成后才可以执行。在服务器端,所有的模块(js文件)都放在硬盘中,因此模块的加载速度很快。但是在浏览器端,加载模块需要向服务器发送请求,会受到网络的影响。如果模块的加载需要等很长时间,浏览器就会处于“假死”状态。因此CommonJS只适用于服务器端,并不适用于浏览器端。
2. AMD (异步模块定义)它是一个在浏览器端模块化开发的规范
require.js 是遵循AMD规范
require.js 主要解决两个问题:
1. js文件之间的依赖关系:被依赖的文件需要早于依赖它的文件加载到浏览器
2. js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应的时间越长
3. CMD (通用模块定义)它也是一个在浏览器端模块化开发的规范
sea.js是遵循CMD规范的一个JavaScript文件和模块加载器
sea.js 推荐一个文件一个模块
4. AMD和CMD的异同
1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。
2. CMD 推崇依赖就近,AMD 推崇依赖前置。
3. AMD 的 API 一个当多个用,职责单一。CMD 中,每个API都简单纯粹。
5. RequireJS 和 sea.js 的区别
1. sea.js 只有在 require 的地方,才会真正执行模块。
2. RequireJS 会先运行所有的依赖,得到所有的结果后再执行回调。
6.ES6的 ES Moudle
ES6 模块化方案,一统浏览器和服务器。采用了完全静态化的方式进行模块加载。
7. ES Module与CommonJS的差异
1.语法 import/export require/module
2.CommonJS 模块输出的是一个值的拷贝(不会随原始值变化),ES6 模块输出的是值的引用(会随着原始值变化)。
3.CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
- 深拷贝和浅拷贝
1. 基本数据类型:就是指保存在栈内存中的简单数据段
2. 引用数据类型:指的是保存在堆内存中的对象,引用数据类型的值是一个指针这个指针保存在栈内存中并且指针指向存储在堆中的对象数据
//
深拷贝和浅拷贝是针对复杂数据类型来说的,浅拷贝只拷贝一层,深拷贝层层拷贝
3.深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后再复制,深拷贝的对象和原来的对象是隔离的互不影响
4.浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是应用数据类型时,复制的其实是引用,当引用的值改变时也会跟着改变
- 深拷贝和浅拷贝的方法
1. 深拷贝
// 1. 深拷贝的方法 JSON.parse/JSON.stringfy
// 该方法的不足之处就是:如果拷贝对象中包含正则表达式、函数、或者undefined等值,此方法就会出现问题
function deepClone(obj) {
let obj1=JSON.stringify(obj)
return JSON.parse(obj1)
}
// 2. 使用递归
function deepClone(newObj,obj) {
// 1. 遍历需要拷贝的数据
for(key in obj){
// 需要先判断数组,因为数组也是对象,否则无法解析数组
// 2. 需要判断遍历数据的每一项是什么类型的数据
const item = obj[key]
if(item instancof Array) {
// 3. 在newObj中
newObj[key]=deepClone([],obj[key])
} else if(item instanceof Object){
newObj[key]=deepClone({},obj[key])
} else {
newObj[key] = obj[key]
}
}
return newObj
}
//3. jq中 $.extend(true,[],object) // 无法拷贝对象中值为undefined的属性
// 三个参数是是深拷贝,两个参数浅拷贝
2. 浅拷贝
// 1. 使用 Array.concat()实现浅拷贝 (能实现类似效果的还有slice()和Array.from()等)
var arr=[1,2,3,4[5,6]]
const data= arr.concat(); //利用conact创建arr的副本
// 修改基本类型的数据,不会改变原数组
data[0]=8;
arr; // [1,2,3,4[5,6]]
// 改变数组中的引用数据类型,原数组也会跟着改变
data[4][1]=9
arr; //[1,2,3,4[9,6]]
// 2. Object.assign() 实现浅拷贝
const obj= {
x:1,
y: {
m:1
}
}
const obj1=Object.assign({},obj)
obj1.y.m=2; // 修改obj2.y.m,改变对象中的引用类型值
obj; // {x: 1, y: {m: 2}} 原对象也被改变
obj1; // {x: 1, y: {m: 2}}
- 原型和原型链
// 原型
1. 在javascript中,比如,每一个构造函数都有一个prototype属性,这个属性指向了构造函数的原型对象并且原型的属性和方法会被实例对象所共享
2. 比如,每一个实例对象都有一个__ proto __ 属性 该属性指向的是其构造函数的原型对象。原型对象中有一个constructor指向构造函数
// 原型链
1. 原型链是一种机制,指的是JavaScript每个对象都有一个内置的__proto__属性指向创建它的函数对象的原型对象,即prototype属性。原型对象也有__proto__属性。因此在不断的指向中,形成了原型链。
2. 原型链的存在,主要是为了实现对象的继承。
- 定高宽的盒子居中的方式
1.通过定位
- 父盒子相对定位 position:relative
- 子盒子绝对定位 position:absolute top:50% left:50% margin-top: -盒子高一半 margin-left:同
2.定位+transform tranlate
- 于上面的盒子相比,子盒子使用 transform: translate(-50%,-50%)
3.flex 布局
- 在父盒子中 dispaly:flex justify-content: center align-items: center
4.table-cell
- 在父盒子中使用 display:table-cell vertical-align:middle
- 在子盒子中使用 margin:auto
- 不定宽高的盒子实现居中
1. flex 布局
- 在父盒子中 dispaly:flex justify-content: center align-items: center
2. 利用定位以及使用tansform:tranlate
- 在父盒子的里面的 position:relative
- 在子盒子里面 position:absolute top:50% left:50% transform: translate(-50%,-50%)
- 盒子模型
1.盒子模型(w3c) box-sizing: content-box
width:contentWidth
heigth:contentHeight
2.IE怪异盒子模型 box-sizing:border-box
width:contentWidth+(左右)padding+(左右)border
height:contentHeight+(上下)padding+(上下)border
// 差异: 不同的点在于对于width和height的设定上是不同的
- h5的新增的标签
1. 内容标签: article section footer header aside
2. 表单: date email time
3. 媒体: video audio
4. 本地存储: localStorage sessionStorage
- 缓存的几种方式及区别
1. cookie 数据始终在同源的http请求中携带(即使不需要),cookie在服务器和浏览器来回传递
2. 而localstorage和sessionstorage不会主动将数据传递给服务器,会保存在本地
3. cookie 携带的数据大小不能超过4k,localstorage和sessionstorage可以5M或更大
4. localstroage是永久存储,而sessionstorage 一旦刷新页面就会消失
- ES6常见的数组方法
1. some // 找一个数据 找到即停止 一旦结束 return true结束
2. filter // 过滤数据 ,筛选符合要求的数据会将所有符合条件的都筛选出来 返回一个数组
3. every // 判断是否每一个都符合条件 返回一个bool值
4. reduce // 求和 //里面是一个添加处理函数
5. map // 数据映射 ,处理一种数据返回一个新数据 //处理函数
6. findIndex // 查找索引值
7. forEach // 遍历数组
- 事件捕获和事件冒泡
1. 事件冒泡 - 子元素的事件会影响父元素事件
2. 事件捕获 - 父元素的事件会影响子元素事件
3. btn.addEventListener('click',fun1,false);
- 第三参数是 false 是事件冒泡 true 是事件捕获
4. 阻止事件冒泡 e.stopPropagation()
5. 阻止默认事件 e.preventDefault()
- 继承(6种方式)
1. 原型链继承
- 原型链继承的基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。
2. 借用构造函数(函数复用无从谈起)
- 在子类型的构造函数中调用超类型构造函数。
- 可以向超类传递参数
- 解决了原型中包含引用类型值被所有实例共享的问题
3. 组合继承(原型链 + 借用构造函数)
-使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承,既通过在原型上定义方法来实现了函数复用,又保证了每个实例都有自己的属性。
4. 寄生组合式继承
- 所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法,
5. es6 extends 继承
- 组合继承以及es6继承的方法
class Father {
constructor(uname, age) {
this.uname = uname;
this.age = age;
}
qian() {
console.log('爸爸说赚他一个亿');
}
}
class Son extends Father {
constructor(uname, age, money) {
// super :是用来调用父构造函数--必须写在constructor中的最前面
super(uname, age);
this.money = money;
}
zQian() {
// super: 可以调用父类方法
super.qian(); //两个方法都会调用
console.log('儿子说先赚1万块');
}
}
var son = new Son('儿子', 4, 99);
son.zQian();
// 组合继承
// 1. 父构造函数
function Father(uname, age) {
// this 指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
Father.prototype.money = function () {
console.log(100000);
};
// 2 .子构造函数
function Son(uname, age, score) {
// this 指向子构造函数的对象实例
Father.call(this, uname, age);
this.score = score;
}
// Son.prototype = Father.prototype; 这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
Son.prototype = new Father();
// 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
Son.prototype.constructor = Son;
var son = new Son('刘德华', 18, 100);
son.money();
- 什么是Ajax
1. 最初页面的渲染是由后端路由来实现的但是后端渲染存在性能问题即:假设用户和服务器经常有提交表单这样的行为后端路由就会导致页面被频繁的刷新导致用户体验会非常的差。因此出现了Ajax技术,可以实现页面上的局部刷新,极大地提高了用户使用体验
他就是用户请求——等待——响应这种web交互模式。
2. ajax 请求的过程
- 1. 创建一个XML HttpRequest 对象
- 2. 创建一个新的http请求,并指定该http请求的方法,url,以及验证信息
- 3. 设置响应http请求状态变化的函数
- 4. 发送http请求
- 5. 获取异步调用返回的数据
- 6. 使用js和dom实现局部刷新
- 改变this的指向
1. 方式:call apply bind
2. 共同点:第一个参数都为改变this的指针。若第一个参数为null/undefined,this默认指向window
3. 区别
- call和apply 会自动执行 bind 需要手动调用
- call和bind有无数个参数,apply 只有两个参数 第二个参数是一个数组
- ES6的一些特性
1. var和let以及const的区别
- var 存在变量提升 也可以定义同名的变量 不具有块级作用域
- let 和 const 是块级作用域,也不能在同一作用域内重复声明同名变量
- const 和 let 的区别就是 const 定义的是常量,也就是说栈内存中的数据不能修改,如果是简单数据类型,则这个简答数据类型是不可以修改的,如果是引用数据类型,则栈内存中的存储的指针不可以修改,但是指针指向的堆内存的数据是可以修改的
2. 模版字符串 使用一对反引号包裹,中间可以嵌套变量,也可以换行
3. 对函数的扩展
-1. es6为函数提供了默认值,在定义函数的时候初始化这个值,以便在参数没有被传进来的时候使用
-2. 箭头函数
- 简化函数的书写方式
- 箭头函数和普通的匿名的区别
- 1. 箭头函数是不能被直接命名的,不过可以将它直接赋值给一个变量
- 2. 箭头函数是不能作为构造函数的,不能对箭头函数使用new关键字
- 3. 箭头函数是不存在prototype属性的
- 4. 箭头函数绑定词法作用域,是不能修改this指向的
-箭头函数的最大的特点就是
- 箭头函数的this是指向包含箭头函数的上下文,但是箭头函数本身也是不产生的上下文的
4. 对对象的扩展
-1. 属性和方法名的简写
-2. Object.keys()的方法,获取对象的所有属性名和方法名,返回一个数组
-3. Object.assign()该方法可以将多个原对象的属性和方法都和合并到目标对象上来
- 可以接受多个参数 第一个参数是目标对象,第二对象是源对象
5. for of 循环 是遍历所欲数据结构的统一方法,范围包括 set map 类数组 以及字符串等
6. import 和 export
- ES6中,js原生支持模块了,将js的代码分割成不同的功能的小模块进行模块化 使用export对外输出模块 ,使用import引入模块
7. 解构赋值
- ES6允许按照一定的模式,从数组和对象中提取值,对变量进行赋值
8. 扩展运算符 ...
- 将字符串转成数组
- 将集合转成数组
- 在函数中 用来代替argunments 参数
9. Set:类型类似于数组,但是成员的值都是唯一的,没有重复的值
Set本身是一个构造函数,用来生成Set数据结构
// 数组去重
1. 可以使用数组来初始化一个Set,并且Set构造器会确保不重复地使用这些值
let arr = [1, 2, 2, 3];
let set = new Set(arr);
// Array.from() 可以将一个类数组对象或者可遍历对象转换成一个真正的数组。
1. let newArr = Array.from(set);
2. newArr=[...set] // es6 的写法
console.log(newArr); // [1, 2, 3]
2. 利用对象的键名是不能重复的特性解决
let arr = [1, 2, 2, 3];
let obj ={}
arr.forEach(item => {
obj[item]=1
})
let newArr = Object.keys(obj).map(key => (key -0))
console.log(newArr)
3. 使用filter来过滤实现
let arr = [1, 2, 2, 3];
let newArr = arr.filter((e,i,arr) => {
return arr.findIndex(e) === i
})
10. Map数据结构
- js的对象本质上是键值对的集合,但是传统上只能用字符串当作键这给它的使用带来了很大的限制。
- ES6 提供了Map数据结构,它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值都可以当作键也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的Hash 结构实现。
11. symbol 数据类型 表示独一无二的值
- ES5 的对象属性名都是字符串,这容易造成属性名的冲突, 为了解决追加属性的名的时不冲突而引入symbol
12. promise
1. promise 是处理异步的一种方案
2. promise对象用于表示一个异步操作的最终结果成功或失败,以及结果值。可以为异步操作的成功和失败绑定处理函数,让异步可以像同步的方式一样返回值,但是立即返回的是一个能够代表未来可能出现结果的Promise对象
3. promise对象有三种状态
1. pending: 初始状态,既不是成功也不是失败
2. fulfilled:意味着操作成功
3. rejected:意味着操作失败
4. promise的使用和提供的静态方法
1.Promise.all() //所有的promise对象都成功的时候才会执行
2.Promise.race() // 一个成功或者失败都会立即触发返回对象的成功和失败
3.Promise.reject(reason) // 返回一个状态为失败的Promise对象
4.Promise.resolve(value) // 返回一个状态由value给定的Promise对象,
5. .then 得到异步任务正确的结果 .catch 获取异常信息
- 几种遍历的方法比较
1. for in 是遍历数组的索引 for of 是遍历数组的value值
2. for in 适合遍历对象 for of 适合遍历除了对象外的所有数据结构
- 给出一个数组随机排序
function RandomSort(arr){
arr.sort(function () {
return Math.random -0.5 //Math.random-0.5 可能大于0 也可能小于0达到随机的目的
})
}
- js的浮点数的精度问题
1. 计算机内部的信息都是二进制方式表示,也就是01组成的各种编码,但是由于某些浮点数没办法用二进制准确的表示出来就会导致一些精度问题
2.解决方法:
1. 如果对精度要求不高调用round()方法或者toFixed()方法保留指定的位数
2. 也可以将小数转为整数再做计算
3. 对精度要求比较高的可以是用bignumber类库
- 创建对象的方式
1. 使用对象字面量
// 缺点: 创建多个对象的时候,代码量很大
var Cat={}
Cat.name='yebi'
Cat.say=function () { alert('miaomiaomiao') }
2. 使用构造函数
// 可以通过constructor和instancof来创建识别对象的实例类型
// 多个实例对象的方法效果一样但是存储了很多次
function Person (name,age) {
this.name=name
this.age=age
this.eat=function () {
alert(`my name is ${this.name},i am ${this.age} old`)
}
}
var ldh = new Person('刘德华',65)
3. 使用工厂模式
// 1. 优点:可以批量生产类似的对象
// 2. 缺点:对象无法识别,所有的实例都指向一个原型,无法通过constructor来识别,里面的方法会被重复创建,浪费内存资源
function People(name) {
var obj = new Object()
obj.name=name
obj.sing=function () {
alert('i can singing')
}
return obj
}
var people1=People('zxy')
4. 原型模式
// 优点:方法是共享的了,所有的实例的say方法都指向同一个。可以动态的添加原型对象的方法和属性,并直接反映在对象实例上。
function Person () {}
Person.prototype.name='zgr'
Person.prototype.dance=function () {
alert('i am a dancer')
}
var person1=new Person()
- new 关键字 执行的过程
1. 在内存中开辟一个空间创建一个空对象
2. 执行构造函数赋值
3. this指向新创建的对象
4. 返回this给外部接受的变量
- this关键字
this 是一个关键字,是一个对象,产生于函数相关,this 与执行环境绑定 通俗的讲就是 谁调用的这个函数就指向谁
普通函数调用:指向window 比如setTimeout
构造函数调用:指向实例化对象
方法属性调用:指向调用者
- 浏览器兼容问题
1. 浏览器默认的margin和padding不同,解决方案:加一个全局的{margin:0,padding:0}来统一
2. IE下可以使用获取常规属性的方法来获取自定义属性,也可以使用getAttribute()来获取自定义属性,但是在FireFox下只能使用getAttribute()来获取自定义属性
3. chrome 中文界面下默认将小于12px的文本强制的按照12px显示,可以通过加入CSS属性
-webkit-text-size-adjust:none 来解决
- 网页从输入网址到渲染完成经历了那些过程
1. 输入网址
2. 发送到DNS服务器,获取域名对应的web服务器对应的ip地址
3. 于web服务器建立TCP连接(三次握手)
4. 浏览器向web服务器发送http请求
5. web服务器响应请求,并返回指定url的数据
6. tcp四次握手,释放连接
7. 浏览器下载web服务器返回的数据以及解析html源文件
8. 生成dom树,解析css和js 渲染页面,直至显示完成
- tcp/ip协议四层模型(链路层,网络层,传输层,应用层)
1. tcp/ip 协议族 包括 TCP,UDP,IP,FTP,HTTP等
2. tcp协议是规定双方是可以通信,通信的规则是http定义的
3. tcp连接(三次握手)
- 客户端向服务端发送建立连接请求。
- 服务端确认建立连接回应客户端,好的,我也要向你发送信息了
- 客户端收到消息,再次向服务端确认 好的
4. TCP 关闭过程
- 客户端向服务端说:我没有消息要给你发了,要关闭客户端到服务端的传输请求。
- 服务端说:好的,确认关闭。
- 服务端向客户端说:我没有消息要给你发了,要关闭服务端到客户端的传输请求。
- 客户端说:好的,确认关闭。
5. 为什么 TCP 的关闭过程需要四步
- 因为 TCP 连接是双向通信,需要双方的单方向确认进行关闭
- http请求消息组成
1. http请求消息组成包括: 1. 请求行 2. 请求头部 3. 空行 4. 请求体
- 1. 请求行的组成部分: 1.请求方式 2. URL 3. http协议版本 他们之间使用空格隔开
- http工作原理
http定义:超文本传输协议,它规定了客户端与服务器之间进行网页内容传输时,所必须遵守的传输格式
Content-Type字段的作用:服务器回应的时候,必须告诉客户端,数据是什么格式
1. HTTP/1.0 版的主要缺点是,每个TCP连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。
2. TCP连接的新建成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢(slow start)。所以,HTTP 1.0版本的性能比较差。随着网页加载的外部资源越来越多,这个问题就愈发突出了。
3. 为了解决这个问题,有些浏览器在请求时,用了一个非标准的Connection字段。 Connection: keep-alive
这个字段要求服务器不要关闭TCP连接,以便其他请求复用。服务器同样回应这个字段。Connection: keep-alive
4. 一个可以复用的TCP连接就建立了,直到客户端或服务器主动关闭连接。但是,这不是标准字段,不同实现的行为可能不一致,因此不是根本的解决办法。
5. HTTP/1.11.1 版的最大变化,就是引入了持久连接(persistent connection),即TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive。
6. 客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送Connection: close,明确要求服务器关闭TCP连接。
7. 1.1 版还引入了管道机制(pipelining),即在同一个TCP连接里面,客户端可以同时发送多个请求。这样就进一步改进了HTTP协议的效率。
8. 一个TCP连接现在可以传送多个回应,势必就要有一种机制,区分数据包是属于哪一个回应的。这就是Content-length字段的作用,声明本次回应的数据长度。Content-Length: 3495 上面代码告诉浏览器,本次回应的长度是3495个字节,后面的字节就属于下一个回应了。
9. 分块传输编码
10. 使用Content-Length字段的前提条件是,服务器发送回应之前,必须知道回应的数据长度。
对于一些很耗时的动态操作来说,这意味着,服务器要等到所有操作完成,才能发送数据,显然这样的效率不高。更好的处理方法是,产生一块数据,就发送一块,采用"流模式"(stream)取代"缓存模式"(buffer)。
因此,1.1版规定可以不使用Content-Length字段,而使用"分块传输编码"(chunked transfer encoding)。只要请求或回应的头信息有Transfer-Encoding字段,就表明回应将由数量未定的数据块组成。
Transfer-Encoding: chunked
11. 每个非空的数据块之前,会有一个16进制的数值,表示这个块的长度。最后是一个大小为0的块,就表示本次回应的数据发送完了
12. 1.1版还新增了许多动词方法:PUT、PATCH、HEAD、 OPTIONS、DELETE。
13. 另外,客户端请求的头信息新增了Host字段,用来指定服务器的域名。有了Host字段,就可以将请求发往同一台服务器上的不同网站,为虚拟主机的兴起打下了基础。
缺点: 虽然1.1版允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为"队头堵塞"(Head-of-line blocking)。
14. 为了避免这个问题,只有两种方法:一是减少请求数,二是同时多开持久连接。这导致了很多的网页优化技巧,比如合并脚本和样式表、将图片嵌入CSS代码、域名分片(domain sharding)等等。如果HTTP协议设计得更好一些,这些额外的工作是可以避免的。
HTTP/2
1. HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。
2. 多工
- HTTP/2 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了"队头堵塞"。
3. 因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。
4. HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数
5. 数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STREAM帧),取消这个数据流。1.1版取消数据流的唯一方法,就是关闭TCP连接。这就是说,HTTP/2 可以取消某一次请求,同时保证TCP连接还打开着,可以被其他请求使用。
6. 客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。
7. 头信息压缩 HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie和User Agent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。
8. HTTP/2 对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息使用gzip或compress压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。
9. 服务器推送
-HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。
-常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。
HttP协议规定了Web客户端如何从Web服务器请求Web页面,以及服务器如何吧web页面传送给客户端
常见的http状体码:
1. 200 // 客户端请求成功
2. 400 // 客户端请求,有语法错误
3. 401 // 请求未经授权
4. 404 // 请求资源不存在
5. 500 // 服务器发生不可预测的错误
6. 503 // 服务器当前不能处理客户端的请求,一段时间之后可能恢复
7. 403 // 服务器资源禁止访问
8. 301 // 重定向
http1.0 和 http2.0的区别
1. HTTP/2采用二进制格式而非文本格式
2. HTTP/2是完全多路复用的,而非有序并阻塞的——只需一个连接即可实现并行
3. 使用报头压缩,HTTP/2降低了开销
4. HTTP/2让服务器可以将响应主动“推送”到客户端缓存中
HTTP和HTTPS的区别
1. 是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
2. http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3. http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4. http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
- 那些行为会导致内存泄露
那些行为会导致内存泄露
1. 意外的全局变量引起的内存泄露
2. 闭包引起的内存泄露
3. 没有清理的DOM元素引用
4. 被遗忘的定时器或者回调
- 常见的web安全以及防护原理
1. sql 注入原理
- 通过把sql命令插入到web表单递交或输入域名获取请求的查询字符串中,最终到达欺骗服务器执行恶意sql命令
- 防范
- 1. 不要信任用户的输入,要对用户的输入进行校验可以通过正则表达式限制长度对单引号和双"-"进行转换等
- 2. 不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。
- 3. 不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接
- 4. 不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息
2. xss
- 它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响
- 防范
-1. 一切用户输入不可信,在输出时进行验证
-2. 将html元素内容,属性以及URL请求参数,css值进行编码
-3. 设置cookie的httpOnly属性
3. CSRF 跨站请求伪造
- 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。
- 防范
- 1. 服务端验证请求来源
- 2. 使用CSRF Token 服务端随机生成返回给浏览器的Token
- 3. 加入二次验证(独立的支付密码)
- vue单页面的优缺点
- 优点
1. 用户体验好,快,内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小。
2. 前后端分离
3. 页面效果会比较炫酷((比如切换页面内容时的专场动画))
- 缺点
1. 不利于seo。(搜索引擎优化)
2. 导航不可用,如果一定要导航需要自行实现前进、后退。
3. 初次加载时耗时多。
4. 页面复杂度提高很多。
- 前端网站性能优化
1. 减少http请求数量
- 在浏览器与服务器进行通信时,主要是通过 HTTP 进行通信。浏览器与服务器需要经过三次握手,每次握手需要花费大量时间。而且不同浏览器对资源文件并发请求数量有限(不同浏览器允许并发数),一旦 HTTP 请求数量达到一定数量,资源请求就存在等待状态,这是很致命的,因此减少 HTTP 的请求数量可以很大程度上对网站性能进行优化。
-1. CSS Sprites
- 这是将多张图片合并成一张图片达到减少HTTP请求的一种解决方案可通过background属性来访问图片内容
-2. 合并CSS和JS文件
- 使用打包工具打包
-3. 采用lazyload
- 可以控制网页上的内容在一开始无需加载,不需要发请求,等到用户操作真正需要的时候立即加载出内容
2. 控制资源文件加载优先级
- 一般情况下都是CSS在头部,JS在底部。
3. 尽量外链CSS和JS(结构、表现和行为的分离),保证网页代码的整洁,也有利于日后维护
4. 利用浏览器缓存
- 浏览器缓存是将网络资源存储在本地,等待下次请求该资源时,如果资源已经存在就不需要到服务器重新请求该资源,直接在本地读取该资源。
5. 引入CDN文件
6. 服务端启用GZIP压缩,浏览速度变快
- 如何删除一个cookie
1.将时间设为当前时间往前一点。
var date = new Date();
date.setDate(date.getDate() - 1);//真正的删除
setDate()方法用于设置一个月的某一天。
2.expires的设置
document.cookie = 'user='+ encodeURIComponent('name') + ';expires = ' + new Date(0)
- 对语意化的理解
1. 如果样式缺失或者掉丢之后可以呈现出清晰的结构
2. 有利于seo
3. 方便其他的设备来解析,以意义的方法来渲染页面
4. 便于段团队的开发和维护,具有更好的可读性
- css 画一个三角形
1. 四边都存在的border就会形成一个正方形
2. 想要形成一个三角形就要将一组border设置为透明并且有值,
另一组的一边border设置为有值并且带有颜色,另一组直接设置就好
.triangle {
height: 0;
width: 0;
border: 20px solid transparent;
border-left-color: red;
}
-
css 画一个九宫格
-
画九宫格的结构
<ul class="box">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
</ul>
- 画九宫格的方法
// 1. 利用 float:left;
.box {
height: 300px;
width: 300px
}
.box >li {
list-style: none;
float:left;
width:100px;
height:100px;
border:4px solid #ccc; // 会产生边框重合变粗,利用外边距重合
box-sizing:border-box;
margin-left:-4px;
margin-right:-4px
}
// 2. 利用flex 布局 // 响应式的
.box {
display: flex;
flex-wrap: wrap;
justify-content: space-around; // 主轴元素之间有空白 相当于一块豆腐竖着切了三刀
}
.box>li {
list-style:none;
width: 30%;
padding-top:30%; // 因为父盒子是没有高度的设置 height:30% 是不起作用的
margin-top:3%; // 每个盒子之间上下的间距 相当于一块豆腐横着切了三刀
}
// 3. 利用grid 来实现
.box {
width: 300px;
height:300px;
display:grid;
grid-template-rows: 100px 100px 100px;
gird-tempalte-columns: 100px 100px 100px
}
.box>li {
list-style: none;
border: 2px solid #ccc; //也会产生边框变粗的情况
box-sizing: box-border;
margin-top:-2px;
margin-left:-2px;
}
- 画一个自适应的盒子
// 1. 结构
<div class="box">我是自适应的盒子</div>
.box {
width: 50%;
height: 50vw;
background-color: red;
}
- 预加载
1. 预加载原理就是在浏览器加载页面的时候先创建一个对象,然后填充数据,从而达到预先加载的效果。(即按照文档流顺序,先利用js加载函数去加载图片,然后在渲染dom元素)
- css对元素的显示和隐藏的辨析
1. display: none 隐藏元素后,不再占有原来的位置
2. visibility: hidden 隐藏元素后,继续占有原来的位置。
- Vertical-align 属性(只是针对行内元素或者是行内快元素)
1. baseline 默认,元素放在父元素的基线上
2. top 把元素的顶端与行中最高元素的顶端对齐
3. middle 把此元素放置在父元素中部
4. bottom 把元素的顶端与行中最低元素的顶端对齐
5. bug:图片底侧会有一个空白缝隙,原因是行内块元素会和文字的基线对齐。 vertical-align:middle 解决
- 清除浮动的几种方法
1. 额外标签法 (在最后一个浮动标签后,新加一个标签,给其设置clear:both)
- clear:both:本质就是闭合浮动, 就是让父盒子闭合出口和入口,不让子盒子出来
2. 父级添加overflow属性(父元素添加overflow:hidden)
- 通过触发BFC方式,实现清除浮动
3. 使用after伪元素清除浮动
- 符合闭合浮动思想,结构语义化正确
- .clearfix:after{/*伪元素是行内元素 正常浏览器清除浮动方法*/
content: "";
display: block;
height: 0;
clear:both;
visibility: hidden;
}
.clearfix{
*zoom: 1;/*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/
}
4. 使用before和after双伪元素清除浮动
- .clearfix:after,.clearfix:before{
content: "";
display: table;
}
.clearfix:after{
clear: both;
}
.clearfix{
*zoom: 1;
}
- 数组的扁平化处理(就是将数组从多维变成一维)
const arr = [1, [2, [3, [4, 5]]], 6];
// 1.使用flat(Infinity)
const res1 =arr.flat(Infinity)
// 2. 使用正则
const res2 = JSON.parse('['+ JSON.stringfy(arr).replace(/\[|\]/g,'').split(',') +']')
// 3. 使用递归的方式
const res3 =[]
const fn = arr =>{
for(lei i=0 ;i<arr.length;i++){
if(Array.isArray(arr[i])){
fn(arr[i])
}else {
res3.push(arr[i])
}
}
}
fn(arr)
- es6数组的方法是否会改变原数组的值
//1. 改变原来的数组
1. shift : 将第一个元素删除并且返回删除元素,空即为undefined
2. unshift:向数组开头添加元素,并返回新的长度
3. pop:删除最后一个并返回删除的元素
4. push: 向数组末尾添加元素,并返回新的长度
5. reverse:颠倒数组顺序
6. sort:对数组排序
7. splice: splice(start,length,item)删,增,替换数组元素,返回被删除数组,无删除则不返回
// start是要删除的元素的索引,length是要删除的长度 item 要是存在的就是添加或者替换被删除的元素
//2. 不会改变数组的方法
1. some // 用于检测数组中是否满足条件的元素 一旦查找到就会终止
2. every // 检查数组中是否所有元素都满足条件
3. map // 数据的映射 处理数据的方法。而且返回一个新的数组 可以和filter等配合使用使用比较方便
4. filter // 过滤 也是返回一个数组
5. concat : 连接多个数组,返回新的数组
6. join : 将数组中所有元素以参数作为分隔符放入一个字符串中
7. slice: slice(start,end), 返回选定的元素 // 如果是负数的就是后向前计算
- 画一个自适应的正方形
<div class="square">nihao</div>
1. 利用vw和百分比
.square {
width: 50%;
height: 50vw;
background: #ccc;
}
2. 设置垂直方向的padding 撑开容器 padding和margin的百分比都是相对父元素的 width来计算的
.square {
width: 50%;
padding-bottom: 50%;
background-color: red;
height: 0; // 如果盒子里面存在内容的 盒子会下掉 设置高度为0即可避免
} // 这样的方法会导致max-length失效,原因是没有的内容的
3. 利用伪元素
.square {
width: 50%;
background-color: red;
position: relative;
}
.square::after{
content: '';
display: block;
/* 这个不会触发外边距合并的问题 */
padding-top: 100%;
}
.box {
// 如果盒子里面有内容,将内容放在子盒子中,然后再通过定位脱离标准流就不会溢出了
position: absolute;
}
- 生成一个指定范围的随机数的方法
1. Math.random() 生成的是伪随机数不是真正的随机数
function getRandomNum (min,max ){
return Math.floor(Math.random*(max-min+1)+min)
}